mirror of
https://github.com/openharmony/kernel_linux_common_modules.git
synced 2026-08-27 01:31:36 -04:00
!1 add New IP protocol stack
Merge pull request !1 from YangYanJun/master
This commit is contained in:
@@ -0,0 +1,359 @@
|
||||
Valid-License-Identifier: GPL-2.0
|
||||
Valid-License-Identifier: GPL-2.0-only
|
||||
Valid-License-Identifier: GPL-2.0+
|
||||
Valid-License-Identifier: GPL-2.0-or-later
|
||||
SPDX-URL: https://spdx.org/licenses/GPL-2.0.html
|
||||
Usage-Guide:
|
||||
To use this license in source code, put one of the following SPDX
|
||||
tag/value pairs into a comment according to the placement
|
||||
guidelines in the licensing rules documentation.
|
||||
For 'GNU General Public License (GPL) version 2 only' use:
|
||||
SPDX-License-Identifier: GPL-2.0
|
||||
or
|
||||
SPDX-License-Identifier: GPL-2.0-only
|
||||
For 'GNU General Public License (GPL) version 2 or any later version' use:
|
||||
SPDX-License-Identifier: GPL-2.0+
|
||||
or
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
License-Text:
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright (c) 2021 Huawei Device Co., Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
This is the configuration file template for OpenHarmony OSS Audit Tool, please copy it to your project root dir and modify it refer to OpenHarmony/tools_oat/README.
|
||||
-->
|
||||
<!-- OAT(OSS Audit Tool) configuration guide:
|
||||
basedir: Root dir, the basedir + project path is the real source file location.
|
||||
licensefile:
|
||||
1.If the project don't have "LICENSE" in root dir, please define all the license files in this project in , OAT will check license files according to this rule.
|
||||
|
||||
tasklist(only for batch mode):
|
||||
1. task: Define oat check thread, each task will start a new thread.
|
||||
2. task name: Only an name, no practical effect.
|
||||
3. task policy: Default policy for projects under this task, this field is required and the specified policy must defined in policylist.
|
||||
4. task filter: Default filefilter for projects under this task, this field is required and the specified filefilter must defined in filefilterlist.
|
||||
5. task project: Projects to be checked, the path field define the source root dir of the project.
|
||||
|
||||
|
||||
policyList:
|
||||
1. policy: All policyitems will be merged to default OAT.xml rules, the name of policy doesn't affect OAT check process.
|
||||
2. policyitem: The fields type, name, path, desc is required, and the fields rule, group, filefilter is optional,the default value is:
|
||||
<policyitem type="" name="" path="" desc="" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
|
||||
3. policyitem type:
|
||||
"compatibility" is used to check license compatibility in the specified path;
|
||||
"license" is used to check source license header in the specified path;
|
||||
"copyright" is used to check source copyright header in the specified path;
|
||||
"import" is used to check source dependency in the specified path, such as import ... ,include ...
|
||||
"filetype" is used to check file type in the specified path, supported file types: archive, binary
|
||||
"filename" is used to check whether the specified file exists in the specified path(support projectroot in default OAT.xml), supported file names: LICENSE, README, README.OpenSource
|
||||
|
||||
4. policyitem name: This field is used for define the license, copyright, "*" means match all, the "!" prefix means could not match this value. For example, "!GPL" means can not use GPL license.
|
||||
5. policyitem path: This field is used for define the source file scope to apply this policyitem, the "!" prefix means exclude the files. For example, "!.*/lib/.*" means files in lib dir will be exclude while process this policyitem.
|
||||
6. policyitem rule and group: These two fields are used together to merge policy results. "may" policyitems in the same group means any one in this group passed, the result will be passed.
|
||||
7. policyitem filefilter: Used to bind filefilter which define filter rules.
|
||||
8. filefilter: Filter rules, the type filename is used to filter file name, the type filepath is used to filter file path.
|
||||
|
||||
Note:If the text contains special characters, please escape them according to the following rules:
|
||||
" == >
|
||||
& == >
|
||||
' == >
|
||||
< == >
|
||||
> == >
|
||||
-->
|
||||
<configuration>
|
||||
<oatconfig>
|
||||
<policylist>
|
||||
<policy name="projectPolicy" desc="New IP protocol stack">
|
||||
<policyitem type="license" name="GPL" path="newip\src\linux-5.10\.*" desc="linux-5.10 kernel"/>
|
||||
<policyitem type="license" name="GPL" path="newip\src\common\.*" desc="NewIP common code"/>
|
||||
<policyitem type="license" name="GPL" path="newip\src\linux\net\newip\nip_checksum.c" desc="NewIP common code (soft link file)"/>
|
||||
<policyitem type="license" name="GPL" path="newip\src\linux\net\newip\nip_checksum.h" desc="NewIP common code (soft link file)"/>
|
||||
<policyitem type="license" name="GPL" path="newip\src\linux\net\newip\nip_addr.c" desc="NewIP common code (soft link file)"/>
|
||||
<policyitem type="license" name="GPL" path="newip\src\linux\net\newip\nip_addr.h" desc="NewIP common code (soft link file)"/>
|
||||
<policyitem type="license" name="GPL" path="newip\src\linux\net\newip\nip_hdr_decap.c" desc="NewIP common code (soft link file)"/>
|
||||
<policyitem type="license" name="GPL" path="newip\src\linux\net\newip\nip_hdr_encap.c" desc="NewIP common code (soft link file)"/>
|
||||
<policyitem type="license" name="GPL" path="newip\src\linux\net\newip\nip_hdr.h" desc="NewIP common code (soft link file)"/>
|
||||
<policyitem type="license" name="GPL" path="newip\examples\.*" desc="NewIP examples code"/>
|
||||
<policyitem type="license" name="GPL" path="newip\tools\wireshark_cfg_for_newip.lua" desc="WireShark lua configure for NewIP protocol stack"/>
|
||||
<policyitem type="copyright" name="Huawei Device Co., Ltd." path="newip\src\.*" desc="huawei copyright"/>
|
||||
</policy>
|
||||
</policylist>
|
||||
<filefilterlist>
|
||||
<filefilter name="defaultFilter" desc="New IP protocol stack">
|
||||
<filteritem type="filepath" name="newip\figures\.*" desc="Describes the architecture of the NewIP"/>
|
||||
<filteritem type="filepath" name="newip\apply_newip.sh" desc="shield"/>
|
||||
<filteritem type="filepath" name="newip\LICENSE" desc="license file"/>
|
||||
<filteritem type="filepath" name="newip\README_zh.md" desc="readme file"/>
|
||||
<filteritem type="filepath" name="newip\README.md" desc="readme file"/>
|
||||
</filefilter>
|
||||
</filefilterlist>
|
||||
</oatconfig>
|
||||
</configuration>
|
||||
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"Name": "linux-5.10",
|
||||
"License": "GPL-2.0+",
|
||||
"License File": "COPYING",
|
||||
"Version Number": "5.10.93",
|
||||
"Owner": "tanyanying@huawei.com",
|
||||
"Upstream URL": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/log/?h=linux-5.10.y",
|
||||
"Description": "linux kernel 5.10"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,90 @@
|
||||
# New IP内核协议栈
|
||||
|
||||
## 简介
|
||||
|
||||
New IP在现有IP能力的基础上,以灵活轻量级报头和可变长多语义地址为基础,通过二三层协议融合,对协议去冗和压缩,减少冗余字节,实现高能效比,高净吞吐,提升通信效率。打造终端之间高效的横向通信,支撑超级终端的体验,实现异构网络的端到端互联。
|
||||
|
||||
目前WiFi协议报文,三层报头和地址开销使得报文开销大,传输效率较低。
|
||||
|
||||

|
||||
|
||||
```
|
||||
IPv4地址长度固定4字节,IPv6地址长度固定16字节。
|
||||
IPv4网络层报头长度20~60字节,IPv6网络层报头长度40字节。
|
||||
```
|
||||
|
||||
New IP支持**可变长多语义地址(最短1字节)**,**可变长定制化报头封装(最短5字节)**,通过精简报文头开销,提升数据传输效率。
|
||||
|
||||
New IP报头开销,相比IPv4节省25.9%,相比IPv6节省44.9%。
|
||||
|
||||
New IP载荷传输效率,相比IPv4提高最少1%,相比IPv6提高最少2.33%。
|
||||
|
||||
| 对比场景 | 报头开销 | 载荷传输效率(WiFi MTU=1500B,BT MTU=255B) |
|
||||
| --------------- | ------------ | ------------------------------------------- |
|
||||
| IPv4 for WiFi | 30+8+20=58 B | (1500-58)/1500=96.13% |
|
||||
| IPv6 for WiFi | 30+8+40=78 B | (1500-78)/1500=94.8% |
|
||||
| New IP for WiFi | 30+8+5=43 B | (1500-43)/1500=97.13% |
|
||||
|
||||
## 系统架构
|
||||
|
||||
New IP内核协议栈架构图如下,用户态应用程序调用Socket API创建New IP socket,采用New IP极简帧头封装进行收发包。
|
||||
|
||||

|
||||
|
||||
## 目录
|
||||
|
||||
New IP内核协议栈主要代码目录结构如下:
|
||||
|
||||
```
|
||||
# 代码路径 /kernel/linux/common_modules/newip
|
||||
├── examples # New IP 用户态样例代码
|
||||
├── src
|
||||
│ ├── common # New IP 通用代码
|
||||
│ └── linux-5.10 # New IP Linux-5.10内核代码
|
||||
│ ├── include # New IP 头文件
|
||||
│ │ ├── linux
|
||||
│ │ ├── net
|
||||
│ │ └── uapi
|
||||
│ └── net
|
||||
│ └── newip # New IP 功能代码
|
||||
├── figures # ReadMe 内嵌图例
|
||||
└── tools # New IP 配套工具
|
||||
```
|
||||
|
||||
## 编译构建
|
||||
|
||||
详见“New IP内核协议栈开发手册-[配置指导](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/kernel/kernel-standard-newip.md#newip配置指导)”章节。
|
||||
|
||||
## 说明
|
||||
|
||||
### 可变长报头格式
|
||||
|
||||
详见“New IP内核协议栈开发手册-[可变报头格式](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/kernel/kernel-standard-newip.md#可变长报头格式)”章节。
|
||||
|
||||
### 可变长地址格式
|
||||
|
||||
详见“New IP内核协议栈开发手册-[可变长地址格式](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/kernel/kernel-standard-newip.md#可变长地址格式)”章节。
|
||||
|
||||
### 接口说明
|
||||
|
||||
详见“New IP内核协议栈开发手册-[New IP相关接口](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/kernel/kernel-standard-newip.md#newip相关接口)”章节。
|
||||
|
||||
### New IP收发包代码示例
|
||||
|
||||
详见“New IP内核协议栈开发手册-[New IP收发包代码示例](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/kernel/kernel-standard-newip.md#newip收发包代码示例)”章节。
|
||||
|
||||
### selinux规则说明
|
||||
|
||||
详见“New IP内核协议栈开发手册-[selinux规则说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/kernel/kernel-standard-newip.md#selinux规则说明)”章节。
|
||||
|
||||
## 相关仓
|
||||
|
||||
[内核子系统](https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/%E5%86%85%E6%A0%B8%E5%AD%90%E7%B3%BB%E7%BB%9F.md)
|
||||
|
||||
[kernel_linux_5.10](https://gitee.com/openharmony/kernel_linux_5.10)
|
||||
|
||||
[kernel_linux_config](https://gitee.com/openharmony/kernel_linux_config)
|
||||
|
||||
[kernel_linux_build](https://gitee.com/openharmony/kernel_linux_build)
|
||||
|
||||
[device_board_hihope](https://gitee.com/openharmony/device_board_hihope)
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
OHOS_SOURCE_ROOT=$1
|
||||
KERNEL_BUILD_ROOT=$2
|
||||
PRODUCT_NAME=$3
|
||||
KERNEL_VERSION=$4
|
||||
NEWIP_SOURCE_ROOT=$OHOS_SOURCE_ROOT/kernel/linux/common_modules/newip
|
||||
|
||||
function main()
|
||||
{
|
||||
pushd .
|
||||
|
||||
cd $KERNEL_BUILD_ROOT/include/linux/
|
||||
ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/include/linux $NEWIP_SOURCE_ROOT/src/linux/include/linux)/*.h ./
|
||||
cd $KERNEL_BUILD_ROOT/include/net/netns
|
||||
ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/include/net/netns $NEWIP_SOURCE_ROOT/src/linux/include/net/netns)/*.h ./
|
||||
cd $KERNEL_BUILD_ROOT/include/net
|
||||
ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/include/net $NEWIP_SOURCE_ROOT/src/linux/include/net)/*.h ./
|
||||
cd $KERNEL_BUILD_ROOT/include/uapi/linux
|
||||
ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/include/uapi/linux $NEWIP_SOURCE_ROOT/src/linux/include/uapi/linux)/*.h ./
|
||||
cd $KERNEL_BUILD_ROOT/include/trace/hooks
|
||||
ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/include/trace/hooks $NEWIP_SOURCE_ROOT/src/linux/include/trace/hooks)/*.h ./
|
||||
|
||||
if [ ! -d " $KERNEL_BUILD_ROOT/net/newip" ]; then
|
||||
mkdir $KERNEL_BUILD_ROOT/net/newip
|
||||
fi
|
||||
|
||||
cd $KERNEL_BUILD_ROOT/net/newip/
|
||||
ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/net/newip $NEWIP_SOURCE_ROOT/src/linux/net/newip)/* ./
|
||||
ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/net/newip $NEWIP_SOURCE_ROOT/src/common)/* ./
|
||||
cd $KERNEL_BUILD_ROOT/include/uapi/linux
|
||||
ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/include/uapi/linux $NEWIP_SOURCE_ROOT/src/common)/nip_addr.h nip_addr.h
|
||||
|
||||
popd
|
||||
}
|
||||
|
||||
main
|
||||
@@ -0,0 +1,60 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
#
|
||||
#
|
||||
CC=gcc
|
||||
# CC = aarch64-linux-gnu-gcc
|
||||
# CC = arm-linux-gnueabi-gcc
|
||||
CFLAGS=-pthread -static -g
|
||||
|
||||
UT_LIST = nip_addr_cfg_demo nip_route_cfg_demo nip_tcp_server_demo nip_tcp_client_demo nip_udp_server_demo nip_udp_client_demo get_af_ninet check_nip_enable nip_addr nip_route
|
||||
|
||||
all: $(UT_LIST)
|
||||
|
||||
clean:
|
||||
rm -f $(UT_LIST)
|
||||
rm -f nip_lib.o
|
||||
rm -f libnip_lib.a
|
||||
|
||||
|
||||
#lib
|
||||
NIP_LIB = libnip_lib.a
|
||||
NIP_DEF_LIB = -L. -lnip_lib
|
||||
|
||||
nip_lib.o: nip_lib.c
|
||||
$(CC) -c nip_lib.c -o nip_lib.o
|
||||
|
||||
libnip_lib.a: nip_lib.o
|
||||
ar -rv libnip_lib.a nip_lib.o
|
||||
|
||||
#UT func list
|
||||
nip_addr_cfg_demo: nip_addr_cfg_demo.c $(NIP_LIB)
|
||||
$(CC) $(CFLAGS) -o nip_addr_cfg_demo nip_addr_cfg_demo.c $(NIP_DEF_LIB)
|
||||
|
||||
nip_route_cfg_demo: nip_route_cfg_demo.c $(NIP_LIB)
|
||||
$(CC) $(CFLAGS) -o nip_route_cfg_demo nip_route_cfg_demo.c $(NIP_DEF_LIB)
|
||||
|
||||
nip_tcp_server_demo: nip_tcp_server_demo.c $(NIP_LIB)
|
||||
$(CC) $(CFLAGS) -o nip_tcp_server_demo nip_tcp_server_demo.c $(NIP_DEF_LIB)
|
||||
|
||||
nip_tcp_client_demo: nip_tcp_client_demo.c $(NIP_LIB)
|
||||
$(CC) $(CFLAGS) -o nip_tcp_client_demo nip_tcp_client_demo.c $(NIP_DEF_LIB)
|
||||
|
||||
nip_udp_server_demo: nip_udp_server_demo.c $(NIP_LIB)
|
||||
$(CC) $(CFLAGS) -o nip_udp_server_demo nip_udp_server_demo.c $(NIP_DEF_LIB)
|
||||
|
||||
nip_udp_client_demo: nip_udp_client_demo.c $(NIP_LIB)
|
||||
$(CC) $(CFLAGS) -o nip_udp_client_demo nip_udp_client_demo.c $(NIP_DEF_LIB)
|
||||
|
||||
get_af_ninet: get_af_ninet.c
|
||||
$(CC) $(CFLAGS) -o get_af_ninet get_af_ninet.c
|
||||
|
||||
check_nip_enable: check_nip_enable.c
|
||||
$(CC) $(CFLAGS) -o check_nip_enable check_nip_enable.c
|
||||
|
||||
nip_addr: nip_addr.c $(NIP_LIB)
|
||||
$(CC) $(CFLAGS) -o nip_addr nip_addr.c $(NIP_DEF_LIB)
|
||||
|
||||
nip_route: nip_route.c $(NIP_LIB)
|
||||
$(CC) $(CFLAGS) -o nip_route nip_route.c $(NIP_DEF_LIB)
|
||||
@@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define NIP_DISABLE_PATH ("/sys/module/newip/parameters/disable")
|
||||
#define NIP_DISABLE_LENTH (5)
|
||||
#define NIP_ENABLE_INVALID (0xFF)
|
||||
|
||||
int g_nip_enable = NIP_ENABLE_INVALID;
|
||||
|
||||
void _check_nip_enable(void)
|
||||
{
|
||||
char tmp[NIP_DISABLE_LENTH];
|
||||
FILE *fn = fopen(NIP_DISABLE_PATH, "r");
|
||||
|
||||
if (!fn) {
|
||||
printf("fail to open %s\n\n", NIP_DISABLE_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fgets(tmp, NIP_DISABLE_LENTH, fn) == NULL) {
|
||||
printf("fail to gets %s\n\n", NIP_DISABLE_PATH);
|
||||
fclose(fn);
|
||||
return;
|
||||
}
|
||||
|
||||
fclose(fn);
|
||||
g_nip_enable = atoi(tmp) ? 0 : 1;
|
||||
}
|
||||
|
||||
int check_nip_enable(void)
|
||||
{
|
||||
if (g_nip_enable == NIP_ENABLE_INVALID) {
|
||||
_check_nip_enable();
|
||||
g_nip_enable = (g_nip_enable == 1 ? 1 : 0);
|
||||
}
|
||||
|
||||
return g_nip_enable;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int af_ninet = check_nip_enable();
|
||||
|
||||
if (af_ninet)
|
||||
printf("Support NewIP\n\n");
|
||||
else
|
||||
printf("Not support NewIP\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define AF_NINET_PATH ("/sys/module/newip/parameters/af_ninet")
|
||||
#define AF_NINET_LENTH (5)
|
||||
|
||||
int g_af_ninet;
|
||||
|
||||
void _get_af_ninet(void)
|
||||
{
|
||||
char tmp[AF_NINET_LENTH];
|
||||
FILE *fn = fopen(AF_NINET_PATH, "r");
|
||||
|
||||
if (!fn) {
|
||||
printf("fail to open %s\n\n", AF_NINET_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fgets(tmp, AF_NINET_LENTH, fn) == NULL) {
|
||||
printf("fail to gets %s\n\n", AF_NINET_PATH);
|
||||
fclose(fn);
|
||||
return;
|
||||
}
|
||||
|
||||
fclose(fn);
|
||||
g_af_ninet = atoi(tmp);
|
||||
}
|
||||
|
||||
int get_af_ninet(void)
|
||||
{
|
||||
if (g_af_ninet == 0)
|
||||
_get_af_ninet();
|
||||
|
||||
return g_af_ninet;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("af_ninet=%d\n\n", get_af_ninet());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#ifndef _NEWIP_ROUTE_H
|
||||
#define _NEWIP_ROUTE_H
|
||||
|
||||
#include "nip.h"
|
||||
|
||||
struct nip_rtmsg {
|
||||
struct nip_addr rtmsg_dst;
|
||||
struct nip_addr rtmsg_src;
|
||||
struct nip_addr rtmsg_gateway;
|
||||
char dev_name[10];
|
||||
unsigned int rtmsg_type;
|
||||
int rtmsg_ifindex;
|
||||
unsigned int rtmsg_metric;
|
||||
unsigned long rtmsg_info;
|
||||
unsigned int rtmsg_flags;
|
||||
};
|
||||
|
||||
#endif /* _NEWIP_ROUTE_H */
|
||||
@@ -0,0 +1,101 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#ifndef _NIP_H
|
||||
#define _NIP_H
|
||||
|
||||
#define NIP_ADDR_LEN_1 1
|
||||
#define NIP_ADDR_LEN_2 2
|
||||
#define NIP_ADDR_LEN_3 3
|
||||
#define NIP_ADDR_LEN_4 4
|
||||
#define NIP_ADDR_LEN_5 5
|
||||
#define NIP_ADDR_LEN_7 7
|
||||
#define NIP_ADDR_LEN_8 8
|
||||
|
||||
#define NIP_ADDR_BIT_LEN_8 8
|
||||
#define NIP_ADDR_BIT_LEN_16 16
|
||||
#define NIP_ADDR_BIT_LEN_24 24
|
||||
#define NIP_ADDR_BIT_LEN_40 40
|
||||
#define NIP_ADDR_BIT_LEN_MAX 64
|
||||
|
||||
enum nip_addr_check_value {
|
||||
ADDR_FIRST_DC = 0xDC,
|
||||
ADDR_FIRST_F0 = 0xF0,
|
||||
ADDR_FIRST_F1,
|
||||
ADDR_FIRST_F2,
|
||||
ADDR_FIRST_F3,
|
||||
ADDR_FIRST_FE = 0xFE,
|
||||
ADDR_FIRST_FF = 0xFF,
|
||||
ADDR_SECOND_MIN_DD = 0xDD,
|
||||
ADDR_SECOND_MIN_F1 = 0x14, /* f1 14 00 */
|
||||
ADDR_THIRD_MIN_F2 = 0x01, /* f2 00 01 00 00 */
|
||||
ADDR_THIRD_MIN_F3 = 0x01, /* F3 0001 0000 0000 */
|
||||
};
|
||||
|
||||
enum nip_8bit_addr_index {
|
||||
NIP_8BIT_ADDR_INDEX_0 = 0,
|
||||
NIP_8BIT_ADDR_INDEX_1 = 1,
|
||||
NIP_8BIT_ADDR_INDEX_2 = 2,
|
||||
NIP_8BIT_ADDR_INDEX_3 = 3,
|
||||
NIP_8BIT_ADDR_INDEX_4 = 4,
|
||||
NIP_8BIT_ADDR_INDEX_5 = 5,
|
||||
NIP_8BIT_ADDR_INDEX_6 = 6,
|
||||
NIP_8BIT_ADDR_INDEX_7 = 7,
|
||||
NIP_8BIT_ADDR_INDEX_MAX,
|
||||
};
|
||||
|
||||
enum nip_16bit_addr_index {
|
||||
NIP_16BIT_ADDR_INDEX_0 = 0,
|
||||
NIP_16BIT_ADDR_INDEX_1 = 1,
|
||||
NIP_16BIT_ADDR_INDEX_2 = 2,
|
||||
NIP_16BIT_ADDR_INDEX_3 = 3,
|
||||
NIP_16BIT_ADDR_INDEX_MAX,
|
||||
};
|
||||
|
||||
enum nip_32bit_addr_index {
|
||||
NIP_32BIT_ADDR_INDEX_0 = 0,
|
||||
NIP_32BIT_ADDR_INDEX_1 = 1,
|
||||
NIP_32BIT_ADDR_INDEX_MAX,
|
||||
};
|
||||
|
||||
#define nip_addr_field8 v.u.field8
|
||||
#define nip_addr_field16 v.u.field16
|
||||
#define nip_addr_field32 v.u.field32
|
||||
|
||||
#pragma pack(1)
|
||||
struct nip_addr_field {
|
||||
union {
|
||||
unsigned char field8[NIP_8BIT_ADDR_INDEX_MAX];
|
||||
unsigned short field16[NIP_16BIT_ADDR_INDEX_MAX]; /* big-endian */
|
||||
unsigned int field32[NIP_32BIT_ADDR_INDEX_MAX]; /* big-endian */
|
||||
} u;
|
||||
};
|
||||
|
||||
struct nip_addr {
|
||||
unsigned char bitlen; /* The address length is in bit (not byte) */
|
||||
struct nip_addr_field v;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
enum nip_index {
|
||||
INDEX_0 = 0,
|
||||
INDEX_1 = 1,
|
||||
INDEX_2 = 2,
|
||||
INDEX_3 = 3,
|
||||
INDEX_4 = 4,
|
||||
INDEX_5 = 5,
|
||||
INDEX_6 = 6,
|
||||
INDEX_7 = 7,
|
||||
INDEX_8 = 8,
|
||||
INDEX_9 = 9,
|
||||
INDEX_10 = 10,
|
||||
INDEX_11 = 11,
|
||||
INDEX_12 = 12,
|
||||
INDEX_13 = 13,
|
||||
INDEX_14 = 14,
|
||||
INDEX_15 = 15,
|
||||
INDEX_MAX,
|
||||
};
|
||||
|
||||
#endif /* _NIP_H */
|
||||
@@ -0,0 +1,136 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "nip_uapi.h"
|
||||
#include "nip_lib.h"
|
||||
|
||||
/* get ifindex based on the device name
|
||||
* struct ifreq ifr;
|
||||
* struct nip_ifreq ifrn;
|
||||
* ioctl(fd, SIOGIFINDEX, &ifr);
|
||||
* ifr.ifr_ifindex; ===> ifindex
|
||||
*/
|
||||
int nip_add_addr(int ifindex, const struct nip_addr *addr, int opt)
|
||||
{
|
||||
int fd, ret;
|
||||
struct nip_ifreq ifrn;
|
||||
|
||||
fd = socket(AF_NINET, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
memset(&ifrn, 0, sizeof(ifrn));
|
||||
ifrn.ifrn_addr = *addr;
|
||||
ifrn.ifrn_ifindex = ifindex;
|
||||
|
||||
ret = ioctl(fd, opt, &ifrn);
|
||||
if (ret < 0 && errno != EEXIST) { // ignore File Exists error
|
||||
printf("cfg newip addr fail, ifindex=%d, opt=%d, ret=%d.\n", ifindex, opt, ret);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cmd_help(void)
|
||||
{
|
||||
/* nip_addr wlan0 add 01 (在wlan0上配置地址01) */
|
||||
/* nip_addr wlan0 del 01 (在wlan0上删除地址01) */
|
||||
printf("[cmd example] nip_addr <netcard-name> { add | del } <addr>\n");
|
||||
}
|
||||
|
||||
int parse_name(char **argv, int *ifindex, char *dev)
|
||||
{
|
||||
int len = strlen(*argv);
|
||||
|
||||
memset(dev, 0, ARRAY_LEN);
|
||||
if (!len || len >= (ARRAY_LEN - 1))
|
||||
return -1;
|
||||
memcpy(dev, *argv, len);
|
||||
dev[len + 1] = '\0';
|
||||
|
||||
if (strncmp(dev, NIC_NAME_CHECK, strlen(NIC_NAME_CHECK))) {
|
||||
printf("unsupport addr cfg cmd-1, cmd=%s\n", dev);
|
||||
cmd_help();
|
||||
return -1;
|
||||
}
|
||||
return nip_get_ifindex(dev, ifindex);
|
||||
}
|
||||
|
||||
int parse_cmd(char **argv, int *opt)
|
||||
{
|
||||
char cmd[ARRAY_LEN];
|
||||
int len = strlen(*argv);
|
||||
|
||||
memset(cmd, 0, ARRAY_LEN);
|
||||
if (!len || len >= (ARRAY_LEN - 1))
|
||||
return -1;
|
||||
memcpy(cmd, *argv, len);
|
||||
cmd[len + 1] = '\0';
|
||||
|
||||
if (!strncmp(cmd, CMD_ADD, strlen(CMD_ADD))) {
|
||||
*opt = SIOCSIFADDR;
|
||||
} else if (!strncmp(cmd, CMD_DEL, strlen(CMD_DEL))) {
|
||||
*opt = SIOCDIFADDR;
|
||||
} else {
|
||||
printf("unsupport addr cfg cmd-2, cmd=%s\n", cmd);
|
||||
cmd_help();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv_input)
|
||||
{
|
||||
char dev[ARRAY_LEN];
|
||||
int ret;
|
||||
int opt;
|
||||
int ifindex = 0;
|
||||
char **argv = argv_input;
|
||||
struct nip_addr addr = {0};
|
||||
|
||||
if (argc != DEMO_INPUT_3) {
|
||||
printf("unsupport addr cfg input, argc=%d\n", argc);
|
||||
cmd_help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 配置参数1解析: <netcard-name> */
|
||||
argv++;
|
||||
ret = parse_name(argv, &ifindex, dev);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
/* 配置参数2解析: { add | del } */
|
||||
argv++;
|
||||
ret = parse_cmd(argv, &opt);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
/* 配置参数3解析: <addr> */
|
||||
argv++;
|
||||
if (nip_get_addr(argv, &addr)) {
|
||||
printf("unsupport addr cfg cmd-3\n");
|
||||
cmd_help();
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = nip_add_addr(ifindex, &addr, opt);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
printf("%s (ifindex=%d) cfg addr success\n", dev, ifindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "nip_uapi.h"
|
||||
#include "nip_lib.h"
|
||||
|
||||
/* get ifindex based on the device name
|
||||
* struct ifreq ifr;
|
||||
* struct nip_ifreq ifrn;
|
||||
* ioctl(fd, SIOGIFINDEX, &ifr);
|
||||
* ifr.ifr_ifindex; ===> ifindex
|
||||
*/
|
||||
int nip_add_addr(int ifindex, const unsigned char *addr, unsigned char addr_len)
|
||||
{
|
||||
int fd, ret;
|
||||
struct nip_ifreq ifrn;
|
||||
|
||||
fd = socket(AF_NINET, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
memset(&ifrn, 0, sizeof(ifrn));
|
||||
ifrn.ifrn_addr.bitlen = addr_len * 8; // Byte length is converted to bit length
|
||||
memcpy(ifrn.ifrn_addr.nip_addr_field8, addr, addr_len);
|
||||
ifrn.ifrn_ifindex = ifindex;
|
||||
|
||||
ret = ioctl(fd, SIOCSIFADDR, &ifrn);
|
||||
if (ret < 0 && errno != EEXIST) { // ignore File Exists error
|
||||
printf("cfg newip addr fail, ifindex=%d, ret=%d\n", ifindex, ret);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Before executing the use case, run ifconfig XXX up.
|
||||
* XXX indicates the NIC name, for example, eth0 and wlan0
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ifindex = 0;
|
||||
int ret;
|
||||
unsigned char client_addr[INDEX_1] = {0x50}; // 1-byte address of the client: 0x50
|
||||
unsigned char server_addr[INDEX_2] = {0xDE, 0x00}; // 2-byte address of the server: 0xDE00
|
||||
unsigned char *addr;
|
||||
unsigned char addr_len;
|
||||
|
||||
if (argc == DEMO_INPUT_1) {
|
||||
if (!strcmp(*(argv + 1), "server")) {
|
||||
printf("server cfg addr=0x%02x%02x\n",
|
||||
server_addr[INDEX_0], server_addr[INDEX_1]);
|
||||
addr = server_addr;
|
||||
addr_len = sizeof(server_addr);
|
||||
} else if (!strcmp(*(argv + 1), "client")) {
|
||||
printf("client cfg addr=0x%02x\n", client_addr[INDEX_0]);
|
||||
addr = client_addr;
|
||||
addr_len = sizeof(client_addr);
|
||||
} else {
|
||||
printf("invalid addr cfg input\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
printf("unsupport addr cfg input\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = nip_get_ifindex(NIC_NAME, &ifindex);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
ret = nip_add_addr(ifindex, addr, addr_len);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
printf("%s %s(ifindex=%d) cfg addr success\n", *argv, NIC_NAME, ifindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <linux/if.h> /* struct ifreq depend */
|
||||
|
||||
#include "nip_uapi.h"
|
||||
#include "nip_lib.h"
|
||||
|
||||
#define ADDR_STR_LEN 2
|
||||
#define STR_FMT_1 55
|
||||
#define STR_FMT_2 87
|
||||
|
||||
int32_t nip_get_ifindex(const char *ifname, int *ifindex)
|
||||
{
|
||||
int fd;
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, ifname);
|
||||
fd = socket(AF_NINET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
printf("creat socket fail, ifname=%s\n", ifname);
|
||||
return -1;
|
||||
}
|
||||
if ((ioctl(fd, SIOCGIFINDEX, &ifr)) < 0) {
|
||||
printf("get ifindex fail, ifname=%s\n", ifname);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
printf("%s ifindex=%u\n", ifname, ifr.ifr_ifindex);
|
||||
*ifindex = ifr.ifr_ifindex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nip_addr_fmt(char *addr_str, struct nip_addr *sap, int addrlen_input)
|
||||
{
|
||||
unsigned char first_byte;
|
||||
int addrlen, i;
|
||||
|
||||
memset(sap, 0, sizeof(struct nip_addr));
|
||||
for (i = 0; i < INDEX_MAX; i++) {
|
||||
if (addr_str[i] == 0)
|
||||
break;
|
||||
|
||||
/* 0 ~ 9 = 48 ~ 57, '0'构造成 0 = 48 - 48 */
|
||||
if (addr_str[i] >= '0' && addr_str[i] <= '9') {
|
||||
addr_str[i] = addr_str[i] - '0';
|
||||
/* A ~ F = 65 ~ 70, 'A'构造成 10 = 65 - 55 */
|
||||
} else if (addr_str[i] >= 'A' && addr_str[i] <= 'F') {
|
||||
addr_str[i] = addr_str[i] - STR_FMT_1;
|
||||
/* a ~ f = 97 ~ 102, 'a'构造成 10 = 97 - 87 */
|
||||
} else if (addr_str[i] >= 'a' && addr_str[i] <= 'f') {
|
||||
addr_str[i] = addr_str[i] - STR_FMT_2;
|
||||
} else {
|
||||
printf("Newip addr error: uaddr[%d]=%c\n", i, addr_str[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
first_byte = addr_str[0] << NIP_ADDR_LEN_4;
|
||||
first_byte += addr_str[1];
|
||||
if (first_byte <= ADDR_FIRST_DC)
|
||||
addrlen = NIP_ADDR_LEN_1;
|
||||
else if (first_byte <= ADDR_FIRST_F0 || first_byte == ADDR_FIRST_FF)
|
||||
addrlen = NIP_ADDR_LEN_2;
|
||||
else if (first_byte == ADDR_FIRST_F1)
|
||||
addrlen = NIP_ADDR_LEN_3;
|
||||
else if (first_byte == ADDR_FIRST_F2)
|
||||
addrlen = NIP_ADDR_LEN_5;
|
||||
else if (first_byte == ADDR_FIRST_F3)
|
||||
addrlen = NIP_ADDR_LEN_7;
|
||||
else if (first_byte == ADDR_FIRST_FE)
|
||||
addrlen = NIP_ADDR_LEN_8;
|
||||
else
|
||||
addrlen = 0;
|
||||
|
||||
if (addrlen_input != addrlen) {
|
||||
printf("Newip addr error, first_byte=0x%x\n", first_byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sap->bitlen = addrlen * NIP_ADDR_LEN_8;
|
||||
printf("*************************************************\n");
|
||||
printf("Newip addr len=%d\n", addrlen);
|
||||
for (i = 0; i < addrlen; i++) {
|
||||
sap->nip_addr_field8[i] = addr_str[i * INDEX_2] << INDEX_4;
|
||||
sap->nip_addr_field8[i] += addr_str[i * INDEX_2 + 1];
|
||||
printf("%02x ", sap->nip_addr_field8[i]);
|
||||
}
|
||||
printf("\n*************************************************\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nip_get_addr(char **args, struct nip_addr *addr)
|
||||
{
|
||||
unsigned int len;
|
||||
char *sp = *args;
|
||||
int addrlen_input = 0;
|
||||
__u8 addr_str[INDEX_MAX] = {0};
|
||||
|
||||
while (*sp != '\0') {
|
||||
addrlen_input += 1;
|
||||
sp++;
|
||||
}
|
||||
|
||||
if (addrlen_input % ADDR_STR_LEN != 0) {
|
||||
printf("NewIP addr str-len invalid, addrlen_input=%d\n", addrlen_input);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strlen(*args);
|
||||
if (!len || len >= (INDEX_MAX - 1))
|
||||
return -1;
|
||||
memcpy(addr_str, *args, len);
|
||||
addr_str[len + 1] = '\0';
|
||||
|
||||
return nip_addr_fmt(addr_str, addr, addrlen_input / ADDR_STR_LEN);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#ifndef _NIP_LIB_H
|
||||
#define _NIP_LIB_H
|
||||
|
||||
/* AF_NINET by reading/sys/module/newip/parameters/af_ninet file to get the type value */
|
||||
#define AF_NINET 45
|
||||
|
||||
#define DEMO_INPUT_1 2 /* The DEMO program contains one parameter */
|
||||
#define DEMO_INPUT_2 3
|
||||
#define DEMO_INPUT_3 4
|
||||
#define DEMO_INPUT_4 5
|
||||
|
||||
/* Change the value based on the actual interface */
|
||||
#define NIC_NAME "wlan0"
|
||||
#define NIC_NAME_CHECK "wlan"
|
||||
#define CMD_ADD "add"
|
||||
#define CMD_DEL "del"
|
||||
|
||||
#define BUFLEN 1024
|
||||
#define LISTEN_MAX 3
|
||||
#define PKTCNT 10 /* Number of sent packets */
|
||||
#define PKTLEN 1024 /* Length of sent packet */
|
||||
#define SLEEP_US 500000 /* Packet sending interval (ms) */
|
||||
#define SELECT_TIME 600
|
||||
#define TCP_SERVER_PORT 5556 /* TCP Server Port */
|
||||
#define UDP_SERVER_PORT 9090 /* UDP Server Port */
|
||||
|
||||
#define ARRAY_LEN 255
|
||||
|
||||
int nip_get_ifindex(const char *ifname, int *ifindex);
|
||||
int nip_get_addr(char **args, struct nip_addr *addr);
|
||||
|
||||
#endif /* _NIP_LIB_H */
|
||||
@@ -0,0 +1,184 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/route.h>
|
||||
|
||||
#include "nip_uapi.h"
|
||||
#include "nip_lib.h"
|
||||
#include "newip_route.h"
|
||||
|
||||
/* get ifindex based on the device name
|
||||
* struct ifreq ifr;
|
||||
* struct nip_ifreq ifrn;
|
||||
* ioctl(fd, SIOGIFINDEX, &ifr);
|
||||
* ifr.ifr_ifindex; ===> ifindex
|
||||
*/
|
||||
int nip_route_add(int ifindex, const struct nip_addr *dst_addr,
|
||||
const struct nip_addr *gateway_addr, __u8 gateway_flag, int opt)
|
||||
{
|
||||
int fd, ret;
|
||||
struct nip_rtmsg rt;
|
||||
|
||||
fd = socket(AF_NINET, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
memset(&rt, 0, sizeof(rt));
|
||||
rt.rtmsg_ifindex = ifindex;
|
||||
rt.rtmsg_flags = RTF_UP;
|
||||
rt.rtmsg_dst = *dst_addr;
|
||||
|
||||
if (gateway_flag) {
|
||||
rt.rtmsg_gateway = *gateway_addr;
|
||||
rt.rtmsg_flags |= RTF_GATEWAY;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, opt, &rt);
|
||||
if (ret < 0 && errno != EEXIST) { // ignore File Exists error
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cmd_help(void)
|
||||
{
|
||||
/* nip_route add 02 wlan0
|
||||
* (配置目的地址02设备路由,出口是wlan0)
|
||||
* nip_route add 02 wlan0 03
|
||||
* (配置目的地址02设备路由,出口是wlan0,网关地址是03)
|
||||
* nip_route add ff09 wlan0 03
|
||||
* (配置广播默认路由, 出口是wlan0,网关地址是03)
|
||||
*/
|
||||
printf("\n[cmd example]\n");
|
||||
printf("nip_route { add | del } <dst-addr> <netcard-name>\n");
|
||||
printf("nip_route { add | del } <dst-addr> <netcard-name> <gateway-addr>\n");
|
||||
}
|
||||
|
||||
int parse_name(char **argv, int *ifindex, char *dev)
|
||||
{
|
||||
int len = strlen(*argv);
|
||||
|
||||
memset(dev, 0, ARRAY_LEN);
|
||||
if (len >= (ARRAY_LEN - 1) || !len)
|
||||
return -1;
|
||||
memcpy(dev, *argv, len);
|
||||
dev[len + 1] = '\0';
|
||||
|
||||
if (strncmp(dev, NIC_NAME_CHECK, strlen(NIC_NAME_CHECK))) {
|
||||
printf("unsupport addr cfg cmd-3, cmd=%s\n", dev);
|
||||
cmd_help();
|
||||
return -1;
|
||||
}
|
||||
return nip_get_ifindex(dev, ifindex);
|
||||
}
|
||||
|
||||
int parse_cmd(char **argv, int *opt)
|
||||
{
|
||||
int len = strlen(*argv);
|
||||
char cmd[ARRAY_LEN];
|
||||
|
||||
memset(cmd, 0, ARRAY_LEN);
|
||||
if (!len || len >= (ARRAY_LEN - 1))
|
||||
return -1;
|
||||
memcpy(cmd, *argv, len);
|
||||
cmd[len + 1] = '\0';
|
||||
|
||||
if (!strncmp(cmd, CMD_ADD, strlen(CMD_ADD))) {
|
||||
*opt = SIOCADDRT;
|
||||
} else if (!strncmp(cmd, CMD_DEL, strlen(CMD_DEL))) {
|
||||
*opt = SIOCDELRT;
|
||||
} else {
|
||||
printf("unsupport route cfg cmd-1, cmd=%s\n", cmd);
|
||||
cmd_help();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_args(char **argv, int *opt, __u8 *gateway_flag, int *ifindex,
|
||||
struct nip_addr *dst_addr, struct nip_addr *gateway_addr, char *dev, int argc)
|
||||
{
|
||||
/* 配置参数1解析: { add | del } */
|
||||
int ret;
|
||||
|
||||
argv++;
|
||||
ret = parse_cmd(argv, opt);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
/* 配置参数2解析: <dst-addr> */
|
||||
argv++;
|
||||
if (nip_get_addr(argv, dst_addr)) {
|
||||
printf("unsupport route cfg cmd-2\n");
|
||||
cmd_help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 配置参数3解析: <netcard-name> */
|
||||
argv++;
|
||||
ret = parse_name(argv, ifindex, dev);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
/* 配置参数4解析: <gateway-addr> */
|
||||
if (argc == DEMO_INPUT_4) {
|
||||
argv++;
|
||||
if (nip_get_addr(argv, gateway_addr)) {
|
||||
printf("unsupport route cfg cmd-4\n");
|
||||
cmd_help();
|
||||
return -1;
|
||||
}
|
||||
*gateway_flag = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv_input)
|
||||
{
|
||||
int ret;
|
||||
int opt;
|
||||
int ifindex = 0;
|
||||
__u8 gateway_flag = 0;
|
||||
char **argv = argv_input;
|
||||
char dev[ARRAY_LEN];
|
||||
struct nip_addr dst_addr = {0};
|
||||
struct nip_addr gateway_addr = {0};
|
||||
|
||||
if (argc != DEMO_INPUT_3 && argc != DEMO_INPUT_4) {
|
||||
printf("unsupport route cfg input, argc=%d\n", argc);
|
||||
cmd_help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = parse_args(argv, &opt, &gateway_flag, &ifindex,
|
||||
&dst_addr, &gateway_addr, dev, argc);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
ret = nip_get_ifindex(dev, &ifindex);
|
||||
if (ret != 0) {
|
||||
printf("get %s ifindex fail, ret=%d\n", dev, ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = nip_route_add(ifindex, &dst_addr, &gateway_addr, gateway_flag, opt);
|
||||
if (ret != 0) {
|
||||
printf("get %s ifindex fail, ret=%d\n", dev, ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("%s (ifindex=%d) cfg route success\n", dev, ifindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <linux/route.h>
|
||||
|
||||
#include "nip_uapi.h"
|
||||
#include "nip_lib.h"
|
||||
#include "newip_route.h"
|
||||
|
||||
/* get ifindex based on the device name
|
||||
* struct ifreq ifr;
|
||||
* struct nip_ifreq ifrn;
|
||||
* ioctl(fd, SIOGIFINDEX, &ifr);
|
||||
* ifr.ifr_ifindex; ===> ifindex
|
||||
*/
|
||||
int nip_route_add(int ifindex, const unsigned char *dst_addr, uint8_t dst_addr_len,
|
||||
const unsigned char *gateway_addr, uint8_t gateway_addr_len)
|
||||
{
|
||||
int fd, ret;
|
||||
struct nip_rtmsg rt;
|
||||
|
||||
fd = socket(AF_NINET, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
memset(&rt, 0, sizeof(rt));
|
||||
rt.rtmsg_ifindex = ifindex;
|
||||
rt.rtmsg_flags = RTF_UP;
|
||||
rt.rtmsg_dst.bitlen = dst_addr_len * 8;
|
||||
memcpy(rt.rtmsg_dst.nip_addr_field8, dst_addr, dst_addr_len);
|
||||
|
||||
if (gateway_addr) {
|
||||
rt.rtmsg_gateway.bitlen = gateway_addr_len * 8;
|
||||
memcpy(rt.rtmsg_gateway.nip_addr_field8, gateway_addr, gateway_addr_len);
|
||||
rt.rtmsg_flags |= RTF_GATEWAY;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SIOCADDRT, &rt);
|
||||
if (ret < 0 && errno != EEXIST) { // ignore File Exists error
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
int ifindex = 0;
|
||||
uint8_t client_addr[INDEX_1] = {0x50}; // 1-byte address of the client: 0x50
|
||||
uint8_t server_addr[INDEX_2] = {0xDE, 0x00}; // 2-byte address of the server: 0xDE00
|
||||
uint8_t *dst_addr;
|
||||
uint8_t dst_addr_len;
|
||||
|
||||
if (argc == DEMO_INPUT_1) {
|
||||
if (!strcmp(*(argv + 1), "server")) {
|
||||
printf("server cfg route, dst-addr=0x%02x\n", client_addr[INDEX_0]);
|
||||
dst_addr = client_addr;
|
||||
dst_addr_len = 1;
|
||||
} else if (!strcmp(*(argv + 1), "client")) {
|
||||
printf("client cfg route, dst-addr=0x%02x%02x\n",
|
||||
server_addr[INDEX_0], server_addr[INDEX_1]);
|
||||
dst_addr = server_addr;
|
||||
dst_addr_len = 2;
|
||||
} else {
|
||||
printf("invalid route cfg input\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
printf("unsupport route cfg input\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = nip_get_ifindex(NIC_NAME, &ifindex);
|
||||
if (ret != 0) {
|
||||
printf("get %s ifindex fail, ret=%d\n", NIC_NAME, ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = nip_route_add(ifindex, dst_addr, dst_addr_len, NULL, 0);
|
||||
if (ret != 0) {
|
||||
printf("get %s ifindex fail, ret=%d\n", NIC_NAME, ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("%s %s(ifindex=%d) cfg route success\n", *argv, NIC_NAME, ifindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "nip_uapi.h"
|
||||
#include "nip_lib.h"
|
||||
#include "newip_route.h"
|
||||
|
||||
#define __USE_GNU
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
|
||||
int _send(int cfd, int pkt_num)
|
||||
{
|
||||
char buf[BUFLEN] = {0};
|
||||
struct timeval sys_time;
|
||||
|
||||
gettimeofday(&sys_time, NULL);
|
||||
sprintf(buf, "%ld %6ld NIP_TCP # %6d", sys_time.tv_sec, sys_time.tv_usec, pkt_num);
|
||||
|
||||
if (send(cfd, buf, PKTLEN, 0) < 0) {
|
||||
perror("sendto");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _recv(int cfd, int pkt_num, int *success)
|
||||
{
|
||||
char buf[BUFLEN] = {0};
|
||||
fd_set readfds;
|
||||
int tmp;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(cfd, &readfds);
|
||||
tv.tv_sec = 2;
|
||||
tv.tv_usec = 0;
|
||||
if (select(cfd + 1, &readfds, NULL, NULL, &tv) < 0) {
|
||||
perror("select");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (FD_ISSET(cfd, &readfds)) {
|
||||
int ret;
|
||||
int no = 0;
|
||||
|
||||
ret = recv(cfd, buf, PKTLEN, MSG_WAITALL);
|
||||
if (ret > 0) {
|
||||
*success += 1;
|
||||
ret = sscanf(buf, "%d %d NIP_TCP # %d", &tmp, &tmp, &no);
|
||||
if (ret <= 0) {
|
||||
perror("sscanf");
|
||||
return -1;
|
||||
}
|
||||
printf("Received --%s sock %d success:%6d/%6d/no=%6d\n",
|
||||
buf, cfd, *success, pkt_num + 1, no);
|
||||
} else {
|
||||
printf("recv fail, ret=%d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *send_recv(void *args)
|
||||
{
|
||||
int cfd = ((struct thread_args *)args)->cfd;
|
||||
int success = 0;
|
||||
|
||||
for (int i = 0; i < PKTCNT; i++) {
|
||||
if (_send(cfd, i) != 0)
|
||||
goto END;
|
||||
|
||||
if (_recv(cfd, i, &success) != 0)
|
||||
goto END;
|
||||
|
||||
usleep(SLEEP_US);
|
||||
}
|
||||
|
||||
END: return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int cfd;
|
||||
pthread_t th;
|
||||
struct thread_args th_args;
|
||||
struct sockaddr_nin si_server;
|
||||
|
||||
cfd = socket(AF_NINET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (cfd < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
printf("creat newip socket, fd=%d\n", cfd);
|
||||
|
||||
memset((char *)&si_server, 0, sizeof(si_server));
|
||||
si_server.sin_family = AF_NINET;
|
||||
si_server.sin_port = htons(TCP_SERVER_PORT);
|
||||
// 2-byte address of the server: 0xDE00
|
||||
si_server.sin_addr.nip_addr_field8[INDEX_0] = 0xDE;
|
||||
si_server.sin_addr.nip_addr_field8[INDEX_1] = 0x00;
|
||||
si_server.sin_addr.bitlen = NIP_ADDR_BIT_LEN_16; // 2-byte: 16bit
|
||||
if (connect(cfd, (struct sockaddr *)&si_server, sizeof(si_server)) < 0) {
|
||||
perror("connect");
|
||||
return -1;
|
||||
}
|
||||
printf("connect success, addr=0x%02x%02x, port=%d\n",
|
||||
si_server.sin_addr.nip_addr_field8[INDEX_0],
|
||||
si_server.sin_addr.nip_addr_field8[INDEX_1], TCP_SERVER_PORT);
|
||||
|
||||
th_args.si_server = si_server;
|
||||
th_args.si_server.sin_port = htons(TCP_SERVER_PORT);
|
||||
th_args.cfd = cfd;
|
||||
pthread_create(&th, NULL, send_recv, &th_args);
|
||||
/* Wait for the thread to end and synchronize operations between threads */
|
||||
pthread_join(th, NULL);
|
||||
close(cfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define __USE_GNU
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "nip_uapi.h"
|
||||
#include "nip_lib.h"
|
||||
#include "newip_route.h"
|
||||
|
||||
void *recv_send(void *args)
|
||||
{
|
||||
int cfd, ret;
|
||||
char buf[BUFLEN] = {0};
|
||||
|
||||
memcpy(&cfd, args, sizeof(int));
|
||||
for (int i = 0; i < PKTCNT; i++) {
|
||||
int recv_num = recv(cfd, buf, PKTLEN, MSG_WAITALL);
|
||||
|
||||
if (recv_num < 0) {
|
||||
perror("recv");
|
||||
goto END;
|
||||
} else if (recv_num == 0) { /* no data */
|
||||
;
|
||||
} else {
|
||||
printf("Received -- %s --:%d\n", buf, recv_num);
|
||||
ret = send(cfd, buf, recv_num, 0);
|
||||
if (ret < 0) {
|
||||
perror("send");
|
||||
goto END;
|
||||
}
|
||||
printf("Sending -- %s --:%d\n", buf, recv_num);
|
||||
}
|
||||
}
|
||||
END: close(cfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pthread_t th;
|
||||
int fd, cfd, addr_len;
|
||||
struct sockaddr_nin si_local;
|
||||
struct sockaddr_nin si_remote;
|
||||
|
||||
fd = socket(AF_NINET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset((char *)&si_local, 0, sizeof(si_local));
|
||||
si_local.sin_family = AF_NINET;
|
||||
si_local.sin_port = htons(TCP_SERVER_PORT);
|
||||
// 2-byte address of the server: 0xDE00
|
||||
si_local.sin_addr.nip_addr_field8[INDEX_0] = 0xDE;
|
||||
si_local.sin_addr.nip_addr_field8[INDEX_1] = 0x00;
|
||||
si_local.sin_addr.bitlen = NIP_ADDR_BIT_LEN_16; // 2-byte: 16bit
|
||||
|
||||
if (bind(fd, (const struct sockaddr *)&si_local, sizeof(si_local)) < 0) {
|
||||
perror("bind");
|
||||
goto END;
|
||||
}
|
||||
printf("bind success, addr=0x%02x%02x, port=%d\n",
|
||||
si_local.sin_addr.nip_addr_field8[INDEX_0],
|
||||
si_local.sin_addr.nip_addr_field8[INDEX_1], TCP_SERVER_PORT);
|
||||
|
||||
if (listen(fd, LISTEN_MAX) < 0) {
|
||||
perror("listen");
|
||||
goto END;
|
||||
}
|
||||
|
||||
addr_len = sizeof(si_remote);
|
||||
memset(&si_remote, 0, sizeof(si_remote));
|
||||
cfd = accept(fd, (struct sockaddr *)&si_remote, (socklen_t *)&addr_len);
|
||||
pthread_create(&th, NULL, recv_send, &cfd);
|
||||
/* Wait for the thread to end and synchronize operations between threads */
|
||||
pthread_join(th, NULL);
|
||||
END: close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#ifndef _NIP_UAPI_H
|
||||
#define _NIP_UAPI_H
|
||||
|
||||
#include "nip.h"
|
||||
|
||||
/* The following structure must be larger than V4. System calls use V4.
|
||||
* If the definition is smaller than V4, the read process will have memory overruns
|
||||
* v4: include\linux\socket.h --> sockaddr (16Byte)
|
||||
*/
|
||||
#define POD_SOCKADDR_SIZE 3
|
||||
struct sockaddr_nin {
|
||||
unsigned short sin_family; /* [2Byte] AF_NINET */
|
||||
unsigned short sin_port; /* [2Byte] Transport layer port, big-endian */
|
||||
struct nip_addr sin_addr; /* [9Byte] NIP address */
|
||||
|
||||
unsigned char sin_zero[POD_SOCKADDR_SIZE]; /* [3Byte] Byte alignment */
|
||||
};
|
||||
|
||||
struct nip_ifreq {
|
||||
struct nip_addr ifrn_addr;
|
||||
int ifrn_ifindex;
|
||||
};
|
||||
|
||||
struct thread_args {
|
||||
int cfd;
|
||||
struct sockaddr_nin si_server;
|
||||
};
|
||||
|
||||
#endif /* _NIP_UAPI_H */
|
||||
@@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define __USE_GNU
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "nip_uapi.h"
|
||||
#include "nip_lib.h"
|
||||
#include "newip_route.h"
|
||||
|
||||
int _sendto(int cfd, struct sockaddr_nin *si_server, int pkt_num)
|
||||
{
|
||||
char buf[BUFLEN] = {0};
|
||||
struct timeval sys_time;
|
||||
socklen_t slen = sizeof(struct sockaddr_nin);
|
||||
|
||||
gettimeofday(&sys_time, NULL);
|
||||
sprintf(buf, "%ld %6ld NIP_UDP # %6d", sys_time.tv_sec, sys_time.tv_usec, pkt_num);
|
||||
|
||||
if (sendto(cfd, buf, BUFLEN, 0, (struct sockaddr *)si_server, slen) < 0) {
|
||||
printf("client sendto fail, pkt_num=%d", pkt_num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _recvfrom(int cfd, struct sockaddr_nin *si_server, int pkt_num, int *success)
|
||||
{
|
||||
char buf[BUFLEN] = {0};
|
||||
fd_set readfds;
|
||||
int tmp;
|
||||
struct timeval tv;
|
||||
socklen_t slen = sizeof(struct sockaddr_nin);
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(cfd, &readfds);
|
||||
tv.tv_sec = 2;
|
||||
tv.tv_usec = 0;
|
||||
if (select(cfd + 1, &readfds, NULL, NULL, &tv) < 0) {
|
||||
printf("client select fail, pkt_num=%d", pkt_num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (FD_ISSET(cfd, &readfds)) {
|
||||
int ret;
|
||||
int no = 0;
|
||||
|
||||
ret = recvfrom(cfd, buf, BUFLEN, 0, (struct sockaddr *)si_server, &slen);
|
||||
if (ret > 0) {
|
||||
*success += 1;
|
||||
ret = sscanf(buf, "%d %d NIP_UDP # %d", &tmp, &tmp, &no);
|
||||
if (ret)
|
||||
printf("Received --%s sock %d success:%6d/%6d/no=%6d\n",
|
||||
buf, cfd, *success, pkt_num + 1, no);
|
||||
} else {
|
||||
printf("client recvfrom fail, ret=%d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *send_recv(void *args)
|
||||
{
|
||||
int success = 0;
|
||||
int cfd = ((struct thread_args *)args)->cfd;
|
||||
struct sockaddr_nin si_server = ((struct thread_args *)args)->si_server;
|
||||
|
||||
for (int i = 0; i < PKTCNT; i++) {
|
||||
if (_sendto(cfd, &si_server, i) != 0)
|
||||
goto END;
|
||||
|
||||
if (_recvfrom(cfd, &si_server, i, &success) != 0)
|
||||
goto END;
|
||||
|
||||
usleep(SLEEP_US);
|
||||
}
|
||||
|
||||
END: return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pthread_t th;
|
||||
int cfd;
|
||||
struct thread_args th_args;
|
||||
struct sockaddr_nin si_server;
|
||||
|
||||
cfd = socket(AF_NINET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (cfd < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset((char *)&si_server, 0, sizeof(si_server));
|
||||
si_server.sin_family = AF_NINET;
|
||||
si_server.sin_port = htons(UDP_SERVER_PORT);
|
||||
// 2-byte address of the server: 0xDE00
|
||||
si_server.sin_addr.nip_addr_field8[INDEX_0] = 0xDE;
|
||||
si_server.sin_addr.nip_addr_field8[INDEX_1] = 0x00;
|
||||
si_server.sin_addr.bitlen = NIP_ADDR_BIT_LEN_16; // 2-byte: 16bit
|
||||
|
||||
th_args.si_server = si_server;
|
||||
th_args.si_server.sin_port = htons(UDP_SERVER_PORT);
|
||||
th_args.cfd = cfd;
|
||||
pthread_create(&th, NULL, send_recv, &th_args);
|
||||
/* Wait for the thread to end and synchronize operations between threads */
|
||||
pthread_join(th, NULL);
|
||||
close(cfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define __USE_GNU
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "nip_uapi.h"
|
||||
#include "nip_lib.h"
|
||||
#include "newip_route.h"
|
||||
|
||||
void *recv_send(void *args)
|
||||
{
|
||||
char buf[BUFLEN] = {0};
|
||||
int fd, ret, recv_num;
|
||||
int count = 0;
|
||||
socklen_t slen;
|
||||
struct sockaddr_nin si_remote;
|
||||
|
||||
memcpy(&fd, args, sizeof(int));
|
||||
while (count < PKTCNT) {
|
||||
slen = sizeof(si_remote);
|
||||
memset(buf, 0, sizeof(char) * BUFLEN);
|
||||
memset(&si_remote, 0, sizeof(si_remote));
|
||||
recv_num = recvfrom(fd, buf, BUFLEN, 0, (struct sockaddr *)&si_remote, &slen);
|
||||
if (recv_num < 0) {
|
||||
printf("server recvfrom fail, ret=%d\n", ret);
|
||||
goto END;
|
||||
} else if (recv_num == 0) { /* no data */
|
||||
;
|
||||
} else {
|
||||
printf("Received -- %s -- from 0x%x:%d\n", buf,
|
||||
si_remote.sin_addr.nip_addr_field16[0], ntohs(si_remote.sin_port));
|
||||
slen = sizeof(si_remote);
|
||||
ret = sendto(fd, buf, BUFLEN, 0, (struct sockaddr *)&si_remote, slen);
|
||||
if (ret < 0) {
|
||||
printf("server sendto fail, ret=%d\n", ret);
|
||||
goto END;
|
||||
}
|
||||
printf("Sending -- %s -- to 0x%0x:%d\n", buf,
|
||||
si_remote.sin_addr.nip_addr_field8[0], ntohs(si_remote.sin_port));
|
||||
}
|
||||
count++;
|
||||
}
|
||||
END: return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
pthread_t th;
|
||||
struct sockaddr_nin si_local;
|
||||
|
||||
fd = socket(AF_NINET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset((char *)&si_local, 0, sizeof(si_local));
|
||||
si_local.sin_family = AF_NINET;
|
||||
si_local.sin_port = htons(UDP_SERVER_PORT);
|
||||
// 2-byte address of the server: 0xDE00
|
||||
si_local.sin_addr.nip_addr_field8[INDEX_0] = 0xDE;
|
||||
si_local.sin_addr.nip_addr_field8[INDEX_1] = 0x00;
|
||||
si_local.sin_addr.bitlen = NIP_ADDR_BIT_LEN_16; // 2-byte: 16bit
|
||||
|
||||
if (bind(fd, (const struct sockaddr *)&si_local, sizeof(si_local)) < 0) {
|
||||
perror("bind");
|
||||
goto END;
|
||||
}
|
||||
|
||||
printf("bind success, addr=0x%02x%02x, port=%d\n",
|
||||
si_local.sin_addr.nip_addr_field8[INDEX_0],
|
||||
si_local.sin_addr.nip_addr_field8[INDEX_1], UDP_SERVER_PORT);
|
||||
|
||||
pthread_create(&th, NULL, recv_send, &fd);
|
||||
/* Wait for the thread to end and synchronize operations between threads */
|
||||
pthread_join(th, NULL);
|
||||
|
||||
END: close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,405 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include "nip_addr.h"
|
||||
|
||||
/* This is similar to 0.0.0.0 in IPv4. Does not appear as a real address,
|
||||
* just a constant used by the native for special processing
|
||||
*/
|
||||
const struct nip_addr nip_any_addr = {
|
||||
.bitlen = NIP_ADDR_BIT_LEN_16,
|
||||
.nip_addr_field8[0] = 0xFF, /* 0xFF09 addr, big-endian */
|
||||
.nip_addr_field8[1] = 0x09,
|
||||
};
|
||||
|
||||
const struct nip_addr nip_broadcast_addr_arp = {
|
||||
.bitlen = NIP_ADDR_BIT_LEN_16,
|
||||
.nip_addr_field8[0] = 0xFF, /* 0xFF04 addr, big-endian */
|
||||
.nip_addr_field8[1] = 0x04,
|
||||
};
|
||||
|
||||
enum addr_check_ret {
|
||||
NOT_CURRENT_ADDR = -1,
|
||||
CURRENT_ADDR_VALID = 0,
|
||||
ADDR_2BYTE_INVALID = 1,
|
||||
ADDR_3BYTE_INVALID = 2,
|
||||
ADDR_5BYTE_INVALID = 3,
|
||||
ADDR_7BYTE_INVALID = 4,
|
||||
ADDR_BITLEN_INVALID = 5,
|
||||
NIP_ADDR_UNKNOWN,
|
||||
};
|
||||
|
||||
#define NIP_TRUE 1
|
||||
#define NIP_FALSE 0
|
||||
|
||||
/* Short address range:
|
||||
* 【1-byte】0 ~ 220
|
||||
* 00 ~ DC
|
||||
*/
|
||||
static inline int is_1byte_addr_flag(unsigned char first_byte)
|
||||
{
|
||||
return first_byte <= ADDR_FIRST_DC ? NIP_TRUE : NIP_FALSE;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【2-byte】221 ~ 5119
|
||||
* DD/DE/.../F0 is a 2-byte address descriptor followed by the address value
|
||||
* DDDD ~ DDFF : 221 ~ 255
|
||||
* DE00 ~ DEFF : 256 ~ 511
|
||||
* DF00 ~ DFFF : 512 ~ 767
|
||||
* ...
|
||||
* F000 ~ F0FF : 4864 ~ 5119
|
||||
*/
|
||||
static inline int is_2byte_addr_flag(unsigned char first_byte)
|
||||
{
|
||||
return (first_byte > ADDR_FIRST_DC) && (first_byte <= ADDR_FIRST_F0) ?
|
||||
NIP_TRUE : NIP_FALSE;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【3-byte】5120 ~ 65535
|
||||
* F1 is a 3-byte address descriptor followed by the address value
|
||||
* F1 1400 ~ F1 FFFF
|
||||
*/
|
||||
static inline int is_3byte_addr_flag(unsigned char first_byte)
|
||||
{
|
||||
return first_byte == ADDR_FIRST_F1 ? NIP_TRUE : NIP_FALSE;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【5-byte】65536 ~ 4,294,967,295
|
||||
* F2 is a 5-byte address descriptor followed by the address value
|
||||
* F2 0001 0000 ~ F2 FFFF FFFF
|
||||
*/
|
||||
static inline int is_5byte_addr_flag(unsigned char first_byte)
|
||||
{
|
||||
return first_byte == ADDR_FIRST_F2 ? NIP_TRUE : NIP_FALSE;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【7-byte】4,294,967,296 ~ 281,474,976,710,655
|
||||
* F3 is a 7-byte address descriptor followed by the address value
|
||||
* F3 0001 0000 0000 ~ F3 FFFF FFFF FFFF
|
||||
*/
|
||||
static inline int is_7byte_addr_flag(unsigned char first_byte)
|
||||
{
|
||||
return first_byte == ADDR_FIRST_F3 ? NIP_TRUE : NIP_FALSE;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【8-byte】
|
||||
* F4 is a 8-byte address descriptor followed by the address value
|
||||
* F400 0000 0000 0000 ~ F4FF FFFF FFFF FFFF
|
||||
*/
|
||||
static inline int is_8byte_addr_flag(unsigned char first_byte)
|
||||
{
|
||||
return first_byte == ADDR_FIRST_FE ? NIP_TRUE : NIP_FALSE;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【public addr】
|
||||
* 0xFF00 - The loopback address
|
||||
* 0xFF01 - Public address for access authentication
|
||||
* 0xFF02 - Public address of access authentication
|
||||
* 0xFF03 - The neighbor found a public address
|
||||
* 0xFF04 - Address resolution (ARP)
|
||||
* 0xFF05 - DHCP public address
|
||||
* 0xFF06 - Public address for minimalist access authentication
|
||||
* 0xFF07 - Self-organizing protocol public address
|
||||
* 0xFF08 - The IEEE EUI - 64 addresses
|
||||
* 0xFF09 - any_addr
|
||||
*/
|
||||
static inline int is_public_addr_flag(unsigned char first_byte)
|
||||
{
|
||||
return first_byte == ADDR_FIRST_FF ? NIP_TRUE : NIP_FALSE;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【1-byte】0 ~ 220
|
||||
* 00 ~ DC
|
||||
*/
|
||||
static int nip_addr_1byte_check(unsigned char first_byte, unsigned char second_byte,
|
||||
unsigned char third_byte, int addr_len)
|
||||
{
|
||||
int ret = NOT_CURRENT_ADDR;
|
||||
|
||||
if (is_1byte_addr_flag(first_byte) && addr_len == NIP_ADDR_LEN_1)
|
||||
ret = CURRENT_ADDR_VALID;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【2-byte】221 ~ 5119
|
||||
* DD/DE/.../F0 is a 2-byte address descriptor followed by the address value
|
||||
* DDDD ~ DDFF : 221 ~ 255
|
||||
* DE00 ~ DEFF : 256 ~ 511
|
||||
* DF00 ~ DFFF : 512 ~ 767
|
||||
* ...
|
||||
* F000 ~ F0FF : 4864 ~ 5119
|
||||
*/
|
||||
static int nip_addr_2byte_check(unsigned char first_byte, unsigned char second_byte,
|
||||
unsigned char third_byte, int addr_len)
|
||||
{
|
||||
int ret = NOT_CURRENT_ADDR;
|
||||
|
||||
if (is_2byte_addr_flag(first_byte) && addr_len == NIP_ADDR_LEN_2) {
|
||||
if (first_byte > ADDR_FIRST_DC + 1 ||
|
||||
second_byte >= ADDR_SECOND_MIN_DD)
|
||||
ret = CURRENT_ADDR_VALID;
|
||||
else
|
||||
ret = ADDR_2BYTE_INVALID;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【3-byte】5120 ~ 65535
|
||||
* F1 is a 3-byte address descriptor followed by the address value
|
||||
* F1 1400 ~ F1 FFFF
|
||||
*/
|
||||
static int nip_addr_3byte_check(unsigned char first_byte, unsigned char second_byte,
|
||||
unsigned char third_byte, int addr_len)
|
||||
{
|
||||
int ret = NOT_CURRENT_ADDR;
|
||||
|
||||
if (is_3byte_addr_flag(first_byte) && addr_len == NIP_ADDR_LEN_3) {
|
||||
if (second_byte >= ADDR_SECOND_MIN_F1)
|
||||
ret = CURRENT_ADDR_VALID;
|
||||
else
|
||||
ret = ADDR_3BYTE_INVALID;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【5-byte】65536 ~ 4,294,967,295
|
||||
* F2 is a 5-byte address descriptor followed by the address value
|
||||
* F2 0001 0000 ~ F2 FFFF FFFF
|
||||
*/
|
||||
static int nip_addr_5byte_check(unsigned char first_byte, unsigned char second_byte,
|
||||
unsigned char third_byte, int addr_len)
|
||||
{
|
||||
int ret = NOT_CURRENT_ADDR;
|
||||
|
||||
if (is_5byte_addr_flag(first_byte) && addr_len == NIP_ADDR_LEN_5) {
|
||||
if (second_byte > 0 || third_byte >= ADDR_THIRD_MIN_F2)
|
||||
ret = CURRENT_ADDR_VALID;
|
||||
else
|
||||
ret = ADDR_5BYTE_INVALID;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【7-byte】4,294,967,296 ~ 281,474,976,710,655
|
||||
* F3 is a 7-byte address descriptor followed by the address value
|
||||
* F3 0001 0000 0000 ~ F3 FFFF FFFF FFFF
|
||||
*/
|
||||
static int nip_addr_7byte_check(unsigned char first_byte, unsigned char second_byte,
|
||||
unsigned char third_byte, int addr_len)
|
||||
{
|
||||
int ret = NOT_CURRENT_ADDR;
|
||||
|
||||
if (is_7byte_addr_flag(first_byte) && addr_len == NIP_ADDR_LEN_7) {
|
||||
if (second_byte > 0 || third_byte >= ADDR_THIRD_MIN_F3)
|
||||
ret = CURRENT_ADDR_VALID;
|
||||
else
|
||||
ret = ADDR_7BYTE_INVALID;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【8-byte】
|
||||
* F4 is a 8-byte address descriptor followed by the address value
|
||||
* F400 0000 0000 0000 ~ F4FF FFFF FFFF FFFF
|
||||
*/
|
||||
static int nip_addr_8byte_check(unsigned char first_byte, unsigned char second_byte,
|
||||
unsigned char third_byte, int addr_len)
|
||||
{
|
||||
int ret = NOT_CURRENT_ADDR;
|
||||
|
||||
if (is_8byte_addr_flag(first_byte) && addr_len == NIP_ADDR_LEN_8)
|
||||
ret = CURRENT_ADDR_VALID;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Short address range:
|
||||
* 【public addr】
|
||||
* 0xFF00 - The loopback address
|
||||
* 0xFF01 - Public address for access authentication
|
||||
* 0xFF02 - Public address of access authentication
|
||||
* 0xFF03 - The neighbor found a public address
|
||||
* 0xFF04 - Address resolution (ARP)
|
||||
* 0xFF05 - DHCP public address
|
||||
* 0xFF06 - Public address for minimalist access authentication
|
||||
* 0xFF07 - Self-organizing protocol public address
|
||||
* 0xFF08 - The IEEE EUI - 64 addresses
|
||||
* 0xFF09 - any_addr
|
||||
*/
|
||||
static int nip_addr_public_check(unsigned char first_byte, unsigned char second_byte,
|
||||
unsigned char third_byte, int addr_len)
|
||||
{
|
||||
int ret = NOT_CURRENT_ADDR;
|
||||
|
||||
if (is_public_addr_flag(first_byte) && addr_len == NIP_ADDR_LEN_2)
|
||||
ret = CURRENT_ADDR_VALID;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nip_addr_unknown(unsigned char first_byte, unsigned char second_byte,
|
||||
unsigned char third_byte, int addr_len)
|
||||
{
|
||||
return NIP_ADDR_UNKNOWN;
|
||||
}
|
||||
|
||||
#define CHECK_FUN_MAX 8
|
||||
static int (*nip_addr_check_fun[CHECK_FUN_MAX])(unsigned char first_byte,
|
||||
unsigned char second_byte,
|
||||
unsigned char third_byte,
|
||||
int addr_len) = {
|
||||
nip_addr_1byte_check,
|
||||
nip_addr_2byte_check,
|
||||
nip_addr_3byte_check,
|
||||
nip_addr_5byte_check,
|
||||
nip_addr_7byte_check,
|
||||
nip_addr_8byte_check,
|
||||
nip_addr_public_check,
|
||||
nip_addr_unknown,
|
||||
};
|
||||
|
||||
int nip_addr_invalid(const struct nip_addr *addr)
|
||||
{
|
||||
int i;
|
||||
int addr_len;
|
||||
int ret = NIP_ADDR_UNKNOWN;
|
||||
unsigned char first_byte, second_byte, third_byte;
|
||||
|
||||
first_byte = addr->nip_addr_field8[NIP_8BIT_ADDR_INDEX_0];
|
||||
second_byte = addr->nip_addr_field8[NIP_8BIT_ADDR_INDEX_1];
|
||||
third_byte = addr->nip_addr_field8[NIP_8BIT_ADDR_INDEX_2];
|
||||
addr_len = addr->bitlen / NIP_ADDR_BIT_LEN_8;
|
||||
|
||||
/* The value of the field after the effective length of the short address should be 0 */
|
||||
for (i = addr_len; i < NIP_8BIT_ADDR_INDEX_MAX; i++) {
|
||||
if (addr->nip_addr_field8[i] > 0x00)
|
||||
return ADDR_BITLEN_INVALID;
|
||||
}
|
||||
|
||||
for (i = 0; i < CHECK_FUN_MAX; i++) {
|
||||
ret = nip_addr_check_fun[i](first_byte, second_byte, third_byte, addr_len);
|
||||
if (ret == CURRENT_ADDR_VALID)
|
||||
return ret;
|
||||
else if (ret == NOT_CURRENT_ADDR)
|
||||
continue;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 0xFF00 - The loopback address
|
||||
* 0xFF01 - Public address for access authentication
|
||||
* 0xFF02 - Public address of access authentication
|
||||
* 0xFF03 - The neighbor found a public address
|
||||
* 0xFF04 - Address resolution (ARP)
|
||||
* 0xFF05 - DHCP public address
|
||||
* 0xFF06 - Public address for minimalist access authentication
|
||||
* 0xFF07 - Self-organizing protocol public address
|
||||
* 0xFF08 - The IEEE EUI - 64 addresses
|
||||
* 0xFF09 - any_addr
|
||||
*/
|
||||
int nip_addr_public(const struct nip_addr *addr)
|
||||
{
|
||||
if (is_public_addr_flag(addr->nip_addr_field8[NIP_8BIT_ADDR_INDEX_0]) &&
|
||||
addr->bitlen == NIP_ADDR_BIT_LEN_16)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* judge whether the nip_addr is equal to 0xFF09 */
|
||||
int nip_addr_any(const struct nip_addr *ad)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (ad->bitlen == NIP_ADDR_BIT_LEN_16) {
|
||||
if (ad->nip_addr_field16[0] == nip_any_addr.nip_addr_field16[0] &&
|
||||
ad->nip_addr_field16[1] == nip_any_addr.nip_addr_field16[1])
|
||||
result = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int get_nip_addr_len(const struct nip_addr *addr)
|
||||
{
|
||||
int len = 0;
|
||||
unsigned char first_byte = addr->nip_addr_field8[0];
|
||||
|
||||
if (is_1byte_addr_flag(first_byte))
|
||||
len = NIP_ADDR_LEN_1;
|
||||
else if (is_2byte_addr_flag(first_byte) || is_public_addr_flag(first_byte))
|
||||
len = NIP_ADDR_LEN_2;
|
||||
else if (is_3byte_addr_flag(first_byte))
|
||||
len = NIP_ADDR_LEN_3;
|
||||
else if (is_5byte_addr_flag(first_byte))
|
||||
len = NIP_ADDR_LEN_5;
|
||||
else if (is_7byte_addr_flag(first_byte))
|
||||
len = NIP_ADDR_LEN_7;
|
||||
else if (is_8byte_addr_flag(first_byte))
|
||||
len = NIP_ADDR_LEN_8;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
unsigned char *build_nip_addr(const struct nip_addr *addr, unsigned char *buf)
|
||||
{
|
||||
int i;
|
||||
unsigned char *p = buf;
|
||||
int addr_len = get_nip_addr_len(addr);
|
||||
|
||||
if (addr_len == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < addr_len; i++) {
|
||||
*p = addr->nip_addr_field8[i];
|
||||
p++;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
unsigned char *decode_nip_addr(unsigned char *buf, struct nip_addr *addr)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
int addr_len;
|
||||
unsigned char *p = buf;
|
||||
|
||||
addr->nip_addr_field8[0] = *p;
|
||||
addr_len = get_nip_addr_len(addr);
|
||||
if (addr_len == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < addr_len; i++) {
|
||||
addr->nip_addr_field8[i] = *p;
|
||||
p++;
|
||||
}
|
||||
addr->bitlen = addr_len * NIP_ADDR_BIT_LEN_8;
|
||||
|
||||
ret = nip_addr_invalid(addr);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#ifndef _UAPI_NEWIP_ADDR_H
|
||||
#define _UAPI_NEWIP_ADDR_H
|
||||
|
||||
#define NIP_ADDR_LEN_1 1
|
||||
#define NIP_ADDR_LEN_2 2
|
||||
#define NIP_ADDR_LEN_3 3
|
||||
#define NIP_ADDR_LEN_4 4
|
||||
#define NIP_ADDR_LEN_5 5
|
||||
#define NIP_ADDR_LEN_7 7
|
||||
#define NIP_ADDR_LEN_8 8
|
||||
|
||||
#define NIP_ADDR_BIT_LEN_8 8
|
||||
#define NIP_ADDR_BIT_LEN_16 16
|
||||
#define NIP_ADDR_BIT_LEN_24 24
|
||||
#define NIP_ADDR_BIT_LEN_40 40
|
||||
#define NIP_ADDR_BIT_LEN_MAX 64
|
||||
|
||||
enum nip_addr_check_value {
|
||||
ADDR_FIRST_DC = 0xDC,
|
||||
ADDR_FIRST_F0 = 0xF0,
|
||||
ADDR_FIRST_F1,
|
||||
ADDR_FIRST_F2,
|
||||
ADDR_FIRST_F3,
|
||||
ADDR_FIRST_FE = 0xFE,
|
||||
ADDR_FIRST_FF = 0xFF,
|
||||
ADDR_SECOND_MIN_DD = 0xDD,
|
||||
ADDR_SECOND_MIN_F1 = 0x14, /* f1 14 00 */
|
||||
ADDR_THIRD_MIN_F2 = 0x01, /* f2 00 01 00 00 */
|
||||
ADDR_THIRD_MIN_F3 = 0x01, /* F3 0001 0000 0000 */
|
||||
};
|
||||
|
||||
enum nip_8bit_addr_index {
|
||||
NIP_8BIT_ADDR_INDEX_0 = 0,
|
||||
NIP_8BIT_ADDR_INDEX_1 = 1,
|
||||
NIP_8BIT_ADDR_INDEX_2 = 2,
|
||||
NIP_8BIT_ADDR_INDEX_3 = 3,
|
||||
NIP_8BIT_ADDR_INDEX_4 = 4,
|
||||
NIP_8BIT_ADDR_INDEX_5 = 5,
|
||||
NIP_8BIT_ADDR_INDEX_6 = 6,
|
||||
NIP_8BIT_ADDR_INDEX_7 = 7,
|
||||
NIP_8BIT_ADDR_INDEX_MAX,
|
||||
};
|
||||
|
||||
enum nip_16bit_addr_index {
|
||||
NIP_16BIT_ADDR_INDEX_0 = 0,
|
||||
NIP_16BIT_ADDR_INDEX_1 = 1,
|
||||
NIP_16BIT_ADDR_INDEX_2 = 2,
|
||||
NIP_16BIT_ADDR_INDEX_3 = 3,
|
||||
NIP_16BIT_ADDR_INDEX_MAX,
|
||||
};
|
||||
|
||||
enum nip_32bit_addr_index {
|
||||
NIP_32BIT_ADDR_INDEX_0 = 0,
|
||||
NIP_32BIT_ADDR_INDEX_1 = 1,
|
||||
NIP_32BIT_ADDR_INDEX_MAX,
|
||||
};
|
||||
|
||||
#define nip_addr_field8 v.u.field8
|
||||
#define nip_addr_field16 v.u.field16
|
||||
#define nip_addr_field32 v.u.field32
|
||||
|
||||
#pragma pack(1)
|
||||
struct nip_addr_field {
|
||||
union {
|
||||
unsigned char field8[NIP_8BIT_ADDR_INDEX_MAX];
|
||||
unsigned short field16[NIP_16BIT_ADDR_INDEX_MAX]; /* big-endian */
|
||||
unsigned int field32[NIP_32BIT_ADDR_INDEX_MAX]; /* big-endian */
|
||||
} u;
|
||||
};
|
||||
|
||||
struct nip_addr {
|
||||
unsigned char bitlen; /* The address length is in bit (not byte) */
|
||||
struct nip_addr_field v;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
enum nip_index {
|
||||
INDEX_0 = 0,
|
||||
INDEX_1 = 1,
|
||||
INDEX_2 = 2,
|
||||
INDEX_3 = 3,
|
||||
INDEX_4 = 4,
|
||||
INDEX_5 = 5,
|
||||
INDEX_6 = 6,
|
||||
INDEX_7 = 7,
|
||||
INDEX_8 = 8,
|
||||
INDEX_9 = 9,
|
||||
INDEX_10 = 10,
|
||||
INDEX_11 = 11,
|
||||
INDEX_12 = 12,
|
||||
INDEX_13 = 13,
|
||||
INDEX_14 = 14,
|
||||
INDEX_15 = 15,
|
||||
INDEX_MAX,
|
||||
};
|
||||
|
||||
extern const struct nip_addr nip_any_addr;
|
||||
extern const struct nip_addr nip_broadcast_addr_arp;
|
||||
|
||||
int nip_addr_invalid(const struct nip_addr *addr);
|
||||
int nip_addr_public(const struct nip_addr *addr);
|
||||
int nip_addr_any(const struct nip_addr *ad);
|
||||
int get_nip_addr_len(const struct nip_addr *addr);
|
||||
unsigned char *build_nip_addr(const struct nip_addr *addr, unsigned char *buf);
|
||||
unsigned char *decode_nip_addr(unsigned char *buf, struct nip_addr *addr);
|
||||
|
||||
#endif /* _UAPI_NEWIP_ADDR_H */
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include "nip_hdr.h"
|
||||
#include "nip_checksum.h"
|
||||
|
||||
#define USHORT_PAYLOAD 16
|
||||
#define NIP_CHECKSUM_UINT8_PAYLOAD 8
|
||||
unsigned int _nip_check_sum(const unsigned char *data, unsigned short data_len)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
unsigned int sum = 0;
|
||||
|
||||
while (i + 1 < data_len) {
|
||||
sum += (data[i] << NIP_CHECKSUM_UINT8_PAYLOAD) + data[i + 1];
|
||||
i += 2; /* Offset 2 bytes */
|
||||
}
|
||||
|
||||
if (i < (unsigned int)data_len)
|
||||
sum += (data[i] << NIP_CHECKSUM_UINT8_PAYLOAD);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
unsigned int _nip_header_chksum(struct nip_pseudo_header *chksum_header)
|
||||
{
|
||||
int i, j;
|
||||
int addr_len;
|
||||
unsigned char pseudo_header[NIP_HDR_MAX] = {0};
|
||||
unsigned short hdr_len = 0;
|
||||
|
||||
addr_len = chksum_header->saddr.bitlen / NIP_ADDR_BIT_LEN_8;
|
||||
if (addr_len) {
|
||||
j = 0;
|
||||
for (i = 0; i < addr_len; i++, j++)
|
||||
pseudo_header[j] = chksum_header->saddr.nip_addr_field8[i];
|
||||
hdr_len += addr_len;
|
||||
}
|
||||
|
||||
addr_len = chksum_header->daddr.bitlen / NIP_ADDR_BIT_LEN_8;
|
||||
if (addr_len) {
|
||||
j = hdr_len;
|
||||
for (i = 0; i < addr_len; i++, j++)
|
||||
pseudo_header[j] = chksum_header->daddr.nip_addr_field8[i];
|
||||
hdr_len += addr_len;
|
||||
}
|
||||
|
||||
/* chksum_header->check_len is network order.(big end) */
|
||||
*(unsigned short *)(pseudo_header + hdr_len) = chksum_header->check_len;
|
||||
hdr_len += sizeof(chksum_header->check_len);
|
||||
*(pseudo_header + hdr_len) = chksum_header->nexthdr;
|
||||
hdr_len += sizeof(chksum_header->nexthdr);
|
||||
|
||||
return _nip_check_sum(pseudo_header, hdr_len);
|
||||
}
|
||||
|
||||
/* The checksum is calculated when the packet is received
|
||||
* Note:
|
||||
* 1.chksum_header->check_len is network order.(big end)
|
||||
* 2.check_len is host order.
|
||||
*/
|
||||
unsigned short nip_check_sum_parse(unsigned char *data,
|
||||
unsigned short check_len,
|
||||
struct nip_pseudo_header *chksum_header)
|
||||
{
|
||||
unsigned int sum = 0;
|
||||
|
||||
sum = _nip_check_sum(data, check_len);
|
||||
sum += _nip_header_chksum(chksum_header);
|
||||
|
||||
while (sum >> USHORT_PAYLOAD)
|
||||
sum = (sum >> USHORT_PAYLOAD) + (sum & 0xffff);
|
||||
return (unsigned short)sum;
|
||||
}
|
||||
|
||||
/* The checksum is calculated when the packet is sent
|
||||
* Note:
|
||||
* 1.chksum_header->check_len is network order.(big end)
|
||||
* 2.data_len is host order.
|
||||
*/
|
||||
unsigned short nip_check_sum_build(unsigned char *data,
|
||||
unsigned short data_len,
|
||||
struct nip_pseudo_header *chksum_header)
|
||||
{
|
||||
unsigned int sum = 0;
|
||||
|
||||
sum = _nip_check_sum(data, data_len);
|
||||
sum += _nip_header_chksum(chksum_header);
|
||||
|
||||
while (sum >> USHORT_PAYLOAD)
|
||||
sum = (sum >> USHORT_PAYLOAD) + (sum & 0xffff);
|
||||
return (unsigned short)(~sum);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#ifndef _NIP_CHECKSUM_H
|
||||
#define _NIP_CHECKSUM_H
|
||||
|
||||
#include "nip_addr.h"
|
||||
|
||||
struct nip_pseudo_header {
|
||||
struct nip_addr saddr; /* Source address, network order.(big end) */
|
||||
struct nip_addr daddr; /* Destination address, network order.(big end) */
|
||||
unsigned short check_len; /* network order.(big end) */
|
||||
unsigned char nexthdr; /* Upper-layer Protocol Type: IPPROTO_UDP */
|
||||
};
|
||||
|
||||
/* The checksum is calculated when the packet is received
|
||||
* Note:
|
||||
* 1.chksum_header->check_len is network order.(big end)
|
||||
* 2.data_len is host order.
|
||||
*/
|
||||
unsigned short nip_check_sum_parse(unsigned char *data,
|
||||
unsigned short check_len,
|
||||
struct nip_pseudo_header *chksum_header);
|
||||
|
||||
/* The checksum is calculated when the packet is sent
|
||||
* Note:
|
||||
* 1.chksum_header->check_len is network order.(big end)
|
||||
* 2.data_len is host order.
|
||||
*/
|
||||
unsigned short nip_check_sum_build(unsigned char *data,
|
||||
unsigned short data_len,
|
||||
struct nip_pseudo_header *chksum_header);
|
||||
|
||||
#endif /* _NIP_CHECKSUM_H */
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#ifndef _NEWIP_HDR_H
|
||||
#define _NEWIP_HDR_H
|
||||
|
||||
#include "nip_addr.h"
|
||||
|
||||
/* Ethernet head 14B, +2B byte alignment, +66 to avoid
|
||||
* HMAC driver SKB space expansion caused by Coredum problem
|
||||
*/
|
||||
/* This parameter is used only to apply for the length of the packet buffer,
|
||||
* but not to determine the actual packet header length
|
||||
*/
|
||||
#define NIP_ETH_HDR_BASE_LEN 14
|
||||
#define NIP_ETH_HDR_LEN (NIP_ETH_HDR_BASE_LEN + 2 + 66)
|
||||
|
||||
/* bitmap1 + bitmap2 + TTL + total len + nexthd + daddr + saddr
|
||||
* 1B 1B 1B 2B 1B 9B 9B = 24B
|
||||
* V4 TCP 1448
|
||||
* NIP TCP 1430 + 30 = 1460
|
||||
*/
|
||||
/* This interface is only used to define the buffer length.
|
||||
* To calculate the packet header length, use the "get_nip_hdr_len" func
|
||||
*/
|
||||
#define NIP_HDR_MAX 24
|
||||
#define NIP_UDP_HDR_LEN 8
|
||||
#define NIP_MIN_MTU (NIP_HDR_MAX + NIP_UDP_HDR_LEN)
|
||||
#define NIP_BYTE_ALIGNMENT 2
|
||||
|
||||
#define NIP_BITMAP_HAVE_MORE_BIT 0x01
|
||||
|
||||
/* Bitmap 1st Byte: bit0 - bit7 */
|
||||
#define NIP_BITMAP_INVALID_SET 0x80 /* Bit 0 is set */
|
||||
#define NIP_BITMAP_INCLUDE_TTL 0x40 /* Bit 1 is set */
|
||||
#define NIP_BITMAP_INCLUDE_TOTAL_LEN 0x20 /* Bit 2 is set */
|
||||
#define NIP_BITMAP_INCLUDE_NEXT_HDR 0x10 /* Bit 3 is set */
|
||||
#define NIP_BITMAP_INCLUDE_RES1 0x08 /* Bit 4 is set */
|
||||
#define NIP_BITMAP_INCLUDE_DADDR 0x04 /* Bit 5 is set */
|
||||
#define NIP_BITMAP_INCLUDE_SADDR 0x02 /* Bit 6 is set */
|
||||
#define NIP_BITMAP_HAVE_BYTE_2 NIP_BITMAP_HAVE_MORE_BIT /* Bit 7 is set */
|
||||
|
||||
/* Bitmap 2nd Byte: bit0 - bit7 */
|
||||
#define NIP_BITMAP_INCLUDE_HDR_LEN 0x80 /* Bit 0 is set */
|
||||
#define NIP_BITMAP_INCLUDE_RES2 0x40 /* Bit 1 is set */
|
||||
#define NIP_BITMAP_INCLUDE_RES3 0x20 /* Bit 2 is set */
|
||||
#define NIP_BITMAP_INCLUDE_RES4 0x10 /* Bit 3 is set */
|
||||
#define NIP_BITMAP_INCLUDE_RES5 0x08 /* Bit 4 is set */
|
||||
#define NIP_BITMAP_INCLUDE_RES6 0x04 /* Bit 5 is set */
|
||||
#define NIP_BITMAP_INCLUDE_RES7 0x02 /* Bit 6 is set */
|
||||
#define NIP_BITMAP_HAVE_BYTE_3 NIP_BITMAP_HAVE_MORE_BIT /* Bit 7 is set */
|
||||
|
||||
/* Bitmap 1st Byte:
|
||||
* | valid | ttl | total_len | next_hdr | res1 | daddr | saddr | have byte2 |
|
||||
* | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 |
|
||||
*/
|
||||
#define NIP_UDP_BITMAP_1 0x56
|
||||
#define NIP_UDP_BITMAP_1_INC_2 0x57
|
||||
|
||||
/* Bitmap 1st Byte:
|
||||
* | valid | ttl | total_len | next_hdr | res1 | daddr | saddr | have byte2 |
|
||||
* | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 |
|
||||
*/
|
||||
#define NIP_NORMAL_BITMAP_1 0x76
|
||||
#define NIP_NORMAL_BITMAP_1_INC_2 0x77
|
||||
|
||||
/* Bitmap 2nd Byte:
|
||||
* | hdr_len | res2 | res2 | res2 | res2 | res2 | res2 | have byte3 |
|
||||
* | 0 or 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
*/
|
||||
#define NIP_NODATA_BITMAP_2 0x00
|
||||
#define NIP_NORMAL_BITMAP_2 0x80
|
||||
|
||||
/* invalid Bitmap 2nd Byte:
|
||||
* | hdr_len | res2 | res2 | res2 | res2 | res2 | res2 | have byte3 |
|
||||
* | 0 or 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
|
||||
*/
|
||||
#define NIP_INVALID_BITMAP_2 0x7F
|
||||
|
||||
#define NIP_DEFAULT_TTL 128
|
||||
#define NIP_ARP_DEFAULT_TTL 64
|
||||
#define IPPROTO_NIP_ICMP 0xB1
|
||||
|
||||
enum NIP_HDR_TYPE {
|
||||
NIP_HDR_UDP = 0,
|
||||
NIP_HDR_COMM = 1,
|
||||
|
||||
NIP_HDR_TYPE_MAX,
|
||||
};
|
||||
|
||||
enum NIP_HDR_DECAP_ERR {
|
||||
NIP_HDR_BITMAP_INVALID = 1,
|
||||
NIP_HDR_BITMAP_NUM_OUT_RANGE = 2,
|
||||
NIP_HDR_NO_TTL = 3,
|
||||
NIP_HDR_NO_NEXT_HDR = 4,
|
||||
NIP_HDR_NO_DADDR = 5,
|
||||
NIP_HDR_DECAP_DADDR_ERR = 6,
|
||||
NIP_HDR_DADDR_INVALID = 7,
|
||||
NIP_HDR_DECAP_SADDR_ERR = 8,
|
||||
NIP_HDR_SADDR_INVALID = 9,
|
||||
NIP_HDR_RCV_BUF_READ_OUT_RANGE = 10,
|
||||
NIP_HDR_UNKNOWN_AND_NO_HDR_LEN = 11,
|
||||
NIP_HDR_LEN_INVALID = 12,
|
||||
NIP_HDR_LEN_OUT_RANGE = 13,
|
||||
|
||||
NIP_HDR_DECAP_ERRCODE_MAX,
|
||||
};
|
||||
|
||||
/* The newIP header contains variable-length fields.
|
||||
* The header structure is defined only for function parameter transmission.
|
||||
* The fields are parsed in the original packet and saved
|
||||
*/
|
||||
struct nip_hdr_decap {
|
||||
struct nip_addr saddr; /* Source address, network order.(big end) */
|
||||
struct nip_addr daddr; /* Destination address, network order.(big end) */
|
||||
|
||||
unsigned char ttl; /* Hop count limit */
|
||||
unsigned char nexthdr; /* Upper-layer Protocol Type: IPPROTO_UDP */
|
||||
unsigned char hdr_len; /* Indicates the length of the packet header */
|
||||
unsigned char hdr_real_len; /* Indicates the actual length of the packet header */
|
||||
|
||||
unsigned short total_len; /* Packet length (Header + packet), network order.(big end) */
|
||||
unsigned short no_hdr_len : 1; /* The header does not contain a header length field */
|
||||
unsigned short include_unknown_bit : 1; /* There is no other bitmap field */
|
||||
unsigned short include_saddr : 1;
|
||||
unsigned short include_daddr : 1;
|
||||
unsigned short include_ttl : 1;
|
||||
unsigned short include_nexthdr : 1;
|
||||
unsigned short include_hdr_len : 1;
|
||||
unsigned short include_total_len : 1;
|
||||
unsigned short res : 8;
|
||||
|
||||
unsigned int rcv_buf_len;
|
||||
};
|
||||
|
||||
/* The newIP packet header function is an incoming or outgoing parameter,
|
||||
* which is not the content encapsulated in the packet
|
||||
*/
|
||||
#define BITMAP_MAX 8
|
||||
#define RES_NUM 2
|
||||
struct nip_hdr_encap {
|
||||
struct nip_addr daddr; /* Destination address, network order.(big end) */
|
||||
struct nip_addr saddr; /* Source address, network order.(big end) */
|
||||
|
||||
unsigned char ttl; /* Hop count limit */
|
||||
unsigned char nexthdr; /* Upper-layer Protocol Type: IPPROTO_UDP */
|
||||
unsigned short total_len; /* Packet header length + packet data length */
|
||||
|
||||
void *usr_data; /* User data pointer */
|
||||
unsigned int usr_data_len; /* Length of data sent by the user */
|
||||
unsigned int trans_hdr_len; /* Transport layer header length */
|
||||
|
||||
unsigned short sport;
|
||||
unsigned short dport;
|
||||
|
||||
/* The following are the output parameters */
|
||||
unsigned char bitmap[BITMAP_MAX]; /* Bitmap currently supports a maximum of 8 bytes */
|
||||
unsigned int bitmap_num; /* Number of valid elements in the bitmap array */
|
||||
|
||||
unsigned char *hdr_buf; /* Cache the newIP header */
|
||||
unsigned int hdr_buf_pos; /* Buf Buffer writable address offset */
|
||||
unsigned short *frag_id_pos; /* Fragment Offset in the original packet */
|
||||
unsigned char *hdr_len_pos; /* Indicates the actual length of the packet header */
|
||||
unsigned short *total_len_pos; /* Total length position of the packet */
|
||||
|
||||
/* Whether the bitmap of the packet header carries a flag */
|
||||
unsigned char encap_ttl : 1;
|
||||
unsigned char encap_hdr_len : 1;
|
||||
unsigned char encap_daddr : 1;
|
||||
unsigned char encap_saddr : 1;
|
||||
unsigned char encap_total_len : 1;
|
||||
unsigned char encap_res : 3;
|
||||
};
|
||||
|
||||
/* Packet segment information */
|
||||
struct nip_pkt_seg_info {
|
||||
unsigned int mid_pkt_num; /* Number of intermediate segments */
|
||||
unsigned int last_pkt_num; /* Number of last segments */
|
||||
|
||||
unsigned int mid_usr_pkt_len; /* Middle segment data length (8B aligned) */
|
||||
unsigned int last_usr_pkt_len; /* Length of the last data segment */
|
||||
|
||||
unsigned char *usr_data; /* Holds a pointer to the user's raw data */
|
||||
unsigned int usr_data_len; /* Length of user data read this time */
|
||||
};
|
||||
|
||||
void nip_calc_pkt_frag_num(unsigned int mtu,
|
||||
unsigned int nip_hdr_len,
|
||||
unsigned int usr_data_len,
|
||||
struct nip_pkt_seg_info *seg_info);
|
||||
|
||||
void nip_hdr_udp_encap(struct nip_hdr_encap *head);
|
||||
|
||||
/* need update total len after this func, call nip_update_total_len */
|
||||
void nip_hdr_comm_encap(struct nip_hdr_encap *head);
|
||||
|
||||
/* input must be network order. */
|
||||
void nip_update_total_len(struct nip_hdr_encap *head, unsigned short total_len);
|
||||
|
||||
/* Note: a function call requires its own byte order conversion.(niph->total_len) */
|
||||
int nip_hdr_parse(unsigned char *rcv_buf, unsigned int buf_len, struct nip_hdr_decap *niph);
|
||||
|
||||
/* The length of the packet header is obtained according to the packet type,
|
||||
* source ADDRESS, and destination address.
|
||||
* If the packet does not carry the source address or destination address, fill in the blank
|
||||
*/
|
||||
int get_nip_hdr_len(enum NIP_HDR_TYPE hdr_type,
|
||||
const struct nip_addr *saddr,
|
||||
const struct nip_addr *daddr);
|
||||
|
||||
struct udp_hdr {
|
||||
unsigned short sport;
|
||||
unsigned short dport;
|
||||
unsigned short len;
|
||||
unsigned short checksum;
|
||||
};
|
||||
|
||||
/* input must be network order. */
|
||||
static inline void nip_build_udp_hdr(unsigned short sport, unsigned short dport,
|
||||
unsigned short len, unsigned char *buf,
|
||||
unsigned short checksum)
|
||||
{
|
||||
struct udp_hdr *uh;
|
||||
|
||||
uh = (struct udp_hdr *)buf;
|
||||
uh->sport = sport;
|
||||
uh->dport = dport;
|
||||
uh->len = len;
|
||||
uh->checksum = checksum;
|
||||
}
|
||||
|
||||
#endif /* _NEWIP_HDR_H */
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include "nip_hdr.h"
|
||||
|
||||
/* Must carry the current field */
|
||||
static int _get_nip_hdr_bitmap(unsigned char *buf,
|
||||
unsigned char bitmap[],
|
||||
unsigned char bitmap_index_max)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned char *p = buf;
|
||||
|
||||
if (*p & NIP_BITMAP_INVALID_SET)
|
||||
return -NIP_HDR_BITMAP_INVALID;
|
||||
|
||||
do {
|
||||
if (i >= bitmap_index_max)
|
||||
return -NIP_HDR_BITMAP_NUM_OUT_RANGE;
|
||||
|
||||
bitmap[i] = *p;
|
||||
p++;
|
||||
} while (bitmap[i++] & NIP_BITMAP_HAVE_MORE_BIT);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Must carry the current field */
|
||||
static int _get_nip_hdr_ttl(const unsigned char *buf,
|
||||
unsigned char bitmap,
|
||||
struct nip_hdr_decap *niph)
|
||||
{
|
||||
if (!(bitmap & NIP_BITMAP_INCLUDE_TTL))
|
||||
return -NIP_HDR_NO_TTL;
|
||||
|
||||
niph->ttl = *buf;
|
||||
niph->include_ttl = 1;
|
||||
|
||||
return sizeof(niph->ttl);
|
||||
}
|
||||
|
||||
/* Optional fields */
|
||||
/* Communication between devices of the same version may not carry packet Header length,
|
||||
* but communication between devices of different versions must carry packet header length
|
||||
*/
|
||||
static int _get_nip_hdr_len(const unsigned char *buf,
|
||||
unsigned char bitmap,
|
||||
struct nip_hdr_decap *niph)
|
||||
{
|
||||
if (!(bitmap & NIP_BITMAP_INCLUDE_HDR_LEN))
|
||||
return 0;
|
||||
|
||||
/* Total_len is a network sequence and cannot be
|
||||
* compared directly with the local sequence
|
||||
*/
|
||||
niph->hdr_len = *buf;
|
||||
niph->include_hdr_len = 1;
|
||||
|
||||
if (niph->include_total_len && niph->hdr_len >= niph->rcv_buf_len)
|
||||
return -NIP_HDR_LEN_OUT_RANGE;
|
||||
|
||||
return sizeof(niph->hdr_len);
|
||||
}
|
||||
|
||||
/* Must carry the current field */
|
||||
static int _get_nip_hdr_nexthdr(const unsigned char *buf,
|
||||
unsigned char bitmap,
|
||||
struct nip_hdr_decap *niph)
|
||||
{
|
||||
if (!(bitmap & NIP_BITMAP_INCLUDE_NEXT_HDR))
|
||||
return -NIP_HDR_NO_NEXT_HDR;
|
||||
|
||||
niph->nexthdr = *buf;
|
||||
niph->include_nexthdr = 1;
|
||||
|
||||
return sizeof(niph->nexthdr);
|
||||
}
|
||||
|
||||
/* Must carry the current field */
|
||||
/* Note: niph->saddr is network order.(big end) */
|
||||
static int _get_nip_hdr_daddr(unsigned char *buf,
|
||||
unsigned char bitmap,
|
||||
struct nip_hdr_decap *niph)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
if (!(bitmap & NIP_BITMAP_INCLUDE_DADDR))
|
||||
return -NIP_HDR_NO_DADDR;
|
||||
|
||||
p = decode_nip_addr(buf, &niph->daddr);
|
||||
if (!p)
|
||||
return -NIP_HDR_DECAP_DADDR_ERR;
|
||||
|
||||
if (nip_addr_invalid(&niph->daddr))
|
||||
return -NIP_HDR_DADDR_INVALID;
|
||||
|
||||
niph->include_daddr = 1;
|
||||
return (niph->daddr.bitlen / NIP_ADDR_BIT_LEN_8);
|
||||
}
|
||||
|
||||
/* Optional fields */
|
||||
/* Note: niph->daddr is network order.(big end) */
|
||||
static int _get_nip_hdr_saddr(unsigned char *buf,
|
||||
unsigned char bitmap,
|
||||
struct nip_hdr_decap *niph)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
if (!(bitmap & NIP_BITMAP_INCLUDE_SADDR))
|
||||
return 0;
|
||||
|
||||
p = decode_nip_addr(buf, &niph->saddr);
|
||||
if (!p)
|
||||
return -NIP_HDR_DECAP_SADDR_ERR;
|
||||
|
||||
if (nip_addr_invalid(&niph->saddr))
|
||||
return -NIP_HDR_SADDR_INVALID;
|
||||
|
||||
niph->include_saddr = 1;
|
||||
return (niph->saddr.bitlen / NIP_ADDR_BIT_LEN_8);
|
||||
}
|
||||
|
||||
/* Optional fields: tcp/arp need, udp needless */
|
||||
/* Note: niph->total_len is network order.(big end), need change to host order */
|
||||
static int _get_nip_total_len(unsigned char *buf,
|
||||
unsigned char bitmap,
|
||||
struct nip_hdr_decap *niph)
|
||||
{
|
||||
if (!(bitmap & NIP_BITMAP_INCLUDE_TOTAL_LEN))
|
||||
return 0;
|
||||
|
||||
/* Total_len is a network sequence and cannot be
|
||||
* compared directly with the local sequence
|
||||
*/
|
||||
niph->total_len = *((unsigned short *)buf);
|
||||
niph->include_total_len = 1;
|
||||
|
||||
return sizeof(niph->total_len);
|
||||
}
|
||||
|
||||
static int _nip_hdr_bitmap0_parse(unsigned char *buf,
|
||||
unsigned char bitmap,
|
||||
struct nip_hdr_decap *niph)
|
||||
{
|
||||
int len;
|
||||
int len_total = 0;
|
||||
|
||||
len = _get_nip_hdr_ttl(buf, bitmap, niph);
|
||||
if (len < 0)
|
||||
return len;
|
||||
len_total += len;
|
||||
|
||||
/* Optional fields */
|
||||
len = _get_nip_total_len(buf + len_total, bitmap, niph);
|
||||
if (len < 0)
|
||||
return len;
|
||||
len_total += len;
|
||||
|
||||
len = _get_nip_hdr_nexthdr(buf + len_total, bitmap, niph);
|
||||
if (len < 0)
|
||||
return len;
|
||||
len_total += len;
|
||||
|
||||
len = _get_nip_hdr_daddr(buf + len_total, bitmap, niph);
|
||||
if (len < 0)
|
||||
return len;
|
||||
len_total += len;
|
||||
|
||||
len = _get_nip_hdr_saddr(buf + len_total, bitmap, niph);
|
||||
if (len < 0)
|
||||
return len;
|
||||
len_total += len;
|
||||
|
||||
return len_total;
|
||||
}
|
||||
|
||||
static int _nip_hdr_bitmap1_parse(unsigned char *buf,
|
||||
unsigned char bitmap,
|
||||
struct nip_hdr_decap *niph)
|
||||
{
|
||||
int len;
|
||||
int len_total = 0;
|
||||
|
||||
/* If add new field needs to be modified with the macro definition */
|
||||
if (bitmap & NIP_INVALID_BITMAP_2)
|
||||
niph->include_unknown_bit = 1;
|
||||
|
||||
/* Optional fields */
|
||||
len = _get_nip_hdr_len(buf + len_total, bitmap, niph);
|
||||
if (len < 0)
|
||||
return len;
|
||||
len_total += len;
|
||||
|
||||
return len_total;
|
||||
}
|
||||
|
||||
static int _nip_hdr_unknown_bit_check(unsigned char *buf,
|
||||
unsigned char bitmap,
|
||||
struct nip_hdr_decap *niph)
|
||||
{
|
||||
niph->include_unknown_bit = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FACTORY_NUM_MAX 3
|
||||
static int (*hdr_parse_factory[FACTORY_NUM_MAX])(unsigned char *,
|
||||
unsigned char,
|
||||
struct nip_hdr_decap *) = {
|
||||
_nip_hdr_bitmap0_parse,
|
||||
_nip_hdr_bitmap1_parse,
|
||||
_nip_hdr_unknown_bit_check,
|
||||
};
|
||||
|
||||
static int nip_hdr_check(struct nip_hdr_decap *niph)
|
||||
{
|
||||
if (niph->include_unknown_bit && !niph->include_hdr_len)
|
||||
/* different ver pkt but no hdr len */
|
||||
return -NIP_HDR_UNKNOWN_AND_NO_HDR_LEN;
|
||||
|
||||
if (niph->include_hdr_len) {
|
||||
if (niph->hdr_len == 0 ||
|
||||
niph->hdr_len < niph->hdr_real_len)
|
||||
return -NIP_HDR_LEN_INVALID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note:
|
||||
* 1.niph->total_len is network order.(big end), need change to host order
|
||||
* 2.niph->saddr/daddr is network order.(big end)
|
||||
*/
|
||||
int nip_hdr_parse(unsigned char *rcv_buf, unsigned int buf_len, struct nip_hdr_decap *niph)
|
||||
{
|
||||
int i = 0;
|
||||
int ret;
|
||||
unsigned char *buf = rcv_buf;
|
||||
unsigned char bitmap[BITMAP_MAX] = {0};
|
||||
int num = _get_nip_hdr_bitmap(buf, bitmap, BITMAP_MAX);
|
||||
|
||||
if (num <= 0 || !rcv_buf)
|
||||
return num;
|
||||
|
||||
niph->hdr_real_len = num * sizeof(bitmap[0]);
|
||||
buf += niph->hdr_real_len;
|
||||
|
||||
niph->rcv_buf_len = buf_len;
|
||||
while (i < num) {
|
||||
int len;
|
||||
|
||||
if (i >= FACTORY_NUM_MAX)
|
||||
break;
|
||||
len = hdr_parse_factory[i](buf, bitmap[i], niph);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
buf += len;
|
||||
niph->hdr_real_len += len;
|
||||
if (niph->hdr_real_len >= buf_len)
|
||||
return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
|
||||
i++;
|
||||
}
|
||||
|
||||
ret = nip_hdr_check(niph);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return niph->hdr_len > niph->hdr_real_len ?
|
||||
niph->hdr_len : niph->hdr_real_len;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
#include "nip_hdr.h"
|
||||
|
||||
#define INTEGER_MULTIPLE_OF_8 (~7) /* ~7 is an integer multiple of 8 */
|
||||
#define FMT_FACTORY_NUM_MAX 1
|
||||
#define ENCAP_FACTORY_NUM_MAX 1
|
||||
|
||||
void nip_calc_pkt_frag_num(unsigned int mtu,
|
||||
unsigned int nip_hdr_len,
|
||||
unsigned int usr_data_len,
|
||||
struct nip_pkt_seg_info *seg_info)
|
||||
{
|
||||
unsigned int mid_usr_pkt_len = (mtu - nip_hdr_len - NIP_UDP_HDR_LEN) &
|
||||
INTEGER_MULTIPLE_OF_8;
|
||||
unsigned int mid_pkt_num = usr_data_len / mid_usr_pkt_len;
|
||||
unsigned int last_usr_pkt_len = 0;
|
||||
|
||||
if (usr_data_len != 0) {
|
||||
last_usr_pkt_len = usr_data_len % mid_usr_pkt_len;
|
||||
if (last_usr_pkt_len == 0) {
|
||||
last_usr_pkt_len = mid_usr_pkt_len;
|
||||
mid_pkt_num--;
|
||||
}
|
||||
}
|
||||
|
||||
seg_info->last_pkt_num = 1;
|
||||
seg_info->mid_pkt_num = mid_pkt_num;
|
||||
seg_info->mid_usr_pkt_len = mid_usr_pkt_len;
|
||||
seg_info->last_usr_pkt_len = last_usr_pkt_len;
|
||||
}
|
||||
|
||||
static inline void _nip_hdr_ttl_encap(struct nip_hdr_encap *head)
|
||||
{
|
||||
*(head->hdr_buf + head->hdr_buf_pos) = head->ttl;
|
||||
head->hdr_buf_pos += sizeof(head->ttl);
|
||||
}
|
||||
|
||||
static inline void _nip_hdr_len_encap(struct nip_hdr_encap *head)
|
||||
{
|
||||
head->hdr_len_pos = head->hdr_buf + head->hdr_buf_pos;
|
||||
head->hdr_buf_pos += 1;
|
||||
}
|
||||
|
||||
static inline void _nip_update_hdr_len(struct nip_hdr_encap *head)
|
||||
{
|
||||
*head->hdr_len_pos = head->hdr_buf_pos;
|
||||
}
|
||||
|
||||
static inline void _nip_hdr_nexthdr_encap(struct nip_hdr_encap *head)
|
||||
{
|
||||
*(head->hdr_buf + head->hdr_buf_pos) = head->nexthdr;
|
||||
head->hdr_buf_pos += sizeof(head->nexthdr);
|
||||
}
|
||||
|
||||
static inline void _nip_hdr_daddr_encap(struct nip_hdr_encap *head)
|
||||
{
|
||||
(void)build_nip_addr(&head->daddr, (head->hdr_buf + head->hdr_buf_pos));
|
||||
head->hdr_buf_pos += (head->daddr.bitlen / NIP_ADDR_BIT_LEN_8);
|
||||
}
|
||||
|
||||
static inline void _nip_hdr_saddr_encap(struct nip_hdr_encap *head)
|
||||
{
|
||||
(void)build_nip_addr(&head->saddr, (head->hdr_buf + head->hdr_buf_pos));
|
||||
head->hdr_buf_pos += (head->saddr.bitlen / NIP_ADDR_BIT_LEN_8);
|
||||
}
|
||||
|
||||
static inline void _nip_hdr_total_len_encap(struct nip_hdr_encap *head)
|
||||
{
|
||||
head->total_len_pos = (unsigned short *)(head->hdr_buf + head->hdr_buf_pos);
|
||||
head->hdr_buf_pos += sizeof(head->total_len);
|
||||
}
|
||||
|
||||
/* total_len must be network order.(big end) */
|
||||
void nip_update_total_len(struct nip_hdr_encap *head, unsigned short total_len)
|
||||
{
|
||||
*head->total_len_pos = total_len;
|
||||
}
|
||||
|
||||
#define BITMAP1_OFFSET 1
|
||||
#define BITMAP2_OFFSET 2
|
||||
static inline void _nip_hdr_encap_udp_bitmap(struct nip_hdr_encap *head)
|
||||
{
|
||||
/* bitmap(1B) + ttl(1B) + total_len(2B) + nexthdr(1B) + daddr(xB) + saddr(xB) */
|
||||
/* If the length of the destination address and the source address is even,
|
||||
* the length of the packet header must be odd. You need to add 1-byte alignment
|
||||
* and 1-byte bitmap
|
||||
*/
|
||||
if (((head->daddr.bitlen / NIP_ADDR_BIT_LEN_8) + (head->saddr.bitlen / NIP_ADDR_BIT_LEN_8))
|
||||
% NIP_BYTE_ALIGNMENT != 0) {
|
||||
head->hdr_buf[0] = NIP_UDP_BITMAP_1;
|
||||
head->hdr_buf_pos = BITMAP1_OFFSET;
|
||||
} else {
|
||||
head->hdr_buf[0] = NIP_UDP_BITMAP_1_INC_2;
|
||||
head->hdr_buf[1] = NIP_NODATA_BITMAP_2;
|
||||
head->hdr_buf_pos = BITMAP2_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _nip_hdr_encap_comm_bitmap(struct nip_hdr_encap *head)
|
||||
{
|
||||
/* bitmap(1B) + ttl(1B) + nexthdr(1B) + daddr(xB) + saddr(xB) */
|
||||
/* If the length of the destination address and the source address is even,
|
||||
* the length of the packet header must be odd. You need to add 1-byte alignment
|
||||
* and 1-byte bitmap
|
||||
*/
|
||||
if (((head->daddr.bitlen / NIP_ADDR_BIT_LEN_8) + (head->saddr.bitlen / NIP_ADDR_BIT_LEN_8))
|
||||
% NIP_BYTE_ALIGNMENT != 0) {
|
||||
head->hdr_buf[0] = NIP_NORMAL_BITMAP_1;
|
||||
head->hdr_buf_pos = BITMAP1_OFFSET;
|
||||
} else {
|
||||
head->hdr_buf[0] = NIP_NORMAL_BITMAP_1_INC_2;
|
||||
head->hdr_buf[1] = NIP_NODATA_BITMAP_2;
|
||||
head->hdr_buf_pos = BITMAP2_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
#define NEWIP_BYTE_ALIGNMENT_ENABLE 1 // 0: disable; 1: enable
|
||||
|
||||
void nip_hdr_udp_encap(struct nip_hdr_encap *head)
|
||||
{
|
||||
/* Encapsulate the bitmap into the newIP packet header BUF */
|
||||
#if (NEWIP_BYTE_ALIGNMENT_ENABLE == 1)
|
||||
_nip_hdr_encap_udp_bitmap(head);
|
||||
#else
|
||||
head->hdr_buf[0] = NIP_UDP_BITMAP_1;
|
||||
head->hdr_buf_pos = 1;
|
||||
#endif
|
||||
|
||||
/* Encapsulate bitmap fields into newIP packet header BUF */
|
||||
_nip_hdr_ttl_encap(head);
|
||||
_nip_hdr_nexthdr_encap(head);
|
||||
_nip_hdr_daddr_encap(head);
|
||||
_nip_hdr_saddr_encap(head);
|
||||
}
|
||||
|
||||
/* need update total len after this func, call nip_update_total_len */
|
||||
void nip_hdr_comm_encap(struct nip_hdr_encap *head)
|
||||
{
|
||||
/* Encapsulate the bitmap into the newIP packet header BUF */
|
||||
#if (NEWIP_BYTE_ALIGNMENT_ENABLE == 1)
|
||||
_nip_hdr_encap_comm_bitmap(head);
|
||||
#else
|
||||
head->hdr_buf[0] = NIP_NORMAL_BITMAP_1;
|
||||
head->hdr_buf_pos = 1;
|
||||
#endif
|
||||
|
||||
/* Encapsulate bitmap fields into newIP packet header BUF */
|
||||
_nip_hdr_ttl_encap(head);
|
||||
_nip_hdr_total_len_encap(head); /* ARP/TCP need include hdr total len */
|
||||
_nip_hdr_nexthdr_encap(head);
|
||||
_nip_hdr_daddr_encap(head);
|
||||
_nip_hdr_saddr_encap(head);
|
||||
}
|
||||
|
||||
#if (NEWIP_BYTE_ALIGNMENT_ENABLE == 1) // include bitmap2
|
||||
#define NIP_COMM_HDR_LEN_NOINCLUDE_ADDR 6 // include total len
|
||||
#define NIP_UDP_HDR_LEN_NOINCLUDE_ADDR 4 // not include total len
|
||||
#else
|
||||
#define NIP_COMM_HDR_LEN_NOINCLUDE_ADDR 5 // include total len
|
||||
#define NIP_UDP_HDR_LEN_NOINCLUDE_ADDR 3 // not include total len
|
||||
#endif
|
||||
/* bitmap1 + bitmap2 + TTL + total len + nexthd + daddr + saddr
|
||||
* 1B 1B 1B 2B 1B 7B 7B = 20B
|
||||
* NIP_HDR_MAX 20
|
||||
* V4 TCP 1448
|
||||
* NIP TCP 1430 + 30 = 1460
|
||||
*/
|
||||
/* The length of the packet header is obtained according to the packet type,
|
||||
* source ADDRESS, and destination address.
|
||||
* If the packet does not carry the source address or destination address, fill in the blank
|
||||
*/
|
||||
int get_nip_hdr_len(enum NIP_HDR_TYPE hdr_type,
|
||||
const struct nip_addr *saddr,
|
||||
const struct nip_addr *daddr)
|
||||
{
|
||||
int saddr_len = 0;
|
||||
int daddr_len = 0;
|
||||
enum NIP_HDR_TYPE base_len = hdr_type == NIP_HDR_UDP ?
|
||||
NIP_UDP_HDR_LEN_NOINCLUDE_ADDR :
|
||||
NIP_COMM_HDR_LEN_NOINCLUDE_ADDR;
|
||||
|
||||
if (hdr_type >= NIP_HDR_TYPE_MAX)
|
||||
return 0;
|
||||
|
||||
if (saddr) {
|
||||
saddr_len = get_nip_addr_len(saddr);
|
||||
if (saddr_len == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (daddr) {
|
||||
daddr_len = get_nip_addr_len(daddr);
|
||||
if (daddr_len == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return base_len + saddr_len + daddr_len;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# enable btdev:
|
||||
# kernel/linux/linux-5.10/drivers/net/Makefile add obj-y += bt/
|
||||
obj-y += btdev.o
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,252 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _BTDEV_H_
|
||||
#define _BTDEV_H_
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
/* must include btdev_user.h first before any macro definition */
|
||||
#include "btdev_user.h"
|
||||
|
||||
#define OK 0
|
||||
#define DELAY_100_MS 100
|
||||
#define MACADDR_LEN (2 * ETH_ALEN)
|
||||
|
||||
#define BT_DEV_MAJOR 125
|
||||
#define BT_DEV_MINOR 0
|
||||
#define BT_RING_BUFFER_SIZE 4096
|
||||
#define STRTOLL_BASE 10
|
||||
#define BT_DEV_ID_OFFSET (sizeof(BT_DEV_PATH_PREFIX) - 1)
|
||||
#define BT_STATISTIC_KTIME_MAX ULONG_MAX
|
||||
|
||||
/**
|
||||
* for debug
|
||||
*/
|
||||
#define DEBUG
|
||||
|
||||
/**
|
||||
* ring buffer
|
||||
*/
|
||||
struct bt_ring {
|
||||
u32 head;
|
||||
u32 tail;
|
||||
u32 size;
|
||||
void **data;
|
||||
};
|
||||
|
||||
/**
|
||||
* one char device
|
||||
*/
|
||||
struct bt_cdev {
|
||||
struct cdev *cdev;
|
||||
struct class *bt_class;
|
||||
char dev_filename[BT_PATHNAME_MAX];
|
||||
};
|
||||
|
||||
struct bt_mng_file {
|
||||
struct bt_cdev *bt_cdev;
|
||||
atomic_t open_limit;
|
||||
};
|
||||
|
||||
struct bt_io_file {
|
||||
struct bt_cdev *bt_cdev;
|
||||
atomic_t read_open_limit;
|
||||
atomic_t write_open_limit;
|
||||
};
|
||||
|
||||
/**
|
||||
* virnet list
|
||||
*/
|
||||
struct bt_table {
|
||||
struct list_head head;
|
||||
struct mutex tbl_lock; // lock for table
|
||||
u32 num;
|
||||
};
|
||||
|
||||
/**
|
||||
* bt virnet state
|
||||
*/
|
||||
enum bt_virnet_state {
|
||||
BT_VIRNET_STATE_CREATED,
|
||||
BT_VIRNET_STATE_CONNECTED,
|
||||
BT_VIRNET_STATE_DISCONNECTED,
|
||||
BT_VIRNET_STATE_DISABLED,
|
||||
BT_VIRNET_STATE_DELETED,
|
||||
BT_VIRNET_STAET_NUM
|
||||
};
|
||||
|
||||
/**
|
||||
* one virnet device
|
||||
*/
|
||||
struct bt_virnet {
|
||||
struct bt_ring *tx_ring;
|
||||
struct bt_io_file *io_file;
|
||||
struct net_device *ndev;
|
||||
struct list_head virnet_entry;
|
||||
struct bt_table *bt_table_head;
|
||||
enum bt_virnet_state state;
|
||||
struct semaphore sem;
|
||||
wait_queue_head_t rx_queue, tx_queue;
|
||||
};
|
||||
|
||||
/**
|
||||
* instance of the module
|
||||
*/
|
||||
struct bt_drv {
|
||||
struct bt_table *devices_table;
|
||||
struct bt_mng_file *mng_file;
|
||||
struct bt_io_file **io_files;
|
||||
u32 bitmap;
|
||||
struct mutex bitmap_lock; // lock for bitmap
|
||||
struct class *bt_class;
|
||||
};
|
||||
|
||||
/**
|
||||
* state to string
|
||||
*/
|
||||
static const char *bt_virnet_state_rep[BT_VIRNET_STAET_NUM] = {
|
||||
"CREATED",
|
||||
"CONNECTED",
|
||||
"DISCONNECTED",
|
||||
"DISABLED",
|
||||
"ENABLED"};
|
||||
|
||||
/**
|
||||
* inline functions
|
||||
*/
|
||||
static inline int bt_get_unused_id(const u32 *bitmap)
|
||||
{
|
||||
int i;
|
||||
|
||||
WARN_ON(!bitmap);
|
||||
for (i = 0; i < BT_VIRNET_MAX_NUM + 1; ++i) {
|
||||
if (!(*bitmap & (1 << i)))
|
||||
return i;
|
||||
}
|
||||
return -1; // all used
|
||||
}
|
||||
|
||||
static inline void bt_set_bit(u32 *bitmap, u32 idx)
|
||||
{
|
||||
WARN_ON(!bitmap);
|
||||
*bitmap |= (1 << idx);
|
||||
}
|
||||
|
||||
static inline void bt_clear_bit(u32 *bitmap, u32 idx)
|
||||
{
|
||||
WARN_ON(!bitmap);
|
||||
*bitmap &= ~(1 << idx);
|
||||
}
|
||||
|
||||
#define SET_STATE(vn, st) bt_virnet_set_state(vn, st)
|
||||
static inline void bt_virnet_set_state(struct bt_virnet *vn,
|
||||
enum bt_virnet_state state)
|
||||
{
|
||||
WARN_ON(!vn);
|
||||
vn->state = state;
|
||||
}
|
||||
|
||||
static inline const struct cdev *bt_virnet_get_cdev(const struct bt_virnet *vn)
|
||||
{
|
||||
WARN_ON(!vn);
|
||||
return vn->io_file->bt_cdev->cdev;
|
||||
}
|
||||
|
||||
static inline const dev_t bt_virnet_get_cdev_number(const struct bt_virnet *vn)
|
||||
{
|
||||
WARN_ON(!vn);
|
||||
return vn->io_file->bt_cdev->cdev->dev;
|
||||
}
|
||||
|
||||
static inline const char *bt_virnet_get_cdev_name(const struct bt_virnet *vn)
|
||||
{
|
||||
WARN_ON(!vn);
|
||||
return vn->io_file->bt_cdev->dev_filename;
|
||||
}
|
||||
|
||||
static inline struct net_device *bt_virnet_get_ndev(const struct bt_virnet *vn)
|
||||
{
|
||||
WARN_ON(!vn);
|
||||
return vn->ndev;
|
||||
}
|
||||
|
||||
static inline const char *bt_virnet_get_ndev_name(const struct bt_virnet *vn)
|
||||
{
|
||||
WARN_ON(!vn);
|
||||
return vn->ndev->name;
|
||||
}
|
||||
|
||||
static inline const char *bt_virnet_get_state_rep(const struct bt_virnet *vn)
|
||||
{
|
||||
WARN_ON(!vn);
|
||||
return bt_virnet_state_rep[vn->state];
|
||||
}
|
||||
|
||||
static inline int bt_get_total_device(const struct bt_drv *bt_drv)
|
||||
{
|
||||
WARN_ON(!bt_drv);
|
||||
return bt_drv->devices_table->num;
|
||||
}
|
||||
|
||||
static inline int bt_virnet_get_ring_packets(const struct bt_virnet *vn)
|
||||
{
|
||||
int packets = 0;
|
||||
|
||||
WARN_ON(!vn);
|
||||
packets = vn->tx_ring->head - vn->tx_ring->tail;
|
||||
if (unlikely(packets < 0))
|
||||
packets += BT_RING_BUFFER_SIZE;
|
||||
|
||||
return packets;
|
||||
}
|
||||
|
||||
static struct bt_table *bt_table_init(void);
|
||||
static int bt_table_add_device(struct bt_table *tbl, struct bt_virnet *vn);
|
||||
static void bt_table_remove_device(struct bt_table *tbl, struct bt_virnet *vn);
|
||||
static void bt_table_delete_all(struct bt_drv *bt_drv);
|
||||
static struct bt_virnet *bt_table_find(struct bt_table *tbl, const char *ifa_name);
|
||||
static void bt_table_destroy(struct bt_drv *bt_drv);
|
||||
static void bt_delete_io_files(struct bt_drv *bt_mng);
|
||||
static struct bt_io_file **bt_create_io_files(void);
|
||||
|
||||
static struct bt_ring *bt_ring_create(void);
|
||||
static int bt_ring_is_empty(const struct bt_ring *ring);
|
||||
static int bt_ring_is_full(const struct bt_ring *ring);
|
||||
static void *bt_ring_current(struct bt_ring *ring);
|
||||
static void bt_ring_produce(struct bt_ring *ring, void *data);
|
||||
static void bt_ring_consume(struct bt_ring *ring);
|
||||
static void bt_ring_destroy(struct bt_ring *ring);
|
||||
|
||||
static int bt_virnet_produce_data(struct bt_virnet *dev, void *data);
|
||||
static struct bt_virnet *bt_virnet_create(struct bt_drv *bt_mng, u32 id);
|
||||
static void bt_virnet_destroy(struct bt_virnet *vnet);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _BTDEV_USER_H_
|
||||
#define _BTDEV_USER_H_
|
||||
|
||||
#include <linux/if.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#define BT_VIRNET_NAME_PREFIX "btn"
|
||||
#define BT_DEV_NAME_PREFIX "btdev"
|
||||
#define BT_DEV_PATH_PREFIX "/dev/" BT_DEV_NAME_PREFIX
|
||||
|
||||
#define BT_DEV_PATH(idx) (BT_DEV_PATH_PREFIX#idx)
|
||||
#define BT_DEV_NAME(idx) (BT_DEV_NAME_PREFIX#idx)
|
||||
|
||||
#define BT_DEV_NAME_MNG_FILE BT_DEV_NAME(0)
|
||||
#define BT_DEV_PATH_MNG_FILE BT_DEV_PATH(0)
|
||||
#define BT_DEV_NAME_IO_FILE(idx) BT_DEV_NAME(idx)
|
||||
#define BT_DEV_PATH_IO_FILE(idx) BT_DEV_PATH(idx)
|
||||
#define BT_VIRNET_NAME(idx) (BT_VIRNET_NAME_PREFIX#idx)
|
||||
|
||||
#define BT_PATHNAME_MAX 256
|
||||
#define BT_VIRNET_MAX_NUM 16
|
||||
#define BT_VIRNET_DATA_HEAD_LEN 2
|
||||
|
||||
/**
|
||||
* ioctl cmd
|
||||
*/
|
||||
#define BT_IOC_CREATE _IO('b', 1)
|
||||
#define BT_IOC_DELETE _IO('b', 2)
|
||||
#define BT_IOC_CHANGE_MTU _IO('b', 3)
|
||||
#define BT_IOC_QUERY_ALL _IO('b', 4)
|
||||
#define BT_IOC_DELETE_ALL _IO('b', 5)
|
||||
#define BT_IOC_ENABLE _IO('b', 6)
|
||||
#define BT_IOC_DISABLE _IO('b', 7)
|
||||
#define BT_IOC_PEEK_PACKET _IO('b', 8)
|
||||
|
||||
/**
|
||||
* user space ioctl arguments
|
||||
*/
|
||||
struct bt_uioc_args {
|
||||
char ifa_name[IFNAMSIZ];
|
||||
char cfile_name[BT_PATHNAME_MAX];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Linux NewIP INET implementation
|
||||
*
|
||||
* Based on include/uapi/linux/ipv6_route.h
|
||||
*
|
||||
* 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_NEWIP_ROUTE_H
|
||||
#define _LINUX_NEWIP_ROUTE_H
|
||||
|
||||
#include <uapi/linux/newip_route.h>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Based on include/linux/ipv6.h
|
||||
* Based on include/net/sock.h
|
||||
*/
|
||||
#ifndef _NIP_H
|
||||
#define _NIP_H
|
||||
|
||||
#include <uapi/linux/nip.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define ETH_P_NEWIP 0xEADD /* NIP */
|
||||
|
||||
/* struct sock_common __sk_common */
|
||||
#define sk_nip_daddr __sk_common.nip_daddr
|
||||
#define sk_nip_rcv_saddr __sk_common.nip_rcv_saddr
|
||||
|
||||
/* struct request_sock req */
|
||||
#define ir_nip_rmt_addr req.__req_common.nip_daddr
|
||||
#define ir_nip_loc_addr req.__req_common.nip_rcv_saddr
|
||||
|
||||
struct nip_devconf {
|
||||
__s32 forwarding;
|
||||
__s32 mtu;
|
||||
__s32 ignore_routes_with_linkdown;
|
||||
|
||||
__s32 disable_nip;
|
||||
__s32 nndisc_notify;
|
||||
__s32 use_oif_addrs_only;
|
||||
__s32 keep_addr_on_down;
|
||||
|
||||
struct ctl_table_header *sysctl_header;
|
||||
};
|
||||
|
||||
/* This structure contains results of exthdrs parsing
|
||||
* The common CB structure: struct sk_buff->char cb[48]
|
||||
* TCP CB structure : struct tcp_skb_cb
|
||||
* struct tcp_skb_cb->header is union, include IPv4/IPv6/NewIP xx_skb_parm, max size is 24
|
||||
* sizeof(struct ninet_skb_parm)=19
|
||||
* sizeof(struct inet_skb_parm)=24
|
||||
* sizeof(struct inet6_skb_parm)=20
|
||||
* sizeof(struct tcp_skb_cb->exclude skb_parm)=24 |__ total size is 48, struct sk_buff->char cb[48]
|
||||
* sizeof(struct tcp_skb_cb->include skb_parm)=24 |
|
||||
*/
|
||||
#pragma pack(1)
|
||||
struct ninet_skb_parm {
|
||||
struct nip_addr dstaddr;
|
||||
struct nip_addr srcaddr;
|
||||
u8 nexthdr;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
struct tcp_nip_common {
|
||||
u32 ack_retrans_num;
|
||||
u32 ack_retrans_seq;
|
||||
u32 nip_ssthresh;
|
||||
u32 nip_ssthresh_reset;
|
||||
bool nip_keepalive_enable;
|
||||
u32 idle_ka_probes_out;
|
||||
u32 nip_keepalive_out;
|
||||
u32 last_rcv_nxt;
|
||||
u32 dup_ack_cnt;
|
||||
u32 keepalive_time_bak;
|
||||
u32 keepalive_probes_bak;
|
||||
u32 keepalive_intvl_bak;
|
||||
};
|
||||
|
||||
struct tcp_nip_request_sock {
|
||||
struct tcp_request_sock tcp_nip_rsk_tcp;
|
||||
struct tcp_nip_common common;
|
||||
};
|
||||
|
||||
struct nip_udp_sock {
|
||||
struct udp_sock udp;
|
||||
};
|
||||
|
||||
struct tcp_nip_sock {
|
||||
struct tcp_sock tcp;
|
||||
struct tcp_nip_common common;
|
||||
};
|
||||
|
||||
#endif /* _NIP_H */
|
||||
@@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Definitions for the NewIP ICMP protocol.
|
||||
*
|
||||
* Based on include/linux/icmp.h
|
||||
*/
|
||||
#ifndef _LINUX_NIP_ICMP_H
|
||||
#define _LINUX_NIP_ICMP_H
|
||||
|
||||
#include <uapi/linux/nip_icmp.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
static inline struct nip_icmp_hdr *nip_icmp_header(const struct sk_buff *skb)
|
||||
{
|
||||
return (struct nip_icmp_hdr *)skb_transport_header(skb);
|
||||
}
|
||||
|
||||
int nip_icmp_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP Generic internet FLOW.
|
||||
*
|
||||
* Based on include/net/flow.h
|
||||
*/
|
||||
#ifndef _NET_FLOW_NIP_H
|
||||
#define _NET_FLOW_NIP_H
|
||||
|
||||
#include <net/flow.h>
|
||||
|
||||
struct flow_nip {
|
||||
struct flowi_common __fl_common;
|
||||
#define flowin_oif __fl_common.flowic_oif
|
||||
#define flowin_iif __fl_common.flowic_iif
|
||||
struct nip_addr daddr;
|
||||
struct nip_addr saddr;
|
||||
union flowi_uli uli;
|
||||
#define fln_sport uli.ports.sport
|
||||
#define fln_dport uli.ports.dport
|
||||
} __attribute__((__aligned__(BITS_PER_LONG / 8)));
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP inet interface/address list definitions
|
||||
* Linux NewIP INET implementation
|
||||
*
|
||||
* Based on include/net/if_inet6.h
|
||||
*/
|
||||
#ifndef _NET_IF_NINET_H
|
||||
#define _NET_IF_NINET_H
|
||||
|
||||
#include <linux/nip.h>
|
||||
|
||||
enum {
|
||||
NINET_IFADDR_STATE_NEW,
|
||||
NINET_IFADDR_STATE_DEAD,
|
||||
};
|
||||
|
||||
struct ninet_ifaddr {
|
||||
struct nip_addr addr;
|
||||
|
||||
/* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */
|
||||
__u32 valid_lft;
|
||||
__u32 preferred_lft;
|
||||
refcount_t refcnt;
|
||||
|
||||
/* protect one ifaddr itself */
|
||||
spinlock_t lock;
|
||||
|
||||
int state;
|
||||
|
||||
__u32 flags;
|
||||
|
||||
unsigned long cstamp; /* created timestamp */
|
||||
unsigned long tstamp; /* updated timestamp */
|
||||
|
||||
struct ninet_dev *idev;
|
||||
struct nip_rt_info *rt;
|
||||
|
||||
struct hlist_node addr_lst;
|
||||
struct list_head if_list;
|
||||
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
struct ninet_dev {
|
||||
struct net_device *dev;
|
||||
|
||||
struct list_head addr_list;
|
||||
|
||||
rwlock_t lock;
|
||||
refcount_t refcnt;
|
||||
__u32 if_flags;
|
||||
int dead;
|
||||
|
||||
struct neigh_parms *nd_parms;
|
||||
struct nip_devconf cnf;
|
||||
|
||||
unsigned long tstamp; /* newip InterfaceTable update timestamp */
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
int ninet_gifconf(struct net_device *dev, char __user *buf, int len, int size);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP in net namespaces
|
||||
*
|
||||
* Based on include/net/netns/ipv6.h
|
||||
*/
|
||||
#ifndef __NETNS_NEWIP_H__
|
||||
#define __NETNS_NEWIP_H__
|
||||
|
||||
#include <net/inet_frag.h>
|
||||
#include <net/dst_ops.h>
|
||||
|
||||
struct ctl_table_header;
|
||||
|
||||
struct netns_sysctl_newip {
|
||||
int nip_rt_gc_interval;
|
||||
};
|
||||
struct netns_newip {
|
||||
uint32_t resv;
|
||||
struct netns_sysctl_newip sysctl;
|
||||
struct nip_devconf *devconf_dflt;
|
||||
|
||||
struct nip_rt_info *nip_null_entry;
|
||||
struct nip_rt_info *nip_broadcast_entry;
|
||||
|
||||
struct dst_ops nip_dst_ops;
|
||||
struct nip_fib_table *nip_fib_main_tbl;
|
||||
struct nip_fib_table *nip_fib_local_tbl;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP NET
|
||||
* Generic infrastructure for NewIP INET connection oriented protocols.
|
||||
*
|
||||
* Based on include/net/inet_connection_sock.h
|
||||
*/
|
||||
#ifndef _NINET_CONNECTION_SOCK_H
|
||||
#define _NINET_CONNECTION_SOCK_H
|
||||
|
||||
#include <net/inet_sock.h>
|
||||
#include <net/request_sock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct inet_bind_bucket;
|
||||
struct request_sock;
|
||||
struct sk_buff;
|
||||
struct sock;
|
||||
struct sockaddr;
|
||||
|
||||
int ninet_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl);
|
||||
void ninet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
|
||||
unsigned long timeout);
|
||||
|
||||
#endif /* _NINET_CONNECTION_SOCK_H */
|
||||
@@ -0,0 +1,121 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Based on include/net/inet6_hashtables.h
|
||||
*/
|
||||
#ifndef NINET_HASHTABLES_H
|
||||
#define NINET_HASHTABLES_H
|
||||
|
||||
#if IS_ENABLED(CONFIG_NEWIP)
|
||||
#include <linux/nip.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/jhash.h>
|
||||
|
||||
#include <net/inet_sock.h>
|
||||
|
||||
#include <net/nip.h>
|
||||
#include <net/netns/hash.h>
|
||||
|
||||
struct inet_hashinfo;
|
||||
|
||||
int ninet_hash(struct sock *sk);
|
||||
void ninet_unhash(struct sock *sk);
|
||||
int ninet_hash_connect(struct inet_timewait_death_row *death_row,
|
||||
struct sock *sk);
|
||||
|
||||
int __ninet_hash(struct sock *sk, struct sock *osk);
|
||||
|
||||
|
||||
static inline unsigned int __ninet_ehashfn(const u32 lhash,
|
||||
const u16 lport,
|
||||
const u32 fhash,
|
||||
const __be16 fport,
|
||||
const u32 initval)
|
||||
{
|
||||
const u32 ports = (((u32) lport) << 16) | (__force u32) fport;
|
||||
|
||||
return jhash_3words(lhash, fhash, ports, initval);
|
||||
}
|
||||
|
||||
struct sock *__ninet_lookup_established(struct net *net,
|
||||
struct inet_hashinfo *hashinfo,
|
||||
const struct nip_addr *saddr,
|
||||
const __be16 sport,
|
||||
const struct nip_addr *daddr,
|
||||
const u16 hnum, const int dif);
|
||||
|
||||
struct sock *ninet_lookup_listener(struct net *net,
|
||||
struct inet_hashinfo *hashinfo,
|
||||
struct sk_buff *skb, int doff,
|
||||
const struct nip_addr *saddr,
|
||||
const __be16 sport,
|
||||
const struct nip_addr *daddr,
|
||||
const unsigned short hnum, const int dif, const int sdif);
|
||||
|
||||
static inline struct sock *__ninet_lookup(struct net *net,
|
||||
struct inet_hashinfo *hashinfo,
|
||||
struct sk_buff *skb, int doff,
|
||||
const struct nip_addr *saddr,
|
||||
const __be16 sport,
|
||||
const struct nip_addr *daddr,
|
||||
const u16 hnum,
|
||||
const int dif, bool *refcounted)
|
||||
{
|
||||
struct sock *sk = __ninet_lookup_established(net, hashinfo, saddr,
|
||||
sport, daddr, hnum, dif);
|
||||
*refcounted = true;
|
||||
if (sk)
|
||||
return sk;
|
||||
*refcounted = false;
|
||||
return ninet_lookup_listener(net, hashinfo, skb, doff, saddr, sport,
|
||||
daddr, hnum, dif, 0);
|
||||
}
|
||||
|
||||
static inline struct sock *__ninet_lookup_skb(struct inet_hashinfo *hashinfo,
|
||||
struct sk_buff *skb, int doff,
|
||||
const __be16 sport,
|
||||
const __be16 dport,
|
||||
int iif, bool *refcounted)
|
||||
{
|
||||
struct sock *sk;
|
||||
|
||||
*refcounted = true;
|
||||
sk = skb_steal_sock(skb, refcounted);
|
||||
if (sk)
|
||||
return sk;
|
||||
|
||||
return __ninet_lookup(dev_net(skb->dev), hashinfo, skb,
|
||||
doff, &(NIPCB(skb)->srcaddr), sport,
|
||||
&(NIPCB(skb)->dstaddr), ntohs(dport),
|
||||
iif, refcounted);
|
||||
}
|
||||
|
||||
#define NINET_MATCH(__sk, __net, __saddr, __daddr, __ports, __dif) \
|
||||
(((__sk)->sk_portpair == (__ports)) && \
|
||||
((__sk)->sk_family == AF_NINET) && \
|
||||
nip_addr_eq(&(__sk)->sk_nip_daddr, (__saddr)) && \
|
||||
nip_addr_eq(&(__sk)->sk_nip_rcv_saddr, (__daddr)) && \
|
||||
(!(__sk)->sk_bound_dev_if || \
|
||||
((__sk)->sk_bound_dev_if == (__dif))) && \
|
||||
net_eq(sock_net(__sk), (__net)))
|
||||
|
||||
int ninet_hash_connect(struct inet_timewait_death_row *death_row,
|
||||
struct sock *sk);
|
||||
|
||||
u64 secure_newip_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
|
||||
__be16 dport);
|
||||
__u32 secure_tcp_nip_sequence_number(const __be32 *saddr, const __be32 *daddr,
|
||||
__be16 sport, __be16 dport);
|
||||
|
||||
u32 ninet_ehashfn(const struct net *net,
|
||||
const struct nip_addr *laddr, const u16 lport,
|
||||
const struct nip_addr *faddr, const __be16 fport);
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_NEWIP) */
|
||||
#endif /* _NINET_HASHTABLES_H */
|
||||
@@ -0,0 +1,128 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Definitions for the NewIP module.
|
||||
*
|
||||
* Based on include/net/ip.h
|
||||
* Based on include/net/protocol.h
|
||||
*/
|
||||
#ifndef _NET_NEWIP_H
|
||||
#define _NET_NEWIP_H
|
||||
|
||||
#include <net/dst.h>
|
||||
#include <net/protocol.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/nip.h>
|
||||
|
||||
#include <net/tcp.h>
|
||||
#include <uapi/linux/nip_addr.h>
|
||||
#include "if_ninet.h"
|
||||
#include "flow_nip.h"
|
||||
|
||||
#define NIP_MAX_SOCKET_NUM 1024
|
||||
|
||||
struct ninet_protocol {
|
||||
void (*early_demux)(struct sk_buff *skb);
|
||||
|
||||
int (*handler)(struct sk_buff *skb);
|
||||
|
||||
void (*err_handler)(struct sk_buff *skb,
|
||||
struct ninet_skb_parm *opt,
|
||||
u8 type, u8 code, int offset, __be32 info);
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
#define NIPCB(skb) ((struct ninet_skb_parm *)&(TCP_SKB_CB(skb)->header.hnip))
|
||||
|
||||
extern const struct ninet_protocol __rcu *ninet_protos[MAX_INET_PROTOS];
|
||||
extern const struct proto_ops ninet_dgram_ops;
|
||||
extern const struct proto_ops ninet_stream_ops;
|
||||
extern struct neigh_table nnd_tbl;
|
||||
|
||||
int tcp_nip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl);
|
||||
void tcp_nip_actual_send_reset(struct sock *sk, struct sk_buff *skb, u32 seq,
|
||||
u32 ack_seq, u32 win, int rst, u32 priority);
|
||||
int nip_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev);
|
||||
struct nip_rt_info *nip_dst_alloc(struct net *net, struct net_device *dev,
|
||||
int flags);
|
||||
|
||||
static inline bool nip_addr_and_ifindex_eq(const struct nip_addr *a1,
|
||||
const struct nip_addr *a2, int ifindex1, int ifindex2)
|
||||
{
|
||||
return (a1->bitlen == a2->bitlen) && (a1->bitlen <= NIP_ADDR_BIT_LEN_MAX) &&
|
||||
(memcmp(&a1->v.u, &a2->v.u, a1->bitlen >> 3) == 0) && (ifindex1 == ifindex2);
|
||||
};
|
||||
|
||||
static inline bool nip_addr_eq(const struct nip_addr *a1,
|
||||
const struct nip_addr *a2)
|
||||
{
|
||||
return (a1->bitlen == a2->bitlen) && (a1->bitlen <= NIP_ADDR_BIT_LEN_MAX) &&
|
||||
(memcmp(&a1->v.u, &a2->v.u, a1->bitlen >> 3) == 0);
|
||||
};
|
||||
|
||||
static inline u32 nip_addr_hash(const struct nip_addr *a)
|
||||
{
|
||||
u32 tmp[4];
|
||||
u8 len = a->bitlen >> 3;
|
||||
|
||||
/* set unused bit to 0 */
|
||||
memset(tmp, 0, NIP_ADDR_BIT_LEN_16);
|
||||
memcpy(tmp, &a->v.u,
|
||||
len > NIP_ADDR_BIT_LEN_16 ? NIP_ADDR_BIT_LEN_16 : len);
|
||||
|
||||
return (__force u32)(tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3]);
|
||||
}
|
||||
|
||||
int nip_send_skb(struct sk_buff *skb);
|
||||
|
||||
void ninet_destroy_sock(struct sock *sk);
|
||||
int nip_datagram_dst_update(struct sock *sk, bool fix_sk_saddr);
|
||||
int ninet_add_protocol(const struct ninet_protocol *prot, unsigned char protocol);
|
||||
int ninet_del_protocol(const struct ninet_protocol *prot, unsigned char protocol);
|
||||
int ninet_register_protosw(struct inet_protosw *p);
|
||||
void ninet_unregister_protosw(struct inet_protosw *p);
|
||||
int nip_input(struct sk_buff *skb);
|
||||
int nip_output(struct net *net, struct sock *sk, struct sk_buff *skb);
|
||||
int nip_forward(struct sk_buff *skb);
|
||||
|
||||
unsigned int tcp_nip_sync_mss(struct sock *sk, u32 pmtu);
|
||||
unsigned int tcp_nip_current_mss(struct sock *sk);
|
||||
int tcp_nip_send_mss(struct sock *sk, int *size_goal, int flags);
|
||||
|
||||
struct nip_addr *nip_nexthop(struct nip_rt_info *rt, struct nip_addr *daddr);
|
||||
struct dst_entry *nip_sk_dst_lookup_flow(struct sock *sk, struct flow_nip *fln);
|
||||
struct dst_entry *nip_dst_lookup_flow(struct net *net, const struct sock *sk,
|
||||
struct flow_nip *fln,
|
||||
const struct nip_addr *final_dst);
|
||||
u_char *nip_get_mac(struct nip_addr *nipaddr, struct net_device *dev);
|
||||
struct net_device *nip_get_defaultdev(void);
|
||||
int nip_init_dev(void);
|
||||
|
||||
int _nip_udp_output(struct sock *sk, void *from, int datalen,
|
||||
int transhdrlen, const struct nip_addr *saddr,
|
||||
ushort sport, const struct nip_addr *daddr,
|
||||
ushort dport, struct dst_entry *dst);
|
||||
|
||||
/* functions defined in nip_sockglue.c */
|
||||
int nip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
|
||||
unsigned int optlen);
|
||||
int nip_getsockopt(struct sock *sk, int level,
|
||||
int optname, char __user *optval, int __user *optlen);
|
||||
|
||||
/* functions defined in nip_addrconf.c */
|
||||
int nip_addrconf_get_ifaddr(struct net *net, unsigned int cmd, void __user *arg);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,115 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Based on include/net/addrconf.h
|
||||
*/
|
||||
#ifndef _NIP_ADDRCONF_H
|
||||
#define _NIP_ADDRCONF_H
|
||||
|
||||
#include <net/if_ninet.h>
|
||||
#include <net/nip.h>
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#define ADDRCONF_NOTIFY_PRIORITY 0
|
||||
#define NIN_ADDR_HSIZE_SHIFT (4)
|
||||
#define NIN_ADDR_HSIZE (1 << NIN_ADDR_HSIZE_SHIFT)
|
||||
|
||||
#define DST_HOST 0x0001 /* NIP */
|
||||
|
||||
int nip_addrconf_add_ifaddr(struct net *net, void __user *arg);
|
||||
int nip_addrconf_del_ifaddr(struct net *net, void __user *arg);
|
||||
|
||||
int nip_dev_get_saddr(struct net *net, const struct net_device *dev,
|
||||
const struct nip_addr *daddr, struct nip_addr *saddr);
|
||||
|
||||
int nip_addrconf_init(void);
|
||||
void nip_addrconf_cleanup(void);
|
||||
void nip_addr_to_str(const struct nip_addr *addr, unsigned char *buf, int buf_len);
|
||||
|
||||
/**
|
||||
* __nin_dev_get - get ninet_dev pointer from netdevice
|
||||
* @dev: network device
|
||||
*
|
||||
* Caller must hold rcu_read_lock or RTNL, because this function
|
||||
* does not take a reference on the ninet_dev.
|
||||
*/
|
||||
static inline struct ninet_dev *__nin_dev_get(const struct net_device *dev)
|
||||
{
|
||||
return rcu_dereference_rtnl(dev->nip_ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* nin_dev_get - get ninet_dev pointer from netdevice
|
||||
* @dev: network device
|
||||
*/
|
||||
static inline struct ninet_dev *nin_dev_get(const struct net_device *dev)
|
||||
{
|
||||
struct ninet_dev *idev;
|
||||
|
||||
rcu_read_lock();
|
||||
idev = rcu_dereference(dev->nip_ptr);
|
||||
if (idev)
|
||||
refcount_inc(&idev->refcnt);
|
||||
rcu_read_unlock();
|
||||
return idev;
|
||||
}
|
||||
|
||||
static inline struct neigh_parms *__nin_dev_nd_parms_get_rcu(
|
||||
const struct net_device *dev)
|
||||
{
|
||||
struct ninet_dev *idev = __nin_dev_get(dev);
|
||||
|
||||
return idev ? idev->nd_parms : NULL;
|
||||
}
|
||||
|
||||
void nin_dev_finish_destroy(struct ninet_dev *idev);
|
||||
|
||||
static inline void nin_dev_put(struct ninet_dev *idev)
|
||||
{
|
||||
if (refcount_dec_and_test(&idev->refcnt))
|
||||
nin_dev_finish_destroy(idev);
|
||||
}
|
||||
|
||||
static inline void nin_dev_put_clear(struct ninet_dev **pidev)
|
||||
{
|
||||
struct ninet_dev *idev = *pidev;
|
||||
|
||||
if (idev) {
|
||||
nin_dev_put(idev);
|
||||
*pidev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __nin_dev_put(struct ninet_dev *idev)
|
||||
{
|
||||
refcount_dec(&idev->refcnt);
|
||||
}
|
||||
|
||||
static inline void nin_dev_hold(struct ninet_dev *idev)
|
||||
{
|
||||
refcount_inc(&idev->refcnt);
|
||||
}
|
||||
|
||||
void ninet_ifa_finish_destroy(struct ninet_ifaddr *ifp);
|
||||
|
||||
static inline void nin_ifa_put(struct ninet_ifaddr *ifp)
|
||||
{
|
||||
if (refcount_dec_and_test(&ifp->refcnt))
|
||||
ninet_ifa_finish_destroy(ifp);
|
||||
}
|
||||
|
||||
static inline void __nin_ifa_put(struct ninet_ifaddr *ifp)
|
||||
{
|
||||
refcount_dec(&ifp->refcnt);
|
||||
}
|
||||
|
||||
static inline void nin_ifa_hold(struct ninet_ifaddr *ifp)
|
||||
{
|
||||
refcount_inc(&ifp->refcnt);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,153 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Linux NewIP INET implementation
|
||||
*
|
||||
* Based on include/net/ip6_fib.h
|
||||
*/
|
||||
#ifndef _NET_NEWIP_FIB_H
|
||||
#define _NET_NEWIP_FIB_H
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <net/inetpeer.h>
|
||||
#include <net/dst.h>
|
||||
#include <linux/ipv6_route.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <linux/newip_route.h>
|
||||
#include "nip.h"
|
||||
#include "flow_nip.h"
|
||||
|
||||
#define NIN_ROUTE_HSIZE_SHIFT 4
|
||||
#define NIN_ROUTE_HSIZE (1 << NIN_ROUTE_HSIZE_SHIFT)
|
||||
|
||||
struct nip_fib_config {
|
||||
u32 fc_table;
|
||||
u32 fc_metric;
|
||||
int fc_ifindex;
|
||||
u32 fc_flags;
|
||||
u32 fc_protocol;
|
||||
u32 fc_type; /* only 8 bits are used */
|
||||
|
||||
struct nip_addr fc_dst;
|
||||
struct nip_addr fc_src;
|
||||
struct nip_addr fc_gateway;
|
||||
|
||||
struct nl_info fc_nlinfo;
|
||||
unsigned long fc_expires;
|
||||
};
|
||||
|
||||
struct nip_fib_node {
|
||||
struct hlist_node fib_hlist;
|
||||
struct nip_rt_info *nip_route_info;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
struct nip_fib_table;
|
||||
|
||||
struct nip_rt_info {
|
||||
struct dst_entry dst;
|
||||
struct dst_entry *from;
|
||||
struct nip_fib_table *rt_table;
|
||||
struct nip_fib_node __rcu *rt_node;
|
||||
struct ninet_dev *rt_idev;
|
||||
struct nip_rt_info *__percpu *rt_pcpu;
|
||||
|
||||
atomic_t rt_ref;
|
||||
|
||||
uint32_t rt_flags;
|
||||
struct nip_addr gateway;
|
||||
struct nip_addr rt_dst;
|
||||
struct nip_addr rt_src;
|
||||
|
||||
u32 rt_metric;
|
||||
u32 rt_pmtu;
|
||||
u8 rt_protocol;
|
||||
};
|
||||
|
||||
static inline struct ninet_dev *nip_dst_idev(struct dst_entry *dst)
|
||||
{
|
||||
return ((struct nip_rt_info *)dst)->rt_idev;
|
||||
}
|
||||
|
||||
struct nip_fib_table {
|
||||
u32 nip_tb_id;
|
||||
spinlock_t nip_tb_lock;
|
||||
struct hlist_head nip_tb_head[NIN_ROUTE_HSIZE];
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
#define NIP_RT_TABLE_MAIN RT_TABLE_MAIN
|
||||
#define NIP_RT_TABLE_LOCAL RT_TABLE_LOCAL
|
||||
|
||||
typedef struct nip_rt_info *(*nip_pol_lookup_t) (struct net *,
|
||||
struct nip_fib_table *,
|
||||
struct flow_nip *, int);
|
||||
|
||||
struct nip_fib_table *nip_fib_get_table(struct net *net, u32 id);
|
||||
|
||||
struct dst_entry *nip_fib_rule_lookup(struct net *net, struct flow_nip *fln,
|
||||
int flags, int *tbl_type, nip_pol_lookup_t lookup);
|
||||
|
||||
#define NIP_RT_EXPIRES_FLAGS 12
|
||||
static inline void nip_rt_set_expires(struct nip_rt_info *rt,
|
||||
unsigned long expires)
|
||||
{
|
||||
rt->dst.expires = expires;
|
||||
|
||||
rt->rt_flags |= NIP_RT_EXPIRES_FLAGS;
|
||||
}
|
||||
|
||||
static inline void nip_rt_clean_expires(struct nip_rt_info *rt)
|
||||
{
|
||||
rt->rt_flags &= ~NIP_RT_EXPIRES_FLAGS;
|
||||
rt->dst.expires = 0;
|
||||
}
|
||||
|
||||
static inline void nip_rt_put(struct nip_rt_info *rt)
|
||||
{
|
||||
BUILD_BUG_ON(offsetof(struct nip_rt_info, dst) != 0);
|
||||
dst_release(&rt->dst);
|
||||
}
|
||||
|
||||
void nip_rt_free_pcpu(struct nip_rt_info *non_pcpu_rt);
|
||||
|
||||
static inline void nip_rt_hold(struct nip_rt_info *rt)
|
||||
{
|
||||
atomic_inc(&rt->rt_ref);
|
||||
}
|
||||
|
||||
static inline void nip_rt_release(struct nip_rt_info *rt)
|
||||
{
|
||||
if (atomic_dec_and_test(&rt->rt_ref)) {
|
||||
nip_rt_free_pcpu(rt);
|
||||
dst_dev_put(&rt->dst);
|
||||
|
||||
dst_release(&rt->dst);
|
||||
}
|
||||
}
|
||||
|
||||
int nip_fib_init(void);
|
||||
|
||||
void nip_fib_gc_cleanup(void);
|
||||
|
||||
struct nip_fib_node *nip_fib_locate(struct hlist_head *nip_tb_head,
|
||||
const struct nip_addr *daddr);
|
||||
|
||||
void nip_fib_clean_all(struct net *net,
|
||||
int (*func)(struct nip_rt_info *, void *arg), void *arg);
|
||||
|
||||
int nip_fib_add(struct nip_fib_table *table, struct nip_rt_info *rt);
|
||||
|
||||
int nip_fib_del(struct nip_rt_info *rt_info, struct nl_info *info);
|
||||
|
||||
int nip_set_route_netlink(struct net *net, struct nip_rtmsg *rtmsg);
|
||||
|
||||
int nip_del_route_netlink(struct net *net, struct nip_rtmsg *rtmsg);
|
||||
|
||||
#endif /* _NET_NEWIP_FIB_H */
|
||||
@@ -0,0 +1,66 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Based on include/net/ip6_route.h
|
||||
*/
|
||||
#ifndef _NET_NIP_ROUTE_H
|
||||
#define _NET_NIP_ROUTE_H
|
||||
|
||||
#include <net/net_namespace.h>
|
||||
#include "nip_fib.h"
|
||||
#include "nip_addrconf.h"
|
||||
|
||||
#define NIP_RT_PRIO_USER 1024
|
||||
|
||||
struct nip_rt_info *nip_addrconf_dst_alloc(struct ninet_dev *idev,
|
||||
const struct nip_addr *addr);
|
||||
|
||||
|
||||
int nip_route_input(struct sk_buff *skb);
|
||||
struct dst_entry *nip_route_input_lookup(struct net *net,
|
||||
struct net_device *dev,
|
||||
struct flow_nip *fln, int flags, int *tbl_type);
|
||||
|
||||
struct dst_entry *nip_route_output_flags(struct net *net, const struct sock *sk,
|
||||
struct flow_nip *fln, int flags);
|
||||
|
||||
|
||||
static inline struct dst_entry *nip_route_output(struct net *net,
|
||||
const struct sock *sk,
|
||||
struct flow_nip *fln)
|
||||
{
|
||||
return nip_route_output_flags(net, sk, fln, 0);
|
||||
}
|
||||
|
||||
struct nip_rt_info *nip_pol_route(struct net *net, struct nip_fib_table *table,
|
||||
int oif, struct flow_nip *fln, int flags);
|
||||
|
||||
bool nip_bind_addr_check(struct net *net,
|
||||
struct nip_addr *addr);
|
||||
|
||||
int nip_ins_rt(struct nip_rt_info *rt);
|
||||
int nip_del_rt(struct nip_rt_info *rt);
|
||||
|
||||
static inline int nip_route_get_saddr(struct net *net, struct nip_rt_info *rt,
|
||||
const struct nip_addr *daddr,
|
||||
struct nip_addr *saddr)
|
||||
{
|
||||
struct ninet_dev *idev =
|
||||
rt ? nip_dst_idev((struct dst_entry *)rt) : NULL;
|
||||
int err = 0;
|
||||
|
||||
err = nip_dev_get_saddr(net, idev ? idev->dev : NULL, daddr, saddr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void nip_rt_ifdown(struct net *net, struct net_device *dev);
|
||||
|
||||
int nip_route_ioctl(struct net *net, unsigned int cmd, struct nip_rtmsg *rtmsg);
|
||||
|
||||
int nip_route_init(void);
|
||||
|
||||
void nip_route_cleanup(void);
|
||||
|
||||
#endif /* _NET_NIP_ROUTE_H */
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Definitions for the NewIP UDP module.
|
||||
*
|
||||
* Based on include/net/udp.h
|
||||
*/
|
||||
#ifndef _NET_NEWIP_UDP_H
|
||||
#define _NET_NEWIP_UDP_H
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#define NIP_UDP_HSLOT_COUNT 10
|
||||
|
||||
int nip_udp_init(void);
|
||||
|
||||
int nip_udp_output(struct sock *sk, struct msghdr *msg, size_t len);
|
||||
|
||||
int nip_udp_input(struct sk_buff *skb);
|
||||
int nip_udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||
int noblock, int flags, int *addr_len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Based on include/net/ndisc.h
|
||||
*/
|
||||
#ifndef _NNDISC_H
|
||||
#define _NNDISC_H
|
||||
|
||||
#include <net/neighbour.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/hash.h>
|
||||
#include <linux/nip_icmp.h>
|
||||
|
||||
#define NEWIP_NEIGH_BUCKET_MAX 8
|
||||
extern struct neigh_table nnd_tbl;
|
||||
|
||||
#define NIP_ARP_NS 0x01 /* ARP request */
|
||||
#define NIP_ARP_NA 0x02 /* ARP response */
|
||||
|
||||
struct nnd_msg {
|
||||
struct nip_icmp_hdr icmph;
|
||||
__u8 data[0];
|
||||
};
|
||||
|
||||
static inline bool neigh_key_eq800(const struct neighbour *n, const void *pkey)
|
||||
{
|
||||
struct nip_addr *a1, *a2;
|
||||
|
||||
a1 = (struct nip_addr *)(pkey);
|
||||
a2 = (struct nip_addr *)(n->primary_key);
|
||||
|
||||
#define RIGHT_POS_3 3
|
||||
return a1->bitlen == a2->bitlen && a1->bitlen <= NIP_ADDR_BIT_LEN_MAX &&
|
||||
memcmp(&a1->v.u, &a2->v.u, a1->bitlen >> RIGHT_POS_3) == 0;
|
||||
}
|
||||
|
||||
static inline u32 nndisc_hashfn(const void *pkey, const struct net_device *dev,
|
||||
__u32 *hash_rnd)
|
||||
{
|
||||
return (*(int *)pkey % NEWIP_NEIGH_BUCKET_MAX);
|
||||
}
|
||||
|
||||
static inline struct neighbour *__nip_neigh_lookup_noref(struct net_device *dev,
|
||||
const void *pkey)
|
||||
{
|
||||
return ___neigh_lookup_noref(&nnd_tbl, neigh_key_eq800, nndisc_hashfn,
|
||||
pkey, dev);
|
||||
}
|
||||
|
||||
static inline struct neighbour *__nip_neigh_lookup(struct net_device *dev,
|
||||
const void *pkey)
|
||||
{
|
||||
struct neighbour *n;
|
||||
|
||||
rcu_read_lock_bh();
|
||||
n = __nip_neigh_lookup_noref(dev, pkey);
|
||||
if (n && !refcount_inc_not_zero(&n->refcnt))
|
||||
n = NULL;
|
||||
rcu_read_unlock_bh();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int nndisc_rcv(struct sk_buff *skb);
|
||||
|
||||
int nndisc_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Definitions for the NewIP TCP module.
|
||||
*
|
||||
* Based on include/net/tcp.h
|
||||
* Based on include/linux/tcp.h
|
||||
*/
|
||||
#ifndef _TCP_NIP_H
|
||||
#define _TCP_NIP_H
|
||||
|
||||
#define FASTRETRANS_DEBUG 1
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cache.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/ktime.h>
|
||||
|
||||
#include <net/inet_connection_sock.h>
|
||||
#include <net/inet_timewait_sock.h>
|
||||
#include <net/inet_hashtables.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/request_sock.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/snmp.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/tcp_states.h>
|
||||
#include <net/inet_ecn.h>
|
||||
#include <net/dst.h>
|
||||
|
||||
#include <net/tcp.h>
|
||||
#include <net/nip.h>
|
||||
#include <net/ninet_connection_sock.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/memcontrol.h>
|
||||
|
||||
extern struct proto tcp_nip_prot;
|
||||
|
||||
#define TCP_HDR_LEN_OFFSET 6
|
||||
#define TCP_HDR_LEN_POS_PAYLOAD 12
|
||||
#define TCP_NIP_4BYTE_PAYLOAD 2
|
||||
|
||||
#define TCP_OPT_MSS_PAYLOAD 24
|
||||
#define TCP_OLEN_MSS_PAYLOAD 16
|
||||
|
||||
#define TCP_NUM_2 2
|
||||
#define TCP_NUM_4 4
|
||||
|
||||
#define TCP_ARRAY_INDEX_2 2
|
||||
|
||||
#define TCP_NIP_KEEPALIVE_CYCLE_MS_DIVISOR 20 /* 1 HZ = 1 seconds */
|
||||
#define TCP_NIP_CSK_KEEPALIVE_CYCLE 10 /* 1 HZ = 1 seconds */
|
||||
|
||||
#define TCP_NIP_WINDOW_MAX 65535U
|
||||
|
||||
#define TCP_NIP_WRITE_TIMER_DEFERRED (TCP_MTU_REDUCED_DEFERRED + 1)
|
||||
#define TCP_NIP_DELACK_TIMER_DEFERRED (TCP_NIP_WRITE_TIMER_DEFERRED + 1)
|
||||
|
||||
/* init */
|
||||
int tcp_nip_init(void);
|
||||
void tcp_nip_exit(void);
|
||||
|
||||
void tcp_nip_done(struct sock *sk);
|
||||
int tcp_direct_connect(struct sock *sk, void __user *arg);
|
||||
void tcp_nip_rcv_established(
|
||||
struct sock *sk,
|
||||
struct sk_buff *skb,
|
||||
const struct tcphdr *th,
|
||||
unsigned int len);
|
||||
|
||||
void __tcp_nip_push_pending_frames(
|
||||
struct sock *sk,
|
||||
unsigned int cur_mss,
|
||||
int nonagle);
|
||||
|
||||
u32 __nip_tcp_select_window(struct sock *sk);
|
||||
unsigned short nip_get_output_checksum_tcp(struct sk_buff *skb, struct nip_addr src_addr,
|
||||
struct nip_addr dst_addr);
|
||||
void tcp_nip_rearm_rto(struct sock *sk);
|
||||
|
||||
int tcp_nip_rcv_state_process(struct sock *sk, struct sk_buff *skb);
|
||||
|
||||
/* tcp_nip_output */
|
||||
int tcp_nip_transmit_skb(
|
||||
struct sock *sk,
|
||||
struct sk_buff *skb,
|
||||
int clone_it,
|
||||
gfp_t gfp_mask);
|
||||
int __tcp_nip_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs);
|
||||
int tcp_nip_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs);
|
||||
void tcp_nip_send_fin(struct sock *sk);
|
||||
void tcp_nip_send_active_reset(struct sock *sk, gfp_t priority);
|
||||
void tcp_nip_send_probe0(struct sock *sk);
|
||||
int tcp_nip_write_wakeup(struct sock *sk, int mib);
|
||||
|
||||
/* tcp_nip_timer */
|
||||
void tcp_nip_init_xmit_timers(struct sock *sk);
|
||||
void tcp_nip_clear_xmit_timers(struct sock *sk);
|
||||
void tcp_nip_delack_timer_handler(struct sock *sk);
|
||||
void tcp_nip_write_timer_handler(struct sock *sk);
|
||||
|
||||
static inline struct sk_buff *tcp_nip_send_head(const struct sock *sk)
|
||||
{
|
||||
return sk->sk_send_head;
|
||||
}
|
||||
|
||||
static inline void tcp_nip_add_write_queue_tail(
|
||||
struct sock *sk,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
__skb_queue_tail(&sk->sk_write_queue, skb);
|
||||
|
||||
if (sk->sk_send_head == NULL)
|
||||
sk->sk_send_head = skb;
|
||||
}
|
||||
|
||||
static inline void tcp_nip_write_queue_purge(struct sock *sk)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) {
|
||||
tcp_skb_tsorted_anchor_cleanup(skb);
|
||||
sk_wmem_free_skb(sk, skb);
|
||||
}
|
||||
|
||||
tcp_clear_all_retrans_hints(tcp_sk(sk));
|
||||
sk->sk_send_head = NULL;
|
||||
tcp_sk(sk)->packets_out = 0;
|
||||
inet_csk(sk)->icsk_backoff = 0;
|
||||
}
|
||||
|
||||
static inline bool tcp_nip_write_queue_empty(struct sock *sk)
|
||||
{
|
||||
return skb_queue_empty(&sk->sk_write_queue);
|
||||
}
|
||||
|
||||
static inline struct tcp_nip_sock *tcp_nip_sk(const struct sock *sk)
|
||||
{
|
||||
return (struct tcp_nip_sock *)sk;
|
||||
}
|
||||
|
||||
static inline struct tcp_nip_request_sock *tcp_nip_rsk(const struct request_sock *req)
|
||||
{
|
||||
return (struct tcp_nip_request_sock *)req;
|
||||
}
|
||||
|
||||
/* connect */
|
||||
int __tcp_nip_connect(struct sock *sk);
|
||||
int _tcp_nip_conn_request(struct request_sock_ops *rsk_ops,
|
||||
const struct tcp_request_sock_ops *af_ops,
|
||||
struct sock *sk, struct sk_buff *skb);
|
||||
struct sk_buff *tcp_nip_make_synack(
|
||||
const struct sock *sk,
|
||||
struct dst_entry *dst,
|
||||
struct request_sock *req,
|
||||
struct tcp_fastopen_cookie *foc,
|
||||
enum tcp_synack_type synack_type);
|
||||
int nip_send_synack(struct request_sock *req, struct sk_buff *skb);
|
||||
struct sock *tcp_nip_check_req(struct sock *sk, struct sk_buff *skb,
|
||||
struct request_sock *req);
|
||||
int tcp_nip_child_process(struct sock *parent, struct sock *child,
|
||||
struct sk_buff *skb);
|
||||
int tcp_nip_rtx_synack(const struct sock *sk, struct request_sock *req);
|
||||
|
||||
/* client send ack */
|
||||
void tcp_nip_send_ack(struct sock *sk);
|
||||
struct sock *tcp_nip_create_openreq_child(const struct sock *sk,
|
||||
struct request_sock *req,
|
||||
struct sk_buff *skb);
|
||||
void tcp_nip_initialize_rcv_mss(struct sock *sk);
|
||||
|
||||
/* release */
|
||||
void tcp_nip_release_cb(struct sock *sk);
|
||||
|
||||
void tcp_nip_keepalive_enable(struct sock *sk);
|
||||
void tcp_nip_keepalive_disable(struct sock *sk);
|
||||
|
||||
#endif /* _NIP_TCP_H */
|
||||
@@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Based on include/net/transp_v6.h
|
||||
*/
|
||||
#ifndef _TRANSP_NIP_H
|
||||
#define _TRANSP_NIP_H
|
||||
|
||||
extern struct proto nip_udp_prot;
|
||||
|
||||
int nip_udp_init(void);
|
||||
void nip_udp_exit(void);
|
||||
|
||||
int nip_udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
|
||||
|
||||
void nip_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
|
||||
struct sk_buff *skb);
|
||||
void nip_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg,
|
||||
struct sk_buff *skb);
|
||||
void nip_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg,
|
||||
struct sk_buff *skb);
|
||||
|
||||
void nip_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, __u16 srcp,
|
||||
__u16 destp, int bucket);
|
||||
|
||||
void ninet_destroy_sock(struct sock *sk);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Linux NewIP INET implementation
|
||||
*
|
||||
* Based on include/uapi/linux/ipv6_route.h
|
||||
*
|
||||
* 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 _UAPI_LINUX_NEWIP_ROUTE_H
|
||||
#define _UAPI_LINUX_NEWIP_ROUTE_H
|
||||
|
||||
#include "nip_addr.h"
|
||||
|
||||
struct nip_rtmsg {
|
||||
struct nip_addr rtmsg_dst;
|
||||
struct nip_addr rtmsg_src;
|
||||
struct nip_addr rtmsg_gateway;
|
||||
char dev_name[10];
|
||||
unsigned int rtmsg_type;
|
||||
int rtmsg_ifindex;
|
||||
unsigned int rtmsg_metric;
|
||||
unsigned long rtmsg_info;
|
||||
unsigned int rtmsg_flags;
|
||||
};
|
||||
#endif /* _UAPI_LINUX_NEWIP_ROUTE_H */
|
||||
@@ -0,0 +1,47 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Based on include/uapi/linux/ipv6.h
|
||||
* Based on include/uapi/linux/in6.h
|
||||
*/
|
||||
#ifndef _UAPI_NEWIP_H
|
||||
#define _UAPI_NEWIP_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/libc-compat.h>
|
||||
#include <linux/types.h>
|
||||
#include "nip_addr.h"
|
||||
#include <linux/if.h>
|
||||
|
||||
struct nip_ifreq {
|
||||
struct nip_addr ifrn_addr;
|
||||
int ifrn_ifindex;
|
||||
};
|
||||
|
||||
/* The following structure must be larger than V4. System calls use V4.
|
||||
* If the definition is smaller than V4, the read process will have memory overruns
|
||||
* v4: include\linux\socket.h --> sockaddr (16Byte)
|
||||
*/
|
||||
#define POD_SOCKADDR_SIZE 3
|
||||
struct sockaddr_nin {
|
||||
unsigned short sin_family; /* [2Byte] AF_NINET */
|
||||
unsigned short sin_port; /* [2Byte] Transport layer port, big-endian */
|
||||
struct nip_addr sin_addr; /* [9Byte] NIP address */
|
||||
|
||||
unsigned char sin_zero[POD_SOCKADDR_SIZE]; /* [3Byte] Byte alignment */
|
||||
};
|
||||
|
||||
struct nip_devreq {
|
||||
char nip_ifr_name[IFNAMSIZ]; /* if name, e.g. "eth0", "wlan0" */
|
||||
|
||||
union {
|
||||
struct sockaddr_nin addr;
|
||||
short flags;
|
||||
} devreq;
|
||||
};
|
||||
|
||||
#define nip_dev_addr devreq.addr /* nip address */
|
||||
#define nip_dev_flags devreq.flags /* net device flags */
|
||||
|
||||
#endif /* _UAPI_NEWIP_H */
|
||||
@@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Definitions for the NewIP ICMP protocol.
|
||||
*
|
||||
* Based on include/uapi/linux/icmp.h
|
||||
*/
|
||||
#ifndef _UAPI_LINUX_NIP_ICMP_H
|
||||
#define _UAPI_LINUX_NIP_ICMP_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct nip_icmp_hdr {
|
||||
__u8 nip_icmp_type;
|
||||
__u8 nip_icmp_code;
|
||||
__sum16 nip_icmp_cksum;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
#
|
||||
|
||||
# net/newip/Kconfig
|
||||
config NEWIP
|
||||
def_bool $(success,$(srctree)/scripts/ohos-check-dir.sh $(srctree)/net/newip)
|
||||
depends on INET && NET
|
||||
help
|
||||
Support for NewIP.
|
||||
|
||||
config NEWIP_FAST_KEEPALIVE
|
||||
bool "NewIP fast keepalive"
|
||||
default n
|
||||
depends on NEWIP
|
||||
help
|
||||
Support for NewIP fast keepalive.
|
||||
|
||||
config NEWIP_HOOKS
|
||||
def_bool NEWIP && VENDOR_HOOKS
|
||||
help
|
||||
Enable NewIP hooks implemented as tracepoints
|
||||
Allow NewIP modules to attach to tracepoint "hooks" defined via
|
||||
DECLARE_TRACE or DECLARE_HOOK
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
#
|
||||
# Makefile for the Linux newip layer
|
||||
#
|
||||
|
||||
# net/newip/Makefile
|
||||
obj-$(CONFIG_NEWIP) += newip.o
|
||||
|
||||
newip-objs := nip_addr.o nip_hdr_encap.o nip_hdr_decap.o nip_checksum.o af_ninet.o nip_input.o udp.o protocol.o nip_output.o nip_addrconf.o nip_addrconf_core.o route.o nip_fib.o nip_fib_rules.o nndisc.o icmp.o tcp_nip_parameter.o devninet.o
|
||||
newip-objs += tcp_nip.o ninet_connection_sock.o ninet_hashtables.o tcp_nip_output.o tcp_nip_input.o tcp_nip_timer.o nip_sockglue.o
|
||||
|
||||
newip-objs += nip_hooks_register.o
|
||||
|
||||
@@ -0,0 +1,773 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET socket protocol family
|
||||
* Linux NewIP INET implementation
|
||||
*
|
||||
* Based on linux/net/ipv6/af_inet6.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched/signal.h> /* for signal_pending() */
|
||||
|
||||
#include <net/nip.h>
|
||||
#include <net/udp.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/inet_common.h>
|
||||
#include <net/route.h>
|
||||
#include <net/nndisc.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include <net/transp_nip.h>
|
||||
#include <net/nip_fib.h>
|
||||
#include <net/nip_route.h>
|
||||
#include <net/nip_addrconf.h>
|
||||
#include <net/tcp_nip.h>
|
||||
#include <linux/nip.h>
|
||||
#include <linux/newip_route.h>
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#ifdef CONFIG_NEWIP_HOOKS
|
||||
#include <trace/hooks/inet.h>
|
||||
#include "nip_hooks_register.h"
|
||||
#endif
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
MODULE_DESCRIPTION("NewIP protocol stack");
|
||||
|
||||
/* The inetsw_nip table contains everything that ninet_create needs to
|
||||
* build a new socket
|
||||
*/
|
||||
static struct list_head inetsw_nip[SOCK_MAX];
|
||||
static DEFINE_SPINLOCK(inetsw_nip_lock);
|
||||
/* count the socket number */
|
||||
atomic_t g_nip_socket_number = ATOMIC_INIT(0);
|
||||
|
||||
static int disable_nip_mod;
|
||||
module_param_named(disable, disable_nip_mod, int, 0444);
|
||||
MODULE_PARM_DESC(disable, "Disable NewIP module such that it is non_functional");
|
||||
|
||||
bool newip_mod_enabled(void)
|
||||
{
|
||||
return disable_nip_mod == 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(newip_mod_enabled);
|
||||
|
||||
static int ninet_create(struct net *net, struct socket *sock, int protocol,
|
||||
int kern)
|
||||
{
|
||||
struct inet_sock *inet;
|
||||
struct sock *sk;
|
||||
struct inet_protosw *answer;
|
||||
struct proto *answer_prot;
|
||||
unsigned char answer_flags;
|
||||
int err;
|
||||
int num;
|
||||
|
||||
if (protocol < 0 ||
|
||||
protocol >= IPPROTO_MAX ||
|
||||
sock->type >= SOCK_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
num = atomic_add_return(1, &g_nip_socket_number);
|
||||
if (num > NIP_MAX_SOCKET_NUM) {
|
||||
nip_dbg("The number of socket is biger than %u", NIP_MAX_SOCKET_NUM);
|
||||
err = -EPERM;
|
||||
goto number_sub;
|
||||
}
|
||||
|
||||
sock->state = SS_UNCONNECTED;
|
||||
/* look for the requested type/protocol pair. */
|
||||
err = -ESOCKTNOSUPPORT;
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(answer, &inetsw_nip[sock->type], list) {
|
||||
err = 0;
|
||||
/* Check the non-wild matcg */
|
||||
if (protocol == answer->protocol) {
|
||||
if (protocol != IPPROTO_IP)
|
||||
break;
|
||||
} else {
|
||||
/* check for the two wild case. */
|
||||
if (protocol == IPPROTO_IP) {
|
||||
protocol = answer->protocol;
|
||||
break;
|
||||
}
|
||||
if (answer->protocol == IPPROTO_IP)
|
||||
break;
|
||||
}
|
||||
err = -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto out_rcu_unlock;
|
||||
|
||||
sock->ops = answer->ops;
|
||||
answer_prot = answer->prot;
|
||||
answer_flags = answer->flags;
|
||||
rcu_read_unlock();
|
||||
|
||||
WARN_ON(!answer_prot->slab);
|
||||
|
||||
err = -ENOBUFS;
|
||||
sk = sk_alloc(net, PF_NINET, GFP_KERNEL, answer_prot, kern);
|
||||
if (!sk)
|
||||
goto number_sub;
|
||||
|
||||
sock_init_data(sock, sk);
|
||||
|
||||
err = 0;
|
||||
if (answer_flags & INET_PROTOSW_REUSE)
|
||||
sk->sk_reuse = SK_CAN_REUSE;
|
||||
inet = inet_sk(sk);
|
||||
inet->is_icsk = (answer_flags & INET_PROTOSW_ICSK) != 0;
|
||||
inet->nodefrag = 0;
|
||||
|
||||
if (sock->type == SOCK_RAW) {
|
||||
inet->inet_num = protocol;
|
||||
if (protocol == IPPROTO_RAW)
|
||||
inet->hdrincl = 1;
|
||||
}
|
||||
|
||||
sk->sk_destruct = inet_sock_destruct;
|
||||
sk->sk_family = PF_NINET;
|
||||
sk->sk_protocol = protocol;
|
||||
sk->sk_backlog_rcv = answer->prot->backlog_rcv;
|
||||
sk->sk_nip_daddr = nip_any_addr;
|
||||
sk->sk_nip_rcv_saddr = nip_any_addr;
|
||||
|
||||
inet->uc_ttl = -1;
|
||||
inet->mc_loop = 1;
|
||||
inet->mc_ttl = 1;
|
||||
inet->mc_all = 1;
|
||||
inet->mc_index = 0;
|
||||
inet->mc_list = NULL;
|
||||
inet->rcv_tos = 0;
|
||||
sk_refcnt_debug_inc(sk);
|
||||
|
||||
if (inet->inet_num) {
|
||||
inet->inet_sport = htons(inet->inet_num);
|
||||
err = sk->sk_prot->hash(sk);
|
||||
if (err) {
|
||||
sk_common_release(sk);
|
||||
goto number_sub;
|
||||
}
|
||||
}
|
||||
if (sk->sk_prot->init) {
|
||||
err = sk->sk_prot->init(sk);
|
||||
if (err) {
|
||||
sk_common_release(sk);
|
||||
goto number_sub;
|
||||
}
|
||||
}
|
||||
out:
|
||||
nip_dbg("The final number of socket is: %d", num);
|
||||
return err;
|
||||
out_rcu_unlock:
|
||||
rcu_read_unlock();
|
||||
number_sub:
|
||||
atomic_dec_if_positive(&g_nip_socket_number);
|
||||
num = atomic_read(&g_nip_socket_number);
|
||||
nip_dbg("[error] The final number of socket is: %d (after dec)", num);
|
||||
goto out;
|
||||
}
|
||||
|
||||
int ninet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||
{
|
||||
struct sockaddr_nin *addr = (struct sockaddr_nin *)uaddr;
|
||||
struct sock *sk = sock->sk;
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
struct net *net = sock_net(sk);
|
||||
u_short snum;
|
||||
int err = 0;
|
||||
|
||||
/* If the socket has its own bind function then use it */
|
||||
if (sk->sk_prot->bind)
|
||||
return sk->sk_prot->bind(sk, uaddr, addr_len);
|
||||
|
||||
if (addr_len < sizeof(struct sockaddr_nin))
|
||||
return -EINVAL;
|
||||
|
||||
snum = ntohs(addr->sin_port);
|
||||
if (snum && snum < PROT_SOCK)
|
||||
return -EACCES;
|
||||
|
||||
if (nip_bind_addr_check(net, &addr->sin_addr) == false) {
|
||||
nip_dbg("binding-addr invalid, bitlen=%u", addr->sin_addr.bitlen);
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
lock_sock(sk);
|
||||
|
||||
/* check these errors (active socket, double bind) */
|
||||
if (sk->sk_state != TCP_CLOSE || inet->inet_num) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sk->sk_nip_rcv_saddr = addr->sin_addr;
|
||||
|
||||
/* make sure we are allowed to bind here */
|
||||
if ((snum || !inet->bind_address_no_port) &&
|
||||
sk->sk_prot->get_port(sk, snum)) {
|
||||
inet->inet_saddr = 0;
|
||||
err = -EADDRINUSE;
|
||||
goto out;
|
||||
}
|
||||
inet->inet_sport = htons(inet->inet_num);
|
||||
inet->inet_daddr = 0;
|
||||
inet->inet_dport = 0;
|
||||
sk_dst_reset(sk);
|
||||
|
||||
out:
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Function
|
||||
* Move a socket into listening state.
|
||||
* Parameter
|
||||
* sock: The socket
|
||||
* backlog: Specifies the number of clients that use a three-way handshake
|
||||
* to establish a TCP connection
|
||||
*/
|
||||
int ninet_listen(struct socket *sock, int backlog)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
unsigned char old_state;
|
||||
int err;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
err = -EINVAL;
|
||||
if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM)
|
||||
goto out;
|
||||
|
||||
old_state = sk->sk_state;
|
||||
if (!((1 << old_state) & (TCPF_CLOSE | TCPF_LISTEN)))
|
||||
goto out;
|
||||
|
||||
WRITE_ONCE(sk->sk_max_ack_backlog, backlog);
|
||||
/* Really, if the socket is already in listen state
|
||||
* we can only allow the backlog to be adjusted.
|
||||
*/
|
||||
if (old_state != TCP_LISTEN) {
|
||||
err = inet_csk_listen_start(sk, backlog);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
release_sock(sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ninet_release(struct socket *sock)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
|
||||
if (!sk)
|
||||
return -EINVAL;
|
||||
|
||||
atomic_dec_if_positive(&g_nip_socket_number);
|
||||
return inet_release(sock);
|
||||
}
|
||||
|
||||
void ninet_destroy_sock(struct sock *sk)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
int ninet_getname(struct socket *sock, struct sockaddr *uaddr,
|
||||
int peer)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
DECLARE_SOCKADDR(struct sockaddr_nin *, sin, uaddr);
|
||||
|
||||
sin->sin_family = AF_NINET;
|
||||
if (peer) {
|
||||
if (!inet->inet_dport)
|
||||
return -ENOTCONN;
|
||||
if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) &&
|
||||
peer == 1)
|
||||
return -ENOTCONN;
|
||||
sin->sin_port = inet->inet_dport;
|
||||
sin->sin_addr = sk->sk_nip_daddr;
|
||||
} else {
|
||||
sin->sin_port = inet->inet_sport;
|
||||
sin->sin_addr = sk->sk_nip_rcv_saddr;
|
||||
}
|
||||
return sizeof(*sin);
|
||||
}
|
||||
|
||||
static long ninet_wait_for_connect(struct sock *sk, long timeo, int writebias)
|
||||
{
|
||||
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
||||
|
||||
add_wait_queue(sk_sleep(sk), &wait);
|
||||
sk->sk_write_pending += writebias;
|
||||
|
||||
/* Basic assumption: if someone sets sk->sk_err, he _must_
|
||||
* change state of the socket from TCP_SYN_*.
|
||||
* Connect() does not allow to get error notifications
|
||||
* without closing the socket.
|
||||
*/
|
||||
while ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
|
||||
release_sock(sk);
|
||||
timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
|
||||
lock_sock(sk);
|
||||
if (signal_pending(current) || !timeo)
|
||||
break;
|
||||
}
|
||||
remove_wait_queue(sk_sleep(sk), &wait);
|
||||
sk->sk_write_pending -= writebias;
|
||||
return timeo;
|
||||
}
|
||||
|
||||
/* Function
|
||||
* The client socket layer is used to establish connection requests
|
||||
* Parameter
|
||||
* sock: The socket
|
||||
* uaddr:The destination address
|
||||
*/
|
||||
int __ninet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
|
||||
int addr_len, int flags)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
int err;
|
||||
long timeo;
|
||||
|
||||
if (uaddr) {
|
||||
if (addr_len < sizeof(uaddr->sa_family))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (sock->state) {
|
||||
default:
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
case SS_CONNECTED:
|
||||
err = -EISCONN;
|
||||
goto out;
|
||||
case SS_CONNECTING:
|
||||
err = -EALREADY;
|
||||
break;
|
||||
case SS_UNCONNECTED:
|
||||
err = -EISCONN;
|
||||
if (sk->sk_state != TCP_CLOSE)
|
||||
goto out;
|
||||
/* Call the tcp_nip_connect function */
|
||||
err = sk->sk_prot->connect(sk, uaddr, addr_len);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
/* Switch to connecting, and then perform subsequent operations */
|
||||
sock->state = SS_CONNECTING;
|
||||
err = -EINPROGRESS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get blocking time */
|
||||
timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
|
||||
if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
|
||||
int writebias = 0;
|
||||
/* Error code is set above */
|
||||
if (!timeo || !ninet_wait_for_connect(sk, timeo, writebias))
|
||||
goto out;
|
||||
|
||||
err = sock_intr_errno(timeo);
|
||||
if (signal_pending(current))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sk->sk_state == TCP_CLOSE)
|
||||
goto sock_error;
|
||||
sock->state = SS_CONNECTED;
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
return err;
|
||||
sock_error:
|
||||
err = sock_error(sk) ? : -ECONNABORTED;
|
||||
sock->state = SS_DISCONNECTING;
|
||||
goto out;
|
||||
}
|
||||
|
||||
int ninet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
|
||||
int addr_len, int flags)
|
||||
{
|
||||
int err;
|
||||
|
||||
lock_sock(sock->sk);
|
||||
err = __ninet_stream_connect(sock, uaddr, addr_len, flags);
|
||||
release_sock(sock->sk);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ninet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct net *net = sock_net(sk);
|
||||
|
||||
nip_dbg("cmd=0x%x", cmd);
|
||||
switch (cmd) {
|
||||
case SIOCADDRT:
|
||||
case SIOCDELRT: {
|
||||
struct nip_rtmsg rtmsg;
|
||||
|
||||
if (copy_from_user(&rtmsg, (void __user *)arg, sizeof(rtmsg))) {
|
||||
nip_dbg("fail to copy route cfg data");
|
||||
return -EFAULT;
|
||||
}
|
||||
return nip_route_ioctl(net, cmd, &rtmsg);
|
||||
}
|
||||
case SIOCSIFADDR:
|
||||
return nip_addrconf_add_ifaddr(net, (void __user *)arg);
|
||||
case SIOCDIFADDR:
|
||||
return nip_addrconf_del_ifaddr(net, (void __user *)arg);
|
||||
case SIOCGIFADDR:
|
||||
return nip_addrconf_get_ifaddr(net, cmd, (void __user *)arg);
|
||||
|
||||
default:
|
||||
if (!sk->sk_prot->ioctl) {
|
||||
nip_dbg("sock sk_prot ioctl is null, cmd=0x%x", cmd);
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
return sk->sk_prot->ioctl(sk, cmd, arg);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_nip_rtmsg {
|
||||
struct nip_addr rtmsg_dst;
|
||||
struct nip_addr rtmsg_src;
|
||||
struct nip_addr rtmsg_gateway;
|
||||
char dev_name[10];
|
||||
unsigned int rtmsg_type;
|
||||
int rtmsg_ifindex;
|
||||
unsigned int rtmsg_metric;
|
||||
unsigned int rtmsg_info; /* long convert to int */
|
||||
unsigned int rtmsg_flags;
|
||||
};
|
||||
|
||||
static int ninet_compat_routing_ioctl(struct sock *sk, unsigned int cmd,
|
||||
struct compat_nip_rtmsg __user *ur)
|
||||
{
|
||||
struct nip_rtmsg rt;
|
||||
|
||||
if (copy_from_user(&rt.rtmsg_dst, &ur->rtmsg_dst, 3 * sizeof(struct nip_addr)) ||
|
||||
copy_from_user(&rt.dev_name, &ur->dev_name, sizeof(rt.dev_name)) ||
|
||||
get_user(rt.rtmsg_type, &ur->rtmsg_type) ||
|
||||
get_user(rt.rtmsg_ifindex, &ur->rtmsg_ifindex) ||
|
||||
get_user(rt.rtmsg_metric, &ur->rtmsg_metric) ||
|
||||
get_user(rt.rtmsg_info, &ur->rtmsg_info) ||
|
||||
get_user(rt.rtmsg_flags, &ur->rtmsg_flags)) {
|
||||
nip_dbg("fail to convert input para, cmd=0x%x", cmd);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
nip_dbg("cmd=0x%x", cmd);
|
||||
return nip_route_ioctl(sock_net(sk), cmd, &rt);
|
||||
}
|
||||
|
||||
int ninet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
void __user *argp = compat_ptr(arg);
|
||||
struct sock *sk = sock->sk;
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCADDRT:
|
||||
case SIOCDELRT:
|
||||
return ninet_compat_routing_ioctl(sk, cmd, argp);
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ninet_compat_ioctl);
|
||||
#endif /* CONFIG_COMPAT */
|
||||
|
||||
/* register new IP socket */
|
||||
const struct proto_ops ninet_dgram_ops = {
|
||||
.family = PF_NINET,
|
||||
.owner = THIS_MODULE,
|
||||
.release = ninet_release,
|
||||
.bind = ninet_bind,
|
||||
.connect = inet_dgram_connect,
|
||||
.socketpair = sock_no_socketpair,
|
||||
.accept = sock_no_accept,
|
||||
.getname = ninet_getname,
|
||||
.poll = datagram_poll,
|
||||
.ioctl = ninet_ioctl,
|
||||
.gettstamp = sock_gettstamp,
|
||||
.listen = sock_no_listen,
|
||||
.shutdown = inet_shutdown,
|
||||
.setsockopt = sock_common_setsockopt,
|
||||
.getsockopt = sock_common_getsockopt,
|
||||
.sendmsg = inet_sendmsg,
|
||||
.recvmsg = inet_recvmsg,
|
||||
.mmap = sock_no_mmap,
|
||||
.sendpage = sock_no_sendpage,
|
||||
.set_peek_off = sk_set_peek_off,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ninet_compat_ioctl,
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct proto_ops ninet_stream_ops = {
|
||||
.family = PF_NINET,
|
||||
.owner = THIS_MODULE,
|
||||
.release = ninet_release,
|
||||
.bind = ninet_bind,
|
||||
.connect = ninet_stream_connect,
|
||||
.socketpair = sock_no_socketpair,
|
||||
.accept = inet_accept,
|
||||
.getname = ninet_getname,
|
||||
.poll = tcp_poll,
|
||||
.ioctl = ninet_ioctl,
|
||||
.listen = ninet_listen,
|
||||
.shutdown = inet_shutdown,
|
||||
.setsockopt = sock_common_setsockopt,
|
||||
.getsockopt = sock_common_getsockopt,
|
||||
.sendmsg = inet_sendmsg,
|
||||
.recvmsg = inet_recvmsg,
|
||||
.mmap = sock_no_mmap,
|
||||
.sendpage = inet_sendpage,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ninet_compat_ioctl,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct net_proto_family ninet_family_ops = {
|
||||
.family = PF_NINET,
|
||||
.create = ninet_create,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
int ninet_register_protosw(struct inet_protosw *p)
|
||||
{
|
||||
struct list_head *lh;
|
||||
struct inet_protosw *answer;
|
||||
struct list_head *last_perm;
|
||||
int protocol = p->protocol;
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&inetsw_nip_lock);
|
||||
|
||||
ret = -EINVAL;
|
||||
if (p->type >= SOCK_MAX)
|
||||
goto out_illegal;
|
||||
|
||||
/* If we are trying to override a permanent protocol, bail. */
|
||||
answer = NULL;
|
||||
ret = -EPERM;
|
||||
last_perm = &inetsw_nip[p->type];
|
||||
list_for_each(lh, &inetsw_nip[p->type]) {
|
||||
answer = list_entry(lh, struct inet_protosw, list);
|
||||
|
||||
/* Check only the non-wild match. */
|
||||
if (answer->flags & INET_PROTOSW_PERMANENT) {
|
||||
if (protocol == answer->protocol)
|
||||
break;
|
||||
last_perm = lh;
|
||||
}
|
||||
|
||||
answer = NULL;
|
||||
}
|
||||
if (answer)
|
||||
goto out_permanent;
|
||||
|
||||
list_add_rcu(&p->list, last_perm);
|
||||
ret = 0;
|
||||
out:
|
||||
spin_unlock_bh(&inetsw_nip_lock);
|
||||
return ret;
|
||||
|
||||
out_permanent:
|
||||
nip_dbg("Attempt to override permanent protocol %d", protocol);
|
||||
goto out;
|
||||
|
||||
out_illegal:
|
||||
nip_dbg("Ignoring attempt to register invalid socket type %d", p->type);
|
||||
goto out;
|
||||
}
|
||||
|
||||
void ninet_unregister_protosw(struct inet_protosw *p)
|
||||
{
|
||||
if (INET_PROTOSW_PERMANENT & p->flags) {
|
||||
nip_dbg("Attempt to unregister permanent protocol %d", p->protocol);
|
||||
} else {
|
||||
spin_lock_bh(&inetsw_nip_lock);
|
||||
list_del_rcu(&p->list);
|
||||
spin_unlock_bh(&inetsw_nip_lock);
|
||||
|
||||
synchronize_net();
|
||||
}
|
||||
}
|
||||
|
||||
int ninet_sk_rebuild_header(struct sock *sk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* register to data link layer */
|
||||
static struct packet_type nip_packet_type __read_mostly = {
|
||||
.type = cpu_to_be16(ETH_P_NEWIP),
|
||||
.func = nip_rcv,
|
||||
};
|
||||
|
||||
static int __init nip_packet_init(void)
|
||||
{
|
||||
dev_add_pack(&nip_packet_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __net_init ninet_net_init(struct net *net)
|
||||
{
|
||||
int err = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __net_exit ninet_net_exit(struct net *net)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static struct pernet_operations ninet_net_ops = {
|
||||
.init = ninet_net_init,
|
||||
.exit = ninet_net_exit,
|
||||
};
|
||||
|
||||
static int __init ninet_init(void)
|
||||
{
|
||||
struct list_head *r;
|
||||
int err = 0;
|
||||
|
||||
sock_skb_cb_check_size(sizeof(struct ninet_skb_parm));
|
||||
|
||||
nip_dbg("NET: start to init nip network");
|
||||
/* register the socket-side information for ninet_create */
|
||||
for (r = &inetsw_nip[0]; r < &inetsw_nip[SOCK_MAX]; ++r)
|
||||
INIT_LIST_HEAD(r);
|
||||
|
||||
if (!newip_mod_enabled()) {
|
||||
nip_dbg("Loaded, but administratively disabled, reboot required to enable");
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = proto_register(&tcp_nip_prot, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = proto_register(&nip_udp_prot, 1);
|
||||
if (err) {
|
||||
nip_dbg("failed to register udp proto");
|
||||
goto out_udp_register_fail;
|
||||
}
|
||||
|
||||
err = sock_register(&ninet_family_ops);
|
||||
if (err) {
|
||||
nip_dbg("failed to register newip_family_ops");
|
||||
goto out_sock_register_fail;
|
||||
}
|
||||
|
||||
err = register_pernet_subsys(&ninet_net_ops);
|
||||
if (err) {
|
||||
nip_dbg("failed to register ninet_net_ops");
|
||||
goto register_pernet_fail;
|
||||
}
|
||||
|
||||
err = nip_icmp_init();
|
||||
if (err) {
|
||||
nip_dbg("nip_icmp_init failed");
|
||||
goto nip_icmp_fail;
|
||||
}
|
||||
|
||||
err = nndisc_init();
|
||||
if (err) {
|
||||
nip_dbg("nndisc_init failed");
|
||||
goto nndisc_fail;
|
||||
}
|
||||
|
||||
err = nip_route_init();
|
||||
if (err)
|
||||
goto nip_route_fail;
|
||||
|
||||
err = nip_addrconf_init();
|
||||
if (err)
|
||||
goto nip_addr_fail;
|
||||
|
||||
err = nip_udp_init();
|
||||
if (err) {
|
||||
nip_dbg("failed to init udp layer");
|
||||
goto udp_fail;
|
||||
}
|
||||
|
||||
err = tcp_nip_init();
|
||||
if (err) {
|
||||
nip_dbg("failed to init tcp layer");
|
||||
goto tcp_fail;
|
||||
} else {
|
||||
nip_dbg("nip_tcp_init ok");
|
||||
}
|
||||
|
||||
err = nip_packet_init();
|
||||
if (err) {
|
||||
nip_dbg("failed to register to l2 layer");
|
||||
goto nip_packet_fail;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NEWIP_HOOKS
|
||||
err = ninet_hooks_register();
|
||||
if (err) {
|
||||
nip_dbg("failed to register to nip hooks");
|
||||
goto nip_packet_fail;
|
||||
}
|
||||
#endif
|
||||
nip_dbg("init newip address family ok");
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
nip_packet_fail:
|
||||
tcp_nip_exit();
|
||||
tcp_fail:
|
||||
nip_udp_exit();
|
||||
udp_fail:
|
||||
nip_addrconf_cleanup();
|
||||
nip_addr_fail:
|
||||
nip_route_cleanup();
|
||||
nip_route_fail:
|
||||
nndisc_fail:
|
||||
nip_icmp_fail:
|
||||
unregister_pernet_subsys(&ninet_net_ops);
|
||||
register_pernet_fail:
|
||||
sock_unregister(PF_NINET);
|
||||
out_sock_register_fail:
|
||||
proto_unregister(&nip_udp_prot);
|
||||
out_udp_register_fail:
|
||||
nip_dbg("newip family init failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
module_init(ninet_init);
|
||||
|
||||
MODULE_ALIAS_NETPROTO(PF_NINET);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* DEVICE - NEWIP device support.
|
||||
* Based on net/ipv4/devinet.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <net/nip_fib.h>
|
||||
#include <net/nip_addrconf.h>
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
int ninet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
|
||||
{
|
||||
struct ninet_dev *nin_dev = __nin_dev_get(dev);
|
||||
const struct ninet_ifaddr *ifa;
|
||||
struct ifreq ifr;
|
||||
int done = 0;
|
||||
|
||||
if (WARN_ON(size > sizeof(struct ifreq)))
|
||||
goto out;
|
||||
if (!nin_dev)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(ifa, &nin_dev->addr_list, if_list) {
|
||||
ifa = rcu_dereference_protected(ifa, lockdep_is_held(&ifa->lock));
|
||||
if (!ifa) {
|
||||
done = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (!buf) {
|
||||
done += size;
|
||||
continue;
|
||||
}
|
||||
if (len < size)
|
||||
break;
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
strcpy(ifr.ifr_name, ifa->rt->dst.dev->name);
|
||||
|
||||
(*(struct sockaddr_nin *)&ifr.ifr_addr).sin_family = AF_NINET;
|
||||
memcpy(&((struct sockaddr_nin *)&ifr.ifr_addr)->sin_addr, &ifa->addr,
|
||||
sizeof(struct nip_addr));
|
||||
|
||||
if (copy_to_user(buf + done, &ifr, size)) {
|
||||
done = -EFAULT;
|
||||
break;
|
||||
}
|
||||
len -= size;
|
||||
done += size;
|
||||
}
|
||||
out:
|
||||
return done;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Internet Control Message Protocol (NewIP ICMP)
|
||||
* Linux NewIP INET implementation
|
||||
*
|
||||
* Based on net/ipv6/icmp.c
|
||||
* Based on net/ipv4/af_inet.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/nip_icmp.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/nip.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/nip_route.h>
|
||||
#include <net/nip_addrconf.h>
|
||||
#include <net/nndisc.h>
|
||||
|
||||
#include "nip_hdr.h"
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
int nip_icmp_rcv(struct sk_buff *skb)
|
||||
{
|
||||
int ret = 0;
|
||||
struct nip_icmp_hdr *hdr = nip_icmp_header(skb);
|
||||
u8 type = hdr->nip_icmp_type;
|
||||
|
||||
nip_dbg("rcv newip icmp packet. type=%u", type);
|
||||
switch (type) {
|
||||
case NIP_ARP_NS:
|
||||
case NIP_ARP_NA:
|
||||
ret = nndisc_rcv(skb);
|
||||
break;
|
||||
default:
|
||||
nip_dbg("nip icmp packet type error");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct ninet_protocol nip_icmp_protocol = {
|
||||
.handler = nip_icmp_rcv,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
int __init nip_icmp_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ninet_add_protocol(&nip_icmp_protocol, IPPROTO_NIP_ICMP);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Support for NewIP INET connection oriented protocols.
|
||||
*
|
||||
* Based on net/ipv4/inet_connection_sock.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/nip.h>
|
||||
#include <linux/jhash.h>
|
||||
|
||||
#include <net/tcp.h>
|
||||
#include <net/nip_addrconf.h>
|
||||
#include <net/inet_connection_sock.h>
|
||||
#include <net/inet_hashtables.h>
|
||||
#include <net/nip_route.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/ninet_connection_sock.h>
|
||||
#include <net/tcp_nip.h>
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
/* Function
|
||||
* Timeout handler for request processing, used to retransmit SYN+ACK
|
||||
* Parameter
|
||||
* t: Request control block
|
||||
*/
|
||||
static void ninet_reqsk_timer_handler(struct timer_list *t)
|
||||
{
|
||||
struct request_sock *req = from_timer(req, t, rsk_timer);
|
||||
struct sock *sk_listener = req->rsk_listener;
|
||||
struct net *net = sock_net(sk_listener);
|
||||
struct inet_connection_sock *icsk = inet_csk(sk_listener);
|
||||
struct request_sock_queue *queue = &icsk->icsk_accept_queue;
|
||||
int max_retries, thresh;
|
||||
|
||||
/* Defines the maximum number of retransmissions. Thresh defaults to 5 */
|
||||
max_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries;
|
||||
thresh = max_retries;
|
||||
|
||||
/* Check timeout times. SYN+ACK retransmission times +1 */
|
||||
if (req->num_timeout <= thresh) {
|
||||
unsigned long timeo;
|
||||
|
||||
req->rsk_ops->rtx_syn_ack(sk_listener, req);
|
||||
req->num_retrans++;
|
||||
/* If the number of times out is still 0, the number is increased by 1
|
||||
* to determine whether it is the first time out
|
||||
*/
|
||||
if (req->num_timeout++ == 0)
|
||||
atomic_dec(&queue->young);
|
||||
timeo = min(TCP_TIMEOUT_INIT, TCP_RTO_MAX);
|
||||
mod_timer(&req->rsk_timer, jiffies + timeo);
|
||||
return;
|
||||
}
|
||||
|
||||
inet_csk_reqsk_queue_drop_and_put(sk_listener, req);
|
||||
}
|
||||
|
||||
/* Function
|
||||
* Add request_SOCK to the connection queue and ehash table,
|
||||
* and set the SYNACK timeout retransmission timer
|
||||
* Parameter
|
||||
* sk: Transmission control block
|
||||
* req: Connection request block
|
||||
* timeout: The initial timeout period
|
||||
*/
|
||||
void ninet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
|
||||
unsigned long timeout)
|
||||
{
|
||||
req->num_retrans = 0;
|
||||
req->num_timeout = 0;
|
||||
req->sk = NULL;
|
||||
|
||||
timer_setup(&req->rsk_timer, ninet_reqsk_timer_handler,
|
||||
TIMER_PINNED);
|
||||
mod_timer(&req->rsk_timer, jiffies + timeout);
|
||||
|
||||
inet_ehash_insert(req_to_sk(req), NULL, NULL);
|
||||
|
||||
smp_wmb(); /* memory barrier */
|
||||
refcount_set(&req->rsk_refcnt, TCP_NUM_2 + 1);
|
||||
|
||||
inet_csk_reqsk_queue_added(sk);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,487 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Generic NewIP INET transport hashtables
|
||||
*
|
||||
* Based on net/ipv4/inet_hashtables.c
|
||||
* Based on net/ipv6/inet6_hashtables.c
|
||||
* Based on include/net/ip.h
|
||||
* Based on include/net/ipv6.h
|
||||
* Based on net/core/secure_seq.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include <net/nip_addrconf.h>
|
||||
#include <net/inet_connection_sock.h>
|
||||
#include <net/inet_hashtables.h>
|
||||
#include <net/ninet_hashtables.h>
|
||||
#include <net/secure_seq.h>
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
static siphash_key_t net_secret __read_mostly;
|
||||
|
||||
static __always_inline void net_secret_init(void)
|
||||
{
|
||||
net_get_random_once(&net_secret, sizeof(net_secret));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_INET
|
||||
static u32 seq_scale(u32 seq)
|
||||
{
|
||||
/* As close as possible to RFC 793, which
|
||||
* suggests using a 250 kHz clock.
|
||||
* Further reading shows this assumes 2 Mb/s networks.
|
||||
* or 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
|
||||
* For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
|
||||
* we also need to limit the resolution so that the u32 seq
|
||||
* overlaps less than one time per MSL (2 minutes).
|
||||
* Choosing a clock of 64 ns period is OK. (period of 274 s)
|
||||
*/
|
||||
return seq + (ktime_get_real_ns() >> 6);
|
||||
}
|
||||
#endif
|
||||
|
||||
__u32 secure_tcp_nip_sequence_number(const __be32 *saddr, const __be32 *daddr,
|
||||
__be16 sport, __be16 dport)
|
||||
{
|
||||
const struct {
|
||||
struct nip_addr saddr;
|
||||
struct nip_addr daddr;
|
||||
__be16 sport;
|
||||
__be16 dport;
|
||||
} __aligned(SIPHASH_ALIGNMENT) combined = {
|
||||
.saddr = *(struct nip_addr *)saddr,
|
||||
.daddr = *(struct nip_addr *)daddr,
|
||||
.sport = sport,
|
||||
.dport = dport,
|
||||
};
|
||||
u32 hash;
|
||||
|
||||
net_secret_init();
|
||||
hash = siphash(&combined, offsetofend(typeof(combined), dport),
|
||||
&net_secret);
|
||||
return seq_scale(hash);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(secure_tcp_nip_sequence_number);
|
||||
|
||||
u64 secure_newip_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
|
||||
__be16 dport)
|
||||
{
|
||||
const struct {
|
||||
struct nip_addr saddr;
|
||||
struct nip_addr daddr;
|
||||
__be16 dport;
|
||||
} __aligned(SIPHASH_ALIGNMENT) combined = {
|
||||
.saddr = *(struct nip_addr *)saddr,
|
||||
.daddr = *(struct nip_addr *)daddr,
|
||||
.dport = dport,
|
||||
};
|
||||
net_secret_init();
|
||||
return siphash(&combined, offsetofend(typeof(combined), dport),
|
||||
&net_secret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(secure_newip_port_ephemeral);
|
||||
|
||||
static inline u32 nip_portaddr_hash(const struct net *net,
|
||||
const struct nip_addr *saddr,
|
||||
unsigned int port)
|
||||
{
|
||||
u32 v = (__force u32)saddr->nip_addr_field32[0] ^ (__force u32)saddr->nip_addr_field32[1];
|
||||
|
||||
return jhash_1word(v, net_hash_mix(net)) ^ port;
|
||||
}
|
||||
|
||||
static u32 __nip_addr_jhash(const struct nip_addr *a, const u32 initval)
|
||||
{
|
||||
u32 v = (__force u32)a->nip_addr_field32[0] ^ (__force u32)a->nip_addr_field32[1];
|
||||
|
||||
return jhash_3words(v,
|
||||
(__force u32)a->nip_addr_field32[0],
|
||||
(__force u32)a->nip_addr_field32[1],
|
||||
initval);
|
||||
}
|
||||
|
||||
static struct inet_listen_hashbucket *
|
||||
ninet_lhash2_bucket_sk(struct inet_hashinfo *h, struct sock *sk)
|
||||
{
|
||||
u32 hash = nip_portaddr_hash(sock_net(sk),
|
||||
&sk->sk_nip_rcv_saddr,
|
||||
inet_sk(sk)->inet_num);
|
||||
return inet_lhash2_bucket(h, hash);
|
||||
}
|
||||
|
||||
static void ninet_hash2(struct inet_hashinfo *h, struct sock *sk)
|
||||
{
|
||||
struct inet_listen_hashbucket *ilb2;
|
||||
|
||||
if (!h->lhash2)
|
||||
return;
|
||||
|
||||
ilb2 = ninet_lhash2_bucket_sk(h, sk);
|
||||
|
||||
spin_lock(&ilb2->lock);
|
||||
hlist_add_head_rcu(&inet_csk(sk)->icsk_listen_portaddr_node, &ilb2->head);
|
||||
|
||||
ilb2->count++;
|
||||
spin_unlock(&ilb2->lock);
|
||||
}
|
||||
|
||||
/* Function
|
||||
* Returns the hash value based on the passed argument
|
||||
* Parameter
|
||||
* net: The namespace
|
||||
* laddr: The destination address
|
||||
* lport: Destination port
|
||||
* faddr: Source address
|
||||
* fport: Source port
|
||||
*/
|
||||
u32 ninet_ehashfn(const struct net *net,
|
||||
const struct nip_addr *laddr, const u16 lport,
|
||||
const struct nip_addr *faddr, const __be16 fport)
|
||||
{
|
||||
static u32 ninet_ehash_secret __read_mostly;
|
||||
static u32 ninet_hash_secret __read_mostly;
|
||||
|
||||
u32 lhash, fhash;
|
||||
|
||||
net_get_random_once(&ninet_ehash_secret, sizeof(ninet_ehash_secret));
|
||||
net_get_random_once(&ninet_hash_secret, sizeof(ninet_hash_secret));
|
||||
|
||||
/* Ipv6 uses S6_ADdr32 [3], the last 32bits of the address */
|
||||
lhash = (__force u32)laddr->nip_addr_field32[0];
|
||||
fhash = __nip_addr_jhash(faddr, ninet_hash_secret);
|
||||
|
||||
return __ninet_ehashfn(lhash, lport, fhash, fport,
|
||||
ninet_ehash_secret + net_hash_mix(net));
|
||||
}
|
||||
|
||||
/* Function
|
||||
* The socket is put into the Listen hash in case the server finds
|
||||
* the socket in the second handshake
|
||||
* Parameter
|
||||
* sk: Transmission control block
|
||||
* osk: old socket
|
||||
*/
|
||||
int __ninet_hash(struct sock *sk, struct sock *osk)
|
||||
{
|
||||
struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
|
||||
struct inet_listen_hashbucket *ilb;
|
||||
int err = 0;
|
||||
|
||||
if (sk->sk_state != TCP_LISTEN) {
|
||||
inet_ehash_nolisten(sk, osk, NULL);
|
||||
return 0;
|
||||
}
|
||||
WARN_ON(!sk_unhashed(sk));
|
||||
ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
|
||||
|
||||
spin_lock(&ilb->lock);
|
||||
|
||||
__sk_nulls_add_node_rcu(sk, &ilb->nulls_head);
|
||||
|
||||
ninet_hash2(hashinfo, sk);
|
||||
ilb->count++;
|
||||
sock_set_flag(sk, SOCK_RCU_FREE);
|
||||
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
|
||||
|
||||
spin_unlock(&ilb->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int ninet_hash(struct sock *sk)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (sk->sk_state != TCP_CLOSE) {
|
||||
local_bh_disable();
|
||||
err = __ninet_hash(sk, NULL);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ninet_unhash2(struct inet_hashinfo *h, struct sock *sk)
|
||||
{
|
||||
struct inet_listen_hashbucket *ilb2;
|
||||
|
||||
if (!h->lhash2 ||
|
||||
WARN_ON_ONCE(hlist_unhashed(&inet_csk(sk)->icsk_listen_portaddr_node)))
|
||||
return;
|
||||
|
||||
ilb2 = ninet_lhash2_bucket_sk(h, sk);
|
||||
|
||||
spin_lock(&ilb2->lock);
|
||||
hlist_del_init_rcu(&inet_csk(sk)->icsk_listen_portaddr_node);
|
||||
ilb2->count--;
|
||||
spin_unlock(&ilb2->lock);
|
||||
}
|
||||
|
||||
void ninet_unhash(struct sock *sk)
|
||||
{
|
||||
struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
|
||||
struct inet_listen_hashbucket *ilb = NULL;
|
||||
spinlock_t *lock; /* Spin lock (note deleted alarm) */
|
||||
|
||||
if (sk_unhashed(sk))
|
||||
return;
|
||||
|
||||
if (sk->sk_state == TCP_LISTEN) {
|
||||
ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
|
||||
lock = &ilb->lock;
|
||||
} else {
|
||||
lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
|
||||
}
|
||||
spin_lock_bh(lock);
|
||||
if (sk_unhashed(sk))
|
||||
goto unlock;
|
||||
|
||||
if (ilb) {
|
||||
ninet_unhash2(hashinfo, sk);
|
||||
ilb->count--;
|
||||
}
|
||||
__sk_nulls_del_node_init_rcu(sk);
|
||||
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
|
||||
|
||||
unlock:
|
||||
spin_unlock_bh(lock);
|
||||
}
|
||||
|
||||
/* Function
|
||||
* Find transport control blocks based on address and port in the ehash table.
|
||||
* If found, three handshakes have been made and a connection has been established,
|
||||
* and normal communication can proceed.
|
||||
* Parameter
|
||||
* net: The namespace
|
||||
* hashinfo: A global scalar of type tcp_hashinfo that stores tcp_SOCK(including ESTABLISHED,
|
||||
* listen, and bind) for various states of the current system.
|
||||
* saddr: Source address
|
||||
* sport: Source port
|
||||
* daddr: The destination address
|
||||
* hnum: Destination port
|
||||
*/
|
||||
struct sock *__ninet_lookup_established(struct net *net,
|
||||
struct inet_hashinfo *hashinfo,
|
||||
const struct nip_addr *saddr,
|
||||
const __be16 sport,
|
||||
const struct nip_addr *daddr,
|
||||
const u16 hnum,
|
||||
const int dif)
|
||||
{
|
||||
struct sock *sk;
|
||||
const struct hlist_nulls_node *node;
|
||||
|
||||
const __portpair ports = INET_COMBINED_PORTS(sport, hnum);
|
||||
|
||||
unsigned int hash = ninet_ehashfn(net, daddr, hnum, saddr, sport);
|
||||
unsigned int slot = hash & hashinfo->ehash_mask;
|
||||
|
||||
struct inet_ehash_bucket *head = &hashinfo->ehash[slot];
|
||||
|
||||
begin:
|
||||
sk_nulls_for_each_rcu(sk, node, &head->chain) {
|
||||
if (sk->sk_hash != hash)
|
||||
continue;
|
||||
if (!NINET_MATCH(sk, net, saddr, daddr, ports, dif))
|
||||
continue;
|
||||
if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) {
|
||||
nip_dbg("sk->sk_refcnt == 0");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(!NINET_MATCH(sk, net, saddr, daddr, ports, dif))) {
|
||||
sock_gen_put(sk);
|
||||
goto begin;
|
||||
}
|
||||
goto found;
|
||||
}
|
||||
if (get_nulls_value(node) != slot)
|
||||
goto begin;
|
||||
out:
|
||||
sk = NULL;
|
||||
found:
|
||||
return sk;
|
||||
}
|
||||
|
||||
static inline int nip_tcp_compute_score(struct sock *sk, struct net *net,
|
||||
const unsigned short hnum,
|
||||
const struct nip_addr *daddr,
|
||||
const int dif, int sdif)
|
||||
{
|
||||
int score = -1;
|
||||
|
||||
if (inet_sk(sk)->inet_num == hnum && sk->sk_family == PF_NINET &&
|
||||
net_eq(sock_net(sk), net)) {
|
||||
score = 1;
|
||||
if (!nip_addr_eq(&sk->sk_nip_rcv_saddr, &nip_any_addr)) {
|
||||
if (!nip_addr_eq(&sk->sk_nip_rcv_saddr, daddr))
|
||||
return -1;
|
||||
score++;
|
||||
}
|
||||
if (!inet_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif))
|
||||
return -1;
|
||||
score++;
|
||||
if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id())
|
||||
score++;
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
/* nip reuseport */
|
||||
static struct sock *ninet_lhash2_lookup(struct net *net,
|
||||
struct inet_listen_hashbucket *ilb2,
|
||||
struct sk_buff *skb, int doff,
|
||||
const struct nip_addr *saddr, __be16 sport,
|
||||
const struct nip_addr *daddr, const unsigned short hnum,
|
||||
const int dif, const int sdif)
|
||||
{
|
||||
struct inet_connection_sock *icsk;
|
||||
struct sock *sk;
|
||||
struct sock *result = NULL;
|
||||
int hiscore = 0;
|
||||
int matches = 0;
|
||||
int reuseport = 0;
|
||||
u32 phash = 0;
|
||||
|
||||
inet_lhash2_for_each_icsk_rcu(icsk, &ilb2->head) {
|
||||
int score;
|
||||
|
||||
sk = (struct sock *)icsk;
|
||||
score = nip_tcp_compute_score(sk, net, hnum, daddr, dif, sdif);
|
||||
if (score > hiscore) {
|
||||
nip_dbg("find sock in lhash table");
|
||||
result = sk;
|
||||
hiscore = score;
|
||||
reuseport = sk->sk_reuseport;
|
||||
if (reuseport) {
|
||||
nip_dbg("find reuseport sock in lhash table");
|
||||
phash = ninet_ehashfn(net, daddr, hnum, saddr, sport);
|
||||
matches = 1;
|
||||
}
|
||||
} else if (score == hiscore && reuseport) {
|
||||
matches++;
|
||||
if (reciprocal_scale(phash, matches) == 0)
|
||||
result = sk;
|
||||
phash = next_pseudo_random32(phash);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct sock *ninet_lookup_listener(struct net *net,
|
||||
struct inet_hashinfo *hashinfo,
|
||||
struct sk_buff *skb, int doff,
|
||||
const struct nip_addr *saddr,
|
||||
const __be16 sport, const struct nip_addr *daddr,
|
||||
const unsigned short hnum, const int dif, const int sdif)
|
||||
{
|
||||
struct inet_listen_hashbucket *ilb2;
|
||||
struct sock *result = NULL;
|
||||
unsigned int hash2 = nip_portaddr_hash(net, daddr, hnum);
|
||||
|
||||
ilb2 = inet_lhash2_bucket(hashinfo, hash2);
|
||||
|
||||
result = ninet_lhash2_lookup(net, ilb2, skb, doff,
|
||||
saddr, sport, daddr, hnum,
|
||||
dif, sdif);
|
||||
if (result)
|
||||
goto done;
|
||||
|
||||
hash2 = nip_portaddr_hash(net, &nip_any_addr, hnum);
|
||||
ilb2 = inet_lhash2_bucket(hashinfo, hash2);
|
||||
|
||||
result = ninet_lhash2_lookup(net, ilb2, skb, doff,
|
||||
saddr, sport, &nip_any_addr, hnum,
|
||||
dif, sdif);
|
||||
done:
|
||||
if (IS_ERR(result))
|
||||
return NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Check whether the quad information in sock is bound by ehash. If not,
|
||||
* the SK is inserted into the ehash and 0 is returned
|
||||
*/
|
||||
static int __ninet_check_established(struct inet_timewait_death_row *death_row,
|
||||
struct sock *sk, const __u16 lport,
|
||||
struct inet_timewait_sock **twp)
|
||||
{
|
||||
struct inet_hashinfo *hinfo = death_row->hashinfo;
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
struct nip_addr *daddr = &sk->sk_nip_rcv_saddr;
|
||||
struct nip_addr *saddr = &sk->sk_nip_daddr;
|
||||
int dif = sk->sk_bound_dev_if;
|
||||
struct net *net = sock_net(sk);
|
||||
const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport);
|
||||
unsigned int hash = ninet_ehashfn(net, daddr, lport,
|
||||
saddr, inet->inet_dport);
|
||||
struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
|
||||
spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
|
||||
struct sock *sk2;
|
||||
const struct hlist_nulls_node *node;
|
||||
|
||||
spin_lock(lock);
|
||||
|
||||
sk_nulls_for_each(sk2, node, &head->chain) {
|
||||
if (sk2->sk_hash != hash)
|
||||
continue;
|
||||
|
||||
if (likely(NINET_MATCH(sk2, net,
|
||||
saddr, daddr, ports, dif))) {
|
||||
nip_dbg("found same sk in ehash");
|
||||
goto not_unique;
|
||||
}
|
||||
}
|
||||
|
||||
/* Must record num and sport now. Otherwise we will see
|
||||
* in hash table socket with a funny identity.
|
||||
*/
|
||||
nip_dbg("add tcp sock into ehash table. sport=%u", lport);
|
||||
inet->inet_num = lport;
|
||||
inet->inet_sport = htons(lport);
|
||||
sk->sk_hash = hash;
|
||||
WARN_ON(!sk_unhashed(sk));
|
||||
__sk_nulls_add_node_rcu(sk, &head->chain);
|
||||
|
||||
spin_unlock(lock);
|
||||
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
|
||||
return 0;
|
||||
|
||||
not_unique:
|
||||
spin_unlock(lock);
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
static u64 ninet_sk_port_offset(const struct sock *sk)
|
||||
{
|
||||
const struct inet_sock *inet = inet_sk(sk);
|
||||
|
||||
return secure_newip_port_ephemeral(sk->sk_nip_rcv_saddr.nip_addr_field32,
|
||||
sk->sk_nip_daddr.nip_addr_field32,
|
||||
inet->inet_dport);
|
||||
}
|
||||
|
||||
/* Bind local ports randomly */
|
||||
int ninet_hash_connect(struct inet_timewait_death_row *death_row,
|
||||
struct sock *sk)
|
||||
{
|
||||
u64 port_offset = 0;
|
||||
|
||||
if (!inet_sk(sk)->inet_num)
|
||||
port_offset = ninet_sk_port_offset(sk);
|
||||
|
||||
return __inet_hash_connect(death_row, sk, port_offset,
|
||||
__ninet_check_established);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,906 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP Address [auto]configuration
|
||||
* Linux NewIP INET implementation
|
||||
*
|
||||
* Based on net/ipv6/addrconf.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/net.h>
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/route.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/hash.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/nip.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/ndisc.h>
|
||||
#include <net/nip_route.h>
|
||||
#include <net/nip_addrconf.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/pkt_sched.h>
|
||||
#include <net/addrconf.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "nip_hdr.h"
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
#define INFINITY_LIFE_TIME 0xFFFFFFFF
|
||||
|
||||
/* Configured unicast address hash table */
|
||||
static struct hlist_head ninet_addr_lst[NIN_ADDR_HSIZE];
|
||||
static DEFINE_SPINLOCK(addrconf_hash_lock);
|
||||
|
||||
static bool nip_chk_same_addr(struct net *net, const struct nip_addr *addr,
|
||||
const struct net_device *dev);
|
||||
static int nip_get_firstaddr(const struct net_device *dev,
|
||||
struct nip_addr *addr);
|
||||
static int nip_addrconf_ifdown(struct net_device *dev, bool unregister);
|
||||
|
||||
static struct nip_devconf newip_devconf_dflt __read_mostly = {
|
||||
.forwarding = 0,
|
||||
.mtu = NIP_MIN_MTU,
|
||||
.disable_nip = 0,
|
||||
.ignore_routes_with_linkdown = 0,
|
||||
};
|
||||
|
||||
/* Check if link is ready: is it up and is a valid qdisc available */
|
||||
static inline bool nip_addrconf_link_ready(const struct net_device *dev)
|
||||
{
|
||||
return netif_oper_up(dev) && !qdisc_tx_is_noop(dev);
|
||||
}
|
||||
|
||||
static void nip_link_dev_addr(struct ninet_dev *idev, struct ninet_ifaddr *ifp)
|
||||
{
|
||||
list_add_tail(&ifp->if_list, &idev->addr_list);
|
||||
}
|
||||
|
||||
static u32 ninet_addr_hash(const struct nip_addr *addr)
|
||||
{
|
||||
return hash_32(nip_addr_hash(addr), NIN_ADDR_HSIZE_SHIFT);
|
||||
}
|
||||
|
||||
static struct ninet_ifaddr *nip_add_addr(struct ninet_dev *idev,
|
||||
const struct nip_addr *addr,
|
||||
u32 flags, u32 valid_lft,
|
||||
u32 preferred_lft)
|
||||
{
|
||||
struct ninet_ifaddr *ifa = NULL;
|
||||
struct nip_rt_info *rt = NULL;
|
||||
unsigned int hash;
|
||||
int err = 0;
|
||||
|
||||
rcu_read_lock_bh();
|
||||
|
||||
nin_dev_hold(idev);
|
||||
|
||||
if (idev->dead) {
|
||||
err = -ENODEV;
|
||||
goto rcu_lock_out;
|
||||
}
|
||||
|
||||
if (idev->cnf.disable_nip) {
|
||||
err = -EACCES;
|
||||
goto rcu_lock_out;
|
||||
}
|
||||
|
||||
spin_lock(&addrconf_hash_lock);
|
||||
|
||||
/* Do not configure two same addresses in a netdevice */
|
||||
if (nip_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) {
|
||||
nip_dbg("already assigned");
|
||||
err = -EEXIST;
|
||||
goto spin_lock_out;
|
||||
}
|
||||
|
||||
ifa = kzalloc(sizeof(*ifa), GFP_ATOMIC);
|
||||
if (!ifa) {
|
||||
/* If you add log here, there will be an alarm:
|
||||
* WARNING: Possible unnecessary 'out of memory' message
|
||||
*/
|
||||
err = -ENOBUFS;
|
||||
goto spin_lock_out;
|
||||
}
|
||||
|
||||
rt = nip_addrconf_dst_alloc(idev, addr);
|
||||
if (IS_ERR(rt)) {
|
||||
err = PTR_ERR(rt);
|
||||
goto spin_lock_out;
|
||||
}
|
||||
|
||||
neigh_parms_data_state_setall(idev->nd_parms);
|
||||
|
||||
ifa->addr = *addr;
|
||||
|
||||
spin_lock_init(&ifa->lock);
|
||||
INIT_HLIST_NODE(&ifa->addr_lst);
|
||||
ifa->flags = flags;
|
||||
ifa->valid_lft = valid_lft;
|
||||
ifa->preferred_lft = preferred_lft;
|
||||
ifa->tstamp = jiffies;
|
||||
ifa->cstamp = ifa->tstamp;
|
||||
|
||||
ifa->rt = rt;
|
||||
|
||||
ifa->idev = idev;
|
||||
refcount_set(&ifa->refcnt, 1);
|
||||
|
||||
/* Add to big hash table */
|
||||
hash = ninet_addr_hash(addr);
|
||||
|
||||
hlist_add_head_rcu(&ifa->addr_lst, &ninet_addr_lst[hash]);
|
||||
spin_unlock(&addrconf_hash_lock);
|
||||
|
||||
write_lock(&idev->lock);
|
||||
/* Add to ninet_dev unicast addr list. */
|
||||
nip_link_dev_addr(idev, ifa);
|
||||
|
||||
nin_ifa_hold(ifa);
|
||||
write_unlock(&idev->lock);
|
||||
|
||||
rcu_lock_out:
|
||||
rcu_read_unlock_bh();
|
||||
|
||||
if (likely(err == 0)) {
|
||||
char add_addr[NIP_ADDR_BIT_LEN_MAX] = {0};
|
||||
|
||||
nip_addr_to_str(addr, add_addr, NIP_ADDR_BIT_LEN_MAX);
|
||||
nip_dbg("success, %s ifindex=%u (addr=%s, idev->refcnt=%u, ifa->refcnt=%u)",
|
||||
idev->dev->name, idev->dev->ifindex, add_addr,
|
||||
refcount_read(&idev->refcnt), refcount_read(&ifa->refcnt));
|
||||
} else {
|
||||
kfree(ifa);
|
||||
nin_dev_put(idev);
|
||||
ifa = ERR_PTR(err);
|
||||
}
|
||||
|
||||
return ifa;
|
||||
spin_lock_out:
|
||||
spin_unlock(&addrconf_hash_lock);
|
||||
goto rcu_lock_out;
|
||||
}
|
||||
|
||||
static struct ninet_dev *nip_add_dev(struct net_device *dev)
|
||||
{
|
||||
struct ninet_dev *ndev;
|
||||
int err = -ENOMEM;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (dev->mtu < NIP_MIN_MTU)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
ndev = kzalloc(sizeof(*ndev), GFP_KERNEL);
|
||||
if (!ndev)
|
||||
return ERR_PTR(err);
|
||||
|
||||
rwlock_init(&ndev->lock);
|
||||
ndev->dev = dev;
|
||||
INIT_LIST_HEAD(&ndev->addr_list);
|
||||
memcpy(&ndev->cnf, dev_net(dev)->newip.devconf_dflt, sizeof(ndev->cnf));
|
||||
|
||||
ndev->cnf.mtu = dev->mtu;
|
||||
ndev->nd_parms = neigh_parms_alloc(dev, &nnd_tbl);
|
||||
if (!ndev->nd_parms) {
|
||||
kfree(ndev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/* We refer to the device */
|
||||
dev_hold(dev);
|
||||
|
||||
refcount_set(&ndev->refcnt, 1);
|
||||
|
||||
nip_dbg("init ninet_dev success, set ndev->refcnt=1");
|
||||
|
||||
if (netif_running(dev) && nip_addrconf_link_ready(dev))
|
||||
ndev->if_flags |= IF_READY;
|
||||
|
||||
/* protected by rtnl_lock */
|
||||
rcu_assign_pointer(dev->nip_ptr, ndev);
|
||||
return ndev;
|
||||
}
|
||||
|
||||
static struct ninet_dev *nip_find_idev(struct net_device *dev)
|
||||
{
|
||||
struct ninet_dev *idev;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
idev = __nin_dev_get(dev);
|
||||
if (!idev) {
|
||||
idev = nip_add_dev(dev);
|
||||
if (IS_ERR(idev))
|
||||
return NULL;
|
||||
}
|
||||
return idev;
|
||||
}
|
||||
|
||||
static struct ninet_dev *nip_addrconf_add_dev(struct net_device *dev)
|
||||
{
|
||||
struct ninet_dev *idev;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
idev = nip_find_idev(dev);
|
||||
if (!idev)
|
||||
return ERR_PTR(-ENOBUFS);
|
||||
|
||||
if (idev->cnf.disable_nip)
|
||||
return ERR_PTR(-EACCES);
|
||||
|
||||
return idev;
|
||||
}
|
||||
|
||||
/* Manual configuration of address on an interface */
|
||||
static int ninet_addr_add(struct net *net, int ifindex,
|
||||
const struct nip_addr *pfx,
|
||||
__u32 ifa_flags, __u32 preferred_lft, __u32 valid_lft)
|
||||
{
|
||||
struct ninet_ifaddr *ifp;
|
||||
struct ninet_dev *idev;
|
||||
struct net_device *dev;
|
||||
unsigned long timeout;
|
||||
__u32 ifa_flags_tmp = ifa_flags;
|
||||
__u32 valid_lft_tmp = valid_lft;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
/* check the lifetime */
|
||||
if (!valid_lft_tmp || preferred_lft > valid_lft_tmp)
|
||||
return -EINVAL;
|
||||
|
||||
dev = __dev_get_by_index(net, ifindex);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
idev = nip_addrconf_add_dev(dev);
|
||||
if (IS_ERR(idev))
|
||||
return PTR_ERR(idev);
|
||||
|
||||
timeout = addrconf_timeout_fixup(valid_lft_tmp, HZ);
|
||||
if (addrconf_finite_timeout(timeout))
|
||||
valid_lft_tmp = timeout;
|
||||
else
|
||||
ifa_flags_tmp |= IFA_F_PERMANENT;
|
||||
|
||||
timeout = addrconf_timeout_fixup(preferred_lft, HZ);
|
||||
if (addrconf_finite_timeout(timeout)) {
|
||||
if (timeout == 0)
|
||||
ifa_flags_tmp |= IFA_F_DEPRECATED;
|
||||
preferred_lft = timeout;
|
||||
}
|
||||
|
||||
ifp = nip_add_addr(idev, pfx, ifa_flags_tmp,
|
||||
valid_lft_tmp,
|
||||
preferred_lft);
|
||||
if (!IS_ERR(ifp)) {
|
||||
nin_ifa_put(ifp);
|
||||
nip_ins_rt(ifp->rt);
|
||||
nip_dbg("success, ifp->refcnt=%u", refcount_read(&ifp->refcnt));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return PTR_ERR(ifp);
|
||||
}
|
||||
|
||||
/* Nobody refers to this ifaddr, destroy it */
|
||||
void ninet_ifa_finish_destroy(struct ninet_ifaddr *ifp)
|
||||
{
|
||||
WARN_ON(!hlist_unhashed(&ifp->addr_lst));
|
||||
|
||||
nip_dbg("before idev put. idev->refcnt=%u", refcount_read(&ifp->idev->refcnt));
|
||||
nin_dev_put(ifp->idev);
|
||||
nip_rt_put(ifp->rt);
|
||||
kfree_rcu(ifp, rcu);
|
||||
}
|
||||
|
||||
static void nip_del_addr(struct ninet_ifaddr *ifp)
|
||||
{
|
||||
int state;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
spin_lock_bh(&ifp->lock);
|
||||
state = ifp->state;
|
||||
ifp->state = NINET_IFADDR_STATE_DEAD;
|
||||
spin_unlock_bh(&ifp->lock);
|
||||
|
||||
if (state == NINET_IFADDR_STATE_DEAD)
|
||||
goto out;
|
||||
|
||||
spin_lock_bh(&addrconf_hash_lock);
|
||||
hlist_del_init_rcu(&ifp->addr_lst);
|
||||
spin_unlock_bh(&addrconf_hash_lock);
|
||||
|
||||
write_lock_bh(&ifp->idev->lock);
|
||||
|
||||
list_del_init(&ifp->if_list);
|
||||
__nin_ifa_put(ifp);
|
||||
|
||||
write_unlock_bh(&ifp->idev->lock);
|
||||
|
||||
if (ifp->rt) {
|
||||
/* If the ifp - & gt; Rt does not belong to any NIP_FIB_node.
|
||||
* The DST reference count does not change
|
||||
*/
|
||||
if (dst_hold_safe(&ifp->rt->dst))
|
||||
nip_del_rt(ifp->rt);
|
||||
}
|
||||
|
||||
out:
|
||||
nin_ifa_put(ifp);
|
||||
}
|
||||
|
||||
static int ninet_addr_del(struct net *net, int ifindex, u32 ifa_flags,
|
||||
const struct nip_addr *pfx)
|
||||
{
|
||||
struct ninet_ifaddr *ifp;
|
||||
struct ninet_dev *idev;
|
||||
struct net_device *dev;
|
||||
|
||||
dev = __dev_get_by_index(net, ifindex);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
idev = __nin_dev_get(dev);
|
||||
if (!idev)
|
||||
return -ENXIO;
|
||||
|
||||
read_lock_bh(&idev->lock);
|
||||
list_for_each_entry(ifp, &idev->addr_list, if_list) {
|
||||
if (nip_addr_eq(pfx, &ifp->addr)) {
|
||||
char addr[NIP_ADDR_BIT_LEN_MAX] = {0};
|
||||
|
||||
nin_ifa_hold(ifp);
|
||||
read_unlock_bh(&idev->lock);
|
||||
|
||||
nip_addr_to_str(&ifp->addr, addr, NIP_ADDR_BIT_LEN_MAX);
|
||||
nip_del_addr(ifp);
|
||||
nip_dbg("success, %s ifindex=%u (addr=%s, ifp->refcnt=%u, idev->refcnt=%u)",
|
||||
idev->dev->name, ifindex, addr, refcount_read(&ifp->refcnt),
|
||||
refcount_read(&idev->refcnt));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&idev->lock);
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
int nip_addrconf_ifaddr_check(struct net *net, void __user *arg, struct nip_ifreq *ireq)
|
||||
{
|
||||
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
|
||||
nip_dbg("not admin can`t cfg");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (copy_from_user(ireq, arg, sizeof(struct nip_ifreq))) {
|
||||
nip_dbg("fail to copy cfg data");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (nip_addr_invalid(&ireq->ifrn_addr)) {
|
||||
nip_dbg("nip addr invalid, bitlen=%u", ireq->ifrn_addr.bitlen);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (nip_addr_public(&ireq->ifrn_addr)) {
|
||||
nip_dbg("The public address cannot be configured");
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nip_addrconf_add_ifaddr(struct net *net, void __user *arg)
|
||||
{
|
||||
struct nip_ifreq ireq;
|
||||
int err;
|
||||
|
||||
err = nip_addrconf_ifaddr_check(net, arg, &ireq);
|
||||
if (err < 0) {
|
||||
nip_dbg("The ifaddr check failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = ninet_addr_add(net, ireq.ifrn_ifindex, &ireq.ifrn_addr,
|
||||
IFA_F_PERMANENT, INFINITY_LIFE_TIME,
|
||||
INFINITY_LIFE_TIME);
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
int nip_addrconf_del_ifaddr(struct net *net, void __user *arg)
|
||||
{
|
||||
struct nip_ifreq ireq;
|
||||
int err;
|
||||
|
||||
err = nip_addrconf_ifaddr_check(net, arg, &ireq);
|
||||
if (err < 0) {
|
||||
nip_dbg("The ifaddr check failed");
|
||||
return err;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
err = ninet_addr_del(net, ireq.ifrn_ifindex, 0, &ireq.ifrn_addr);
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool nip_chk_same_addr(struct net *net, const struct nip_addr *addr,
|
||||
const struct net_device *dev)
|
||||
{
|
||||
unsigned int hash = ninet_addr_hash(addr);
|
||||
struct ninet_ifaddr *ifp;
|
||||
|
||||
hlist_for_each_entry(ifp, &ninet_addr_lst[hash], addr_lst) {
|
||||
if (!net_eq(dev_net(ifp->idev->dev), net))
|
||||
continue;
|
||||
if (nip_addr_eq(&ifp->addr, addr)) {
|
||||
if (!dev || ifp->idev->dev == dev)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __nip_get_firstaddr(struct ninet_dev *idev, struct nip_addr *addr)
|
||||
{
|
||||
struct ninet_ifaddr *ifp;
|
||||
int err = -EADDRNOTAVAIL;
|
||||
|
||||
list_for_each_entry(ifp, &idev->addr_list, if_list) {
|
||||
*addr = ifp->addr;
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nip_get_firstaddr(const struct net_device *dev,
|
||||
struct nip_addr *addr)
|
||||
{
|
||||
struct ninet_dev *idev;
|
||||
int err = -EADDRNOTAVAIL;
|
||||
|
||||
rcu_read_lock();
|
||||
idev = __nin_dev_get(dev);
|
||||
if (idev) {
|
||||
read_lock_bh(&idev->lock);
|
||||
err = __nip_get_firstaddr(idev, addr);
|
||||
read_unlock_bh(&idev->lock);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
int nip_dev_get_saddr(struct net *net, const struct net_device *dev,
|
||||
const struct nip_addr *daddr, struct nip_addr *saddr)
|
||||
{
|
||||
if (!dev || !saddr)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
return nip_get_firstaddr(dev, saddr);
|
||||
}
|
||||
|
||||
static int nip_addrconf_notify(struct notifier_block *this, unsigned long event,
|
||||
void *ptr)
|
||||
{
|
||||
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
struct ninet_dev *idev = __nin_dev_get(dev);
|
||||
struct net *net = dev_net(dev);
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_REGISTER:
|
||||
if (!idev && dev->mtu >= NIP_MIN_MTU) {
|
||||
nip_dbg("NIP_ADDRCONF(NETDEV_REGISTER): ");
|
||||
idev = nip_add_dev(dev);
|
||||
if (IS_ERR(idev))
|
||||
return notifier_from_errno(PTR_ERR(idev));
|
||||
}
|
||||
break;
|
||||
|
||||
case NETDEV_CHANGEMTU:
|
||||
/* if MTU under NIP_MIN_MTU stop New IP on this interface. */
|
||||
if (dev->mtu < NIP_MIN_MTU) {
|
||||
nip_addrconf_ifdown(dev, dev != net->loopback_dev);
|
||||
break;
|
||||
}
|
||||
|
||||
if (idev) {
|
||||
idev->cnf.mtu = dev->mtu;
|
||||
break;
|
||||
}
|
||||
|
||||
/* allocate new idev */
|
||||
idev = nip_add_dev(dev);
|
||||
if (IS_ERR(idev))
|
||||
break;
|
||||
|
||||
/* device is still not ready */
|
||||
if (!(idev->if_flags & IF_READY))
|
||||
break;
|
||||
|
||||
fallthrough;
|
||||
case NETDEV_UP:
|
||||
case NETDEV_CHANGE:
|
||||
if (dev->flags & IFF_SLAVE)
|
||||
break;
|
||||
|
||||
if (idev && idev->cnf.disable_nip)
|
||||
break;
|
||||
|
||||
if (event == NETDEV_UP) {
|
||||
if (!nip_addrconf_link_ready(dev)) {
|
||||
/* device is not ready yet. */
|
||||
nip_dbg("NIP_ADDRCONF(NETDEV_UP)");
|
||||
nip_dbg("%s:link is not ready", dev->name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!idev && dev->mtu >= NIP_MIN_MTU)
|
||||
idev = nip_add_dev(dev);
|
||||
|
||||
if (!IS_ERR_OR_NULL(idev))
|
||||
idev->if_flags |= IF_READY;
|
||||
} else if (event == NETDEV_CHANGE) {
|
||||
if (!nip_addrconf_link_ready(dev))
|
||||
/* device is still not ready. */
|
||||
break;
|
||||
|
||||
if (idev)
|
||||
idev->if_flags |= IF_READY;
|
||||
|
||||
nip_dbg("NIP_ADDRCONF(NETDEV_CHANGE)");
|
||||
nip_dbg("%s:link becomes ready", dev->name);
|
||||
}
|
||||
|
||||
if (!IS_ERR_OR_NULL(idev)) {
|
||||
/* If the MTU changed during the interface down,
|
||||
* when the interface up, the changed MTU must be
|
||||
* reflected in the idev as well as routers.
|
||||
*/
|
||||
if (idev->cnf.mtu != dev->mtu && dev->mtu >= NIP_MIN_MTU)
|
||||
idev->cnf.mtu = dev->mtu;
|
||||
idev->tstamp = jiffies;
|
||||
|
||||
/* If the changed mtu during down is lower than
|
||||
* NIP_MIN_MTU stop New IP on this interface.
|
||||
*/
|
||||
if (dev->mtu < NIP_MIN_MTU)
|
||||
nip_addrconf_ifdown(dev, dev != net->loopback_dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case NETDEV_DOWN:
|
||||
case NETDEV_UNREGISTER:
|
||||
/* Remove all addresses from this interface. */
|
||||
nip_addrconf_ifdown(dev, event != NETDEV_DOWN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int nip_addrconf_ifdown(struct net_device *dev, bool unregister)
|
||||
{
|
||||
struct net *net = dev_net(dev);
|
||||
struct ninet_dev *idev = __nin_dev_get(dev);
|
||||
struct ninet_ifaddr *ifa, *tmp;
|
||||
struct list_head del_list;
|
||||
int i;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
nip_dbg("%s ifindex=%u, unregister=%u (unregister:1, down:0)",
|
||||
dev->name, dev->ifindex, unregister);
|
||||
|
||||
nip_rt_ifdown(net, dev);
|
||||
neigh_ifdown(&nnd_tbl, dev);
|
||||
if (!idev)
|
||||
return -ENODEV;
|
||||
|
||||
/* Step 1: remove reference to newip device from parent device.
|
||||
* Do not dev_put!
|
||||
*/
|
||||
if (unregister) {
|
||||
idev->dead = 1;
|
||||
|
||||
/* protected by rtnl_lock */
|
||||
RCU_INIT_POINTER(dev->nip_ptr, NULL);
|
||||
}
|
||||
|
||||
/* Step 2: clear hash table */
|
||||
for (i = 0; i < NIN_ADDR_HSIZE; i++) {
|
||||
struct hlist_head *h = &ninet_addr_lst[i];
|
||||
|
||||
spin_lock_bh(&addrconf_hash_lock);
|
||||
hlist_for_each_entry_rcu(ifa, h, addr_lst) {
|
||||
if (ifa->idev == idev) {
|
||||
char addr[NIP_ADDR_BIT_LEN_MAX] = {0};
|
||||
|
||||
nip_addr_to_str(&ifa->addr, addr, NIP_ADDR_BIT_LEN_MAX);
|
||||
nip_dbg("clear addr hash table.(addr=%s)", addr);
|
||||
hlist_del_init_rcu(&ifa->addr_lst);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&addrconf_hash_lock);
|
||||
}
|
||||
|
||||
write_lock_bh(&idev->lock);
|
||||
|
||||
/* Step 2: clear flags for stateless addrconf */
|
||||
if (!unregister)
|
||||
idev->if_flags &= ~(IF_RS_SENT | IF_RA_RCVD | IF_READY);
|
||||
|
||||
/* Step 3: Remove address node from ifa->if_list
|
||||
* and insert it into the list to be del_list
|
||||
*/
|
||||
INIT_LIST_HEAD(&del_list);
|
||||
list_for_each_entry_safe(ifa, tmp, &idev->addr_list, if_list) {
|
||||
list_move(&ifa->if_list, &del_list);
|
||||
|
||||
write_unlock_bh(&idev->lock);
|
||||
spin_lock_bh(&ifa->lock);
|
||||
ifa->state = NINET_IFADDR_STATE_DEAD;
|
||||
spin_unlock_bh(&ifa->lock);
|
||||
write_lock_bh(&idev->lock);
|
||||
}
|
||||
write_unlock_bh(&idev->lock);
|
||||
|
||||
/* Step 4: Unchain the node to be deleted and release IFA */
|
||||
while (!list_empty(&del_list)) {
|
||||
ifa = list_first_entry(&del_list, struct ninet_ifaddr, if_list);
|
||||
list_del(&ifa->if_list);
|
||||
nin_ifa_put(ifa);
|
||||
}
|
||||
|
||||
/* Last: Shot the device (if unregistered) */
|
||||
if (unregister) {
|
||||
neigh_parms_release(&nnd_tbl, idev->nd_parms);
|
||||
neigh_ifdown(&nnd_tbl, dev);
|
||||
nip_dbg("%s (ifindex=%u) before idev put. idev->refcnt=%u",
|
||||
dev->name, dev->ifindex, refcount_read(&idev->refcnt));
|
||||
nin_dev_put(idev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nip_addr_proc_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct net *net = seq->private;
|
||||
struct ninet_ifaddr *ifp;
|
||||
int i, j;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < NIN_ADDR_HSIZE; i++)
|
||||
hlist_for_each_entry_rcu(ifp, &ninet_addr_lst[i], addr_lst) {
|
||||
if (!net_eq(dev_net(ifp->idev->dev), net))
|
||||
continue;
|
||||
|
||||
for (j = 0; j < ifp->addr.bitlen / NIP_ADDR_BIT_LEN_8; j++)
|
||||
seq_printf(seq, "%02x", ifp->addr.nip_addr_field8[j]);
|
||||
seq_printf(seq, "\t%8s\n", ifp->idev->dev ? ifp->idev->dev->name : "");
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __net_init nip_addr_net_init(struct net *net)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
struct nip_devconf *dflt;
|
||||
|
||||
dflt = kmemdup(&newip_devconf_dflt,
|
||||
sizeof(newip_devconf_dflt),
|
||||
GFP_KERNEL);
|
||||
if (!dflt)
|
||||
goto err_alloc_dflt;
|
||||
|
||||
net->newip.devconf_dflt = dflt;
|
||||
|
||||
if (!proc_create_net_single("nip_addr", 0444, net->proc_net,
|
||||
nip_addr_proc_show, NULL)) {
|
||||
goto err_addr_proc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_addr_proc:
|
||||
kfree(dflt);
|
||||
err_alloc_dflt:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __net_exit nip_addr_net_exit(struct net *net)
|
||||
{
|
||||
kfree(net->newip.devconf_dflt);
|
||||
remove_proc_entry("nip_addr", net->proc_net);
|
||||
}
|
||||
|
||||
static struct pernet_operations nip_route_proc_net_ops = {
|
||||
.init = nip_addr_net_init,
|
||||
.exit = nip_addr_net_exit,
|
||||
};
|
||||
|
||||
/* addrconf module should be notified of a device going up
|
||||
*/
|
||||
static struct notifier_block nip_dev_notf = {
|
||||
.notifier_call = nip_addrconf_notify,
|
||||
.priority = ADDRCONF_NOTIFY_PRIORITY,
|
||||
};
|
||||
|
||||
int __init nip_addrconf_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = register_pernet_subsys(&nip_route_proc_net_ops);
|
||||
if (err < 0) {
|
||||
nip_dbg("register_pernet_subsys failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
register_netdevice_notifier(&nip_dev_notf);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
void nip_addrconf_cleanup(void)
|
||||
{
|
||||
struct net_device *dev;
|
||||
int i;
|
||||
|
||||
unregister_netdevice_notifier(&nip_dev_notf);
|
||||
unregister_pernet_subsys(&nip_route_proc_net_ops);
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
/* clean dev list */
|
||||
for_each_netdev(&init_net, dev) {
|
||||
if (!__nin_dev_get(dev))
|
||||
continue;
|
||||
nip_addrconf_ifdown(dev, 1);
|
||||
}
|
||||
|
||||
/* Check hash table. */
|
||||
spin_lock_bh(&addrconf_hash_lock);
|
||||
for (i = 0; i < NIN_ADDR_HSIZE; i++)
|
||||
WARN_ON(!hlist_empty(&ninet_addr_lst[i]));
|
||||
spin_unlock_bh(&addrconf_hash_lock);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static int ninet_addr_get(const struct net_device *dev, struct ninet_ifaddr *ifa)
|
||||
{
|
||||
int err;
|
||||
struct nip_addr addr;
|
||||
|
||||
err = nip_get_firstaddr(dev, &addr);
|
||||
if (!err)
|
||||
ifa->addr = addr;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int nip_addrconf_get_ifaddr(struct net *net, unsigned int cmd, void __user *arg)
|
||||
{
|
||||
struct nip_devreq ifr;
|
||||
struct sockaddr_nin *snin;
|
||||
struct ninet_ifaddr ifa;
|
||||
struct net_device *dev;
|
||||
void __user *p = (void __user *)arg;
|
||||
int ret = -EFAULT;
|
||||
|
||||
if (copy_from_user(&ifr, p, sizeof(struct nip_ifreq)))
|
||||
goto out;
|
||||
|
||||
ifr.nip_ifr_name[IFNAMSIZ - 1] = 0;
|
||||
snin = (struct sockaddr_nin *)&ifr.nip_dev_addr;
|
||||
|
||||
nip_dbg("dev name is %s", ifr.nip_ifr_name);
|
||||
dev_load(net, ifr.nip_ifr_name);
|
||||
|
||||
if (cmd == SIOCGIFADDR) {
|
||||
memset(snin, 0, sizeof(*snin));
|
||||
snin->sin_family = AF_NINET;
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
dev = __dev_get_by_name(net, ifr.nip_ifr_name);
|
||||
if (!dev)
|
||||
goto done;
|
||||
|
||||
ret = ninet_addr_get(dev, &ifa);
|
||||
if (ret)
|
||||
goto done;
|
||||
/* Get interface address */
|
||||
snin->sin_addr = ifa.addr;
|
||||
|
||||
if (copy_to_user(p, &ifr, sizeof(struct nip_devreq)))
|
||||
ret = -EFAULT;
|
||||
|
||||
done:
|
||||
rtnl_unlock();
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nip_addr_to_str(const struct nip_addr *addr, unsigned char *buf, int buf_len)
|
||||
{
|
||||
int i;
|
||||
int total_len = 0;
|
||||
int addr_num = addr->bitlen / NIP_ADDR_BIT_LEN_8;
|
||||
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
total_len = sprintf(buf, "%s", "0x");
|
||||
for (i = 0; (i < addr_num) && (total_len < buf_len); i++) {
|
||||
int len = sprintf(buf + total_len, "%02x", addr->nip_addr_field8[i]);
|
||||
|
||||
if (len <= 0)
|
||||
break;
|
||||
total_len += len;
|
||||
}
|
||||
|
||||
switch (addr_num) {
|
||||
case NIP_ADDR_LEN_1:
|
||||
buf[INDEX_2] = '*'; /* 0x*0 ~ 0x*C */
|
||||
break;
|
||||
case NIP_ADDR_LEN_2:
|
||||
buf[INDEX_2] = '*'; /* 0x**DD ~ 0x**FF */
|
||||
buf[INDEX_3] = '*';
|
||||
break;
|
||||
case NIP_ADDR_LEN_3:
|
||||
buf[INDEX_4] = '*'; /* 0xF1**00 ~ 0xF1**FF */
|
||||
buf[INDEX_5] = '*';
|
||||
break;
|
||||
case NIP_ADDR_LEN_5:
|
||||
buf[INDEX_4] = '*'; /* 0xF2 **** 0000 ~ 0xF2 **** FFFF */
|
||||
buf[INDEX_5] = '*';
|
||||
buf[INDEX_6] = '*';
|
||||
buf[INDEX_7] = '*';
|
||||
break;
|
||||
case NIP_ADDR_LEN_7:
|
||||
buf[INDEX_4] = '*'; /* 0xF3 **** 0000 0000 ~ 0xF3 **** FFFF FFFF */
|
||||
buf[INDEX_5] = '*';
|
||||
buf[INDEX_6] = '*';
|
||||
buf[INDEX_7] = '*';
|
||||
break;
|
||||
case NIP_ADDR_LEN_8:
|
||||
buf[INDEX_4] = '*'; /* 0xF4** **** 0000 0000 ~ 0xF4** **** FFFF FFFF */
|
||||
buf[INDEX_5] = '*';
|
||||
buf[INDEX_6] = '*';
|
||||
buf[INDEX_7] = '*';
|
||||
buf[INDEX_8] = '*';
|
||||
buf[INDEX_9] = '*';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP library code, needed by static components when full NewIP support is
|
||||
* not configured or static.
|
||||
*
|
||||
* Based on net/ipv6/addrconf_core.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <net/nip.h>
|
||||
#include <net/nip_addrconf.h>
|
||||
#include <net/ip.h>
|
||||
#include <linux/export.h>
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
static void nin_dev_finish_destroy_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct ninet_dev *idev = container_of(head, struct ninet_dev, rcu);
|
||||
|
||||
kfree(idev);
|
||||
}
|
||||
|
||||
void nin_dev_finish_destroy(struct ninet_dev *idev)
|
||||
{
|
||||
struct net_device *dev = idev->dev;
|
||||
|
||||
WARN_ON(!list_empty(&idev->addr_list));
|
||||
|
||||
dev_put(dev);
|
||||
if (idev->dead)
|
||||
call_rcu(&idev->rcu, nin_dev_finish_destroy_rcu);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Linux NewIP INET implementation
|
||||
* Forwarding Information Database
|
||||
*
|
||||
* Based on net/ipv6/ip6_fib.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/route.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include <net/nip.h>
|
||||
#include <net/ndisc.h>
|
||||
#include <net/addrconf.h>
|
||||
|
||||
#include <net/nip_fib.h>
|
||||
#include <net/nip_route.h>
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
static struct kmem_cache *nip_fib_node_kmem __read_mostly;
|
||||
|
||||
struct nip_fib_table *nip_fib_get_table(struct net *net, u32 id)
|
||||
{
|
||||
if (id == NIP_RT_TABLE_MAIN)
|
||||
return net->newip.nip_fib_main_tbl;
|
||||
else if (id == NIP_RT_TABLE_LOCAL)
|
||||
return net->newip.nip_fib_local_tbl;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nip_fib_node *nip_node_alloc(void)
|
||||
{
|
||||
struct nip_fib_node *fn;
|
||||
|
||||
fn = kmem_cache_zalloc(nip_fib_node_kmem, GFP_ATOMIC);
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
void nip_rt_free_pcpu(struct nip_rt_info *non_pcpu_rt)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
if (!non_pcpu_rt->rt_pcpu)
|
||||
return;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct nip_rt_info **ppcpu_rt;
|
||||
struct nip_rt_info *pcpu_rt;
|
||||
|
||||
ppcpu_rt = per_cpu_ptr(non_pcpu_rt->rt_pcpu, cpu);
|
||||
pcpu_rt = *ppcpu_rt;
|
||||
if (pcpu_rt) {
|
||||
dst_dev_put(&pcpu_rt->dst);
|
||||
dst_release(&pcpu_rt->dst);
|
||||
*ppcpu_rt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free_percpu(non_pcpu_rt->rt_pcpu);
|
||||
non_pcpu_rt->rt_pcpu = NULL;
|
||||
}
|
||||
|
||||
static u32 ninet_route_hash(const struct nip_addr *addr)
|
||||
{
|
||||
return hash_32(nip_addr_hash(addr), NIN_ROUTE_HSIZE_SHIFT);
|
||||
}
|
||||
|
||||
struct nip_fib_node *nip_fib_locate(struct hlist_head *nip_tb_head,
|
||||
const struct nip_addr *daddr)
|
||||
{
|
||||
struct nip_fib_node *fib_node;
|
||||
struct hlist_head *h;
|
||||
unsigned int hash;
|
||||
|
||||
hash = ninet_route_hash(daddr);
|
||||
h = &nip_tb_head[hash];
|
||||
|
||||
hlist_for_each_entry_rcu(fib_node, h, fib_hlist) {
|
||||
if (nip_addr_eq(&fib_node->nip_route_info->rt_dst, daddr))
|
||||
return fib_node;
|
||||
}
|
||||
|
||||
/* find default route */
|
||||
hash = ninet_route_hash(&nip_any_addr);
|
||||
h = &nip_tb_head[hash];
|
||||
|
||||
hlist_for_each_entry_rcu(fib_node, h, fib_hlist) {
|
||||
if (nip_addr_eq(&fib_node->nip_route_info->rt_dst, &nip_any_addr))
|
||||
return fib_node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* nip_tb_lock must be taken to avoid racing */
|
||||
int nip_fib_add(struct nip_fib_table *table, struct nip_rt_info *rt)
|
||||
{
|
||||
struct nip_fib_node *fib_node, *new_node;
|
||||
int err = 0;
|
||||
struct hlist_head *h;
|
||||
unsigned int hash;
|
||||
char dst[NIP_ADDR_BIT_LEN_MAX] = {0};
|
||||
char gateway[NIP_ADDR_BIT_LEN_MAX] = {0};
|
||||
|
||||
hash = ninet_route_hash(&rt->rt_dst);
|
||||
h = &table->nip_tb_head[hash];
|
||||
|
||||
hlist_for_each_entry(fib_node, h, fib_hlist) {
|
||||
if (table->nip_tb_id == NIP_RT_TABLE_MAIN) {
|
||||
if (nip_addr_eq(&fib_node->nip_route_info->rt_dst,
|
||||
&rt->rt_dst)) {
|
||||
err = -EEXIST;
|
||||
goto fail;
|
||||
}
|
||||
} else if (table->nip_tb_id == NIP_RT_TABLE_LOCAL) {
|
||||
if (nip_addr_and_ifindex_eq
|
||||
(&fib_node->nip_route_info->rt_dst, &rt->rt_dst,
|
||||
fib_node->nip_route_info->rt_idev->dev->ifindex,
|
||||
rt->rt_idev->dev->ifindex)) {
|
||||
err = -EEXIST;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_node = nip_node_alloc();
|
||||
if (!new_node) {
|
||||
nip_dbg("fail to alloc mem");
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
new_node->nip_route_info = rt;
|
||||
rcu_assign_pointer(rt->rt_node, new_node);
|
||||
atomic_inc(&rt->rt_ref);
|
||||
hlist_add_tail_rcu(&new_node->fib_hlist, h);
|
||||
nip_addr_to_str(&rt->rt_dst, dst, NIP_ADDR_BIT_LEN_MAX);
|
||||
nip_addr_to_str(&rt->gateway, gateway, NIP_ADDR_BIT_LEN_MAX);
|
||||
nip_dbg("%s ifindex=%u (addr=%s, gateway=%s, rt_idev->refcnt=%u)",
|
||||
rt->rt_idev->dev->name, rt->rt_idev->dev->ifindex,
|
||||
dst, gateway, refcount_read(&rt->rt_idev->refcnt));
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
fail:
|
||||
dst_release_immediate(&rt->dst);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void nip_fib_destroy_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct nip_fib_node *fn = container_of(head, struct nip_fib_node, rcu);
|
||||
|
||||
nip_rt_release(fn->nip_route_info);
|
||||
kfree(fn);
|
||||
}
|
||||
|
||||
/* nip_tb_lock must be taken to avoid racing */
|
||||
int nip_fib_del(struct nip_rt_info *rt, struct nl_info *info)
|
||||
{
|
||||
struct nip_fib_node *fn;
|
||||
struct net *net = info->nl_net;
|
||||
|
||||
fn = rcu_dereference_protected(rt->rt_node,
|
||||
lockdep_is_held(&rt->rt_table->nip_tb_lock));
|
||||
if (!fn || rt == net->newip.nip_null_entry)
|
||||
return -ENOENT;
|
||||
|
||||
hlist_del_init_rcu(&fn->fib_hlist);
|
||||
|
||||
/* route_info directed by the fib_node can be released
|
||||
* only after the fib_node is released
|
||||
*/
|
||||
RCU_INIT_POINTER(rt->rt_node, NULL);
|
||||
call_rcu(&fn->rcu, nip_fib_destroy_rcu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nip_fib_free_table(struct nip_fib_table *table)
|
||||
{
|
||||
kfree(table);
|
||||
}
|
||||
|
||||
/* caller must hold nip_tb_lock */
|
||||
static void nip_fib_clean_hash(struct net *net, struct hlist_head *nip_tb_head,
|
||||
int (*func)(struct nip_rt_info *, void *arg),
|
||||
void *arg)
|
||||
{
|
||||
int i;
|
||||
int err;
|
||||
struct nip_fib_node *fn;
|
||||
struct hlist_node *tmp;
|
||||
struct nl_info info = {
|
||||
.nl_net = net,
|
||||
};
|
||||
|
||||
for (i = 0; i < NIN_ROUTE_HSIZE; i++) {
|
||||
struct hlist_head *h = &nip_tb_head[i];
|
||||
|
||||
hlist_for_each_entry_safe(fn, tmp, h, fib_hlist) {
|
||||
if (func(fn->nip_route_info, arg) < 0) {
|
||||
char dst[NIP_ADDR_BIT_LEN_MAX] = {0};
|
||||
char gateway[NIP_ADDR_BIT_LEN_MAX] = {0};
|
||||
|
||||
nip_addr_to_str(&fn->nip_route_info->rt_dst, dst,
|
||||
NIP_ADDR_BIT_LEN_MAX);
|
||||
nip_addr_to_str(&fn->nip_route_info->gateway, gateway,
|
||||
NIP_ADDR_BIT_LEN_MAX);
|
||||
|
||||
nip_dbg("try to del rt_info, rt_dst=%s, gateway=%s", dst, gateway);
|
||||
err = nip_fib_del(fn->nip_route_info, &info);
|
||||
if (err)
|
||||
nip_dbg("nip_fib_del failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nip_fib_clean_all(struct net *net,
|
||||
int (*func)(struct nip_rt_info *, void *arg), void *arg)
|
||||
{
|
||||
struct nip_fib_table *main_tbl = net->newip.nip_fib_main_tbl;
|
||||
struct nip_fib_table *local_tbl = net->newip.nip_fib_local_tbl;
|
||||
|
||||
spin_lock_bh(&main_tbl->nip_tb_lock);
|
||||
nip_fib_clean_hash(net, main_tbl->nip_tb_head, func, arg);
|
||||
spin_unlock_bh(&main_tbl->nip_tb_lock);
|
||||
|
||||
spin_lock_bh(&local_tbl->nip_tb_lock);
|
||||
nip_fib_clean_hash(net, local_tbl->nip_tb_head, func, arg);
|
||||
spin_unlock_bh(&local_tbl->nip_tb_lock);
|
||||
}
|
||||
|
||||
static void nip_fib_link_table(struct nip_fib_table *tb)
|
||||
{
|
||||
/* You need to initialize multiple routing tables */
|
||||
spin_lock_init(&tb->nip_tb_lock);
|
||||
}
|
||||
|
||||
static void __net_init nip_fib_tables_init(struct net *net)
|
||||
{
|
||||
nip_fib_link_table(net->newip.nip_fib_main_tbl);
|
||||
nip_fib_link_table(net->newip.nip_fib_local_tbl);
|
||||
}
|
||||
|
||||
static int __net_init nip_fib_net_init(struct net *net)
|
||||
{
|
||||
net->newip.nip_fib_main_tbl =
|
||||
kzalloc(sizeof(*net->newip.nip_fib_main_tbl), GFP_KERNEL);
|
||||
if (!net->newip.nip_fib_main_tbl)
|
||||
goto out_fib_table_hash;
|
||||
|
||||
net->newip.nip_fib_main_tbl->nip_tb_id = NIP_RT_TABLE_MAIN;
|
||||
net->newip.nip_fib_main_tbl->flags = 1;
|
||||
|
||||
net->newip.nip_fib_local_tbl =
|
||||
kzalloc(sizeof(*net->newip.nip_fib_local_tbl), GFP_KERNEL);
|
||||
if (!net->newip.nip_fib_local_tbl)
|
||||
goto out_main_tbl;
|
||||
|
||||
net->newip.nip_fib_local_tbl->nip_tb_id = NIP_RT_TABLE_LOCAL;
|
||||
|
||||
nip_fib_tables_init(net);
|
||||
|
||||
return 0;
|
||||
|
||||
out_main_tbl:
|
||||
kfree(net->newip.nip_fib_main_tbl);
|
||||
out_fib_table_hash:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void nip_fib_net_exit(struct net *net)
|
||||
{
|
||||
nip_fib_free_table(net->newip.nip_fib_main_tbl);
|
||||
nip_fib_free_table(net->newip.nip_fib_local_tbl);
|
||||
}
|
||||
|
||||
static struct pernet_operations nip_fib_net_ops = {
|
||||
.init = nip_fib_net_init,
|
||||
.exit = nip_fib_net_exit,
|
||||
};
|
||||
|
||||
int __init nip_fib_init(void)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
|
||||
nip_fib_node_kmem = kmem_cache_create("nip_fib_nodes",
|
||||
sizeof(struct nip_fib_node),
|
||||
0, SLAB_HWCACHE_ALIGN, NULL);
|
||||
if (!nip_fib_node_kmem)
|
||||
goto out;
|
||||
|
||||
nip_dbg("nip_fib_node size is %lu",
|
||||
sizeof(struct nip_fib_node) + sizeof(struct nip_rt_info));
|
||||
|
||||
ret = register_pernet_subsys(&nip_fib_net_ops);
|
||||
if (ret)
|
||||
goto out_kmem_cache_create;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
|
||||
out_kmem_cache_create:
|
||||
kmem_cache_destroy(nip_fib_node_kmem);
|
||||
goto out;
|
||||
}
|
||||
|
||||
void nip_fib_gc_cleanup(void)
|
||||
{
|
||||
unregister_pernet_subsys(&nip_fib_net_ops);
|
||||
kmem_cache_destroy(nip_fib_node_kmem);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP Routing Policy Rules
|
||||
*
|
||||
* Based on net/ipv6/fib_rules.c
|
||||
* Based on net/ipv6/fib6_rules.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <net/nip_fib.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/export.h>
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
struct dst_entry *nip_fib_rule_lookup(struct net *net, struct flow_nip *fln,
|
||||
int flags, int *tbl_type, nip_pol_lookup_t lookup)
|
||||
{
|
||||
struct nip_rt_info *rt;
|
||||
|
||||
rt = lookup(net, net->newip.nip_fib_local_tbl, fln, flags);
|
||||
if (rt != net->newip.nip_null_entry) {
|
||||
*tbl_type = (int)RT_TABLE_LOCAL;
|
||||
return &rt->dst;
|
||||
}
|
||||
nip_rt_put(rt);
|
||||
rt = lookup(net, net->newip.nip_fib_main_tbl, fln, flags);
|
||||
if (rt != net->newip.nip_null_entry) {
|
||||
*tbl_type = (int)RT_TABLE_MAIN;
|
||||
return &rt->dst;
|
||||
}
|
||||
nip_rt_put(rt);
|
||||
|
||||
dst_hold(&net->newip.nip_null_entry->dst);
|
||||
*tbl_type = (int)RT_TABLE_MAX;
|
||||
return &net->newip.nip_null_entry->dst;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Definitions for the NewIP Hooks Register module.
|
||||
*/
|
||||
#ifdef CONFIG_NEWIP_HOOKS
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <net/ninet_hashtables.h> /* ninet_ehashfn */
|
||||
#include <net/if_ninet.h>
|
||||
#include <trace/hooks/inet.h>
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
void vendor_ninet_ehashfn(void *data, const struct sock *sk, u32 *ret)
|
||||
{
|
||||
*ret = ninet_ehashfn(sock_net(sk), &sk->sk_nip_rcv_saddr,
|
||||
sk->sk_num, &sk->sk_nip_daddr, sk->sk_dport);
|
||||
}
|
||||
|
||||
void vendor_ninet_gifconf(void *data, struct net_device *dev,
|
||||
char __user *buf, int len, int size, int *ret)
|
||||
{
|
||||
if (*ret >= 0) {
|
||||
int done = ninet_gifconf(dev, buf + *ret, len - *ret, size);
|
||||
|
||||
if (done < 0)
|
||||
*ret = done;
|
||||
else
|
||||
*ret += done;
|
||||
}
|
||||
}
|
||||
|
||||
int ninet_hooks_register(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = register_trace_vendor_ninet_ehashfn(&vendor_ninet_ehashfn, NULL);
|
||||
if (ret) {
|
||||
nip_dbg("failed to register to vendor_ninet_ehashfn");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = register_trace_vendor_ninet_gifconf(&vendor_ninet_gifconf, NULL);
|
||||
if (ret) {
|
||||
nip_dbg("failed to register to vendor_ninet_gifconf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NEWIP_HOOKS */
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Definitions for the NewIP Hooks Register module.
|
||||
*/
|
||||
#ifndef _NIP_HOOKS_REGISTER_H
|
||||
#define _NIP_HOOKS_REGISTER_H
|
||||
|
||||
#ifdef CONFIG_NEWIP_HOOKS
|
||||
int ninet_hooks_register(void);
|
||||
#endif
|
||||
|
||||
#endif /* _NIP_HOOKS_REGISTER_H */
|
||||
@@ -0,0 +1,160 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP input
|
||||
* Linux NewIP INET implementation
|
||||
*
|
||||
* Based on net/ipv6/ip6_input.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/nip.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/dst_metadata.h>
|
||||
#include <net/transp_nip.h>
|
||||
#include <net/nip_route.h>
|
||||
#include <net/nip.h>
|
||||
|
||||
#include "nip_hdr.h"
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
static int _nip_update_recv_skb_len(struct sk_buff *skb,
|
||||
struct nip_hdr_decap *niph)
|
||||
{
|
||||
if (!niph->include_total_len)
|
||||
return 0;
|
||||
|
||||
if (niph->total_len > skb->len) {
|
||||
nip_dbg("total_len(%u) is bigger than skb_len(%u), Drop a packet",
|
||||
niph->total_len, skb->len);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
/* At present, NewIP only uses linear regions, uses skb_trim to remove end from a buffer;
|
||||
* If the nonlinear region is also used later, use pskb_trim to remove end from a buffer;
|
||||
*/
|
||||
skb_trim(skb, niph->total_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nip_rcv_finish(struct sk_buff *skb)
|
||||
{
|
||||
struct net *net = dev_net(skb->dev);
|
||||
void (*edemux)(struct sk_buff *skb) = NULL;
|
||||
int err = 0;
|
||||
|
||||
/* set /proc/sys/net/ipv4/ip_early_demux to change sysctl_ip_early_demux,
|
||||
* which is used by ipv4, ipv6 and newip
|
||||
*/
|
||||
if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && !skb->sk) {
|
||||
const struct ninet_protocol *ipprot;
|
||||
|
||||
nip_dbg("try to early demux skb, nexthdr=0x%x", NIPCB(skb)->nexthdr);
|
||||
ipprot = rcu_dereference(ninet_protos[NIPCB(skb)->nexthdr]);
|
||||
if (ipprot)
|
||||
edemux = READ_ONCE(ipprot->early_demux);
|
||||
if (edemux)
|
||||
edemux(skb);
|
||||
}
|
||||
|
||||
/* nip_route_input will set nip_null_entry
|
||||
* instead of NULL in skb when looking up failed.
|
||||
*/
|
||||
if (!skb_valid_dst(skb))
|
||||
err = nip_route_input(skb);
|
||||
if (err) {
|
||||
nip_dbg("nip_route_input lookup route exception, release skb");
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
return dst_input(skb);
|
||||
}
|
||||
|
||||
int nip_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev)
|
||||
{
|
||||
int offset = 0;
|
||||
struct nip_hdr_decap niph = {0};
|
||||
|
||||
if (skb->pkt_type == PACKET_OTHERHOST) {
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
memset(NIPCB(skb), 0, sizeof(struct ninet_skb_parm));
|
||||
offset = nip_hdr_parse(skb->data, skb->len, &niph);
|
||||
if (offset <= 0) {
|
||||
nip_dbg("check in failure, errcode=%d, Drop a packet (nexthdr=%u, hdr_len=%u)",
|
||||
offset, niph.nexthdr, niph.hdr_len);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (niph.nexthdr != IPPROTO_UDP && niph.nexthdr != IPPROTO_TCP &&
|
||||
niph.nexthdr != IPPROTO_NIP_ICMP) {
|
||||
nip_dbg("nexthdr(%u) invalid, Drop a packet", niph.nexthdr);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
niph.total_len = ntohs(niph.total_len);
|
||||
NIPCB(skb)->dstaddr = niph.daddr;
|
||||
NIPCB(skb)->srcaddr = niph.saddr;
|
||||
NIPCB(skb)->nexthdr = niph.nexthdr;
|
||||
skb->transport_header = skb->network_header + offset;
|
||||
skb_orphan(skb);
|
||||
|
||||
/* SKB refreshes the length after replication */
|
||||
if (_nip_update_recv_skb_len(skb, &niph))
|
||||
goto drop;
|
||||
|
||||
return nip_rcv_finish(skb);
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
out:
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
/* Deliver the packet to transport layer,
|
||||
* including TCP, UDP and ICMP.
|
||||
* Caller must hold rcu.
|
||||
*/
|
||||
void nip_protocol_deliver_rcu(struct sk_buff *skb)
|
||||
{
|
||||
const struct ninet_protocol *ipprot;
|
||||
|
||||
if (!pskb_pull(skb, skb_transport_offset(skb)))
|
||||
goto discard;
|
||||
|
||||
ipprot = rcu_dereference(ninet_protos[NIPCB(skb)->nexthdr]);
|
||||
if (ipprot) {
|
||||
ipprot->handler(skb);
|
||||
} else {
|
||||
kfree_skb(skb);
|
||||
nip_dbg("not found transport protol, drop this packet");
|
||||
}
|
||||
return;
|
||||
|
||||
discard:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* Generally called by dst_input */
|
||||
int nip_input(struct sk_buff *skb)
|
||||
{
|
||||
rcu_read_lock();
|
||||
nip_protocol_deliver_rcu(skb);
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,523 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP output functions
|
||||
* Linux NewIP INET implementation
|
||||
*
|
||||
* Based on net/ipv6/ip6_output.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/nip.h>
|
||||
#include <linux/route.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/netfilter.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
#include <net/nndisc.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/nip.h>
|
||||
#include <net/nip_udp.h>
|
||||
#include <net/nip_route.h>
|
||||
#include <net/tcp_nip.h>
|
||||
|
||||
#include "nip_hdr.h"
|
||||
#include "nip_checksum.h"
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
#define NIP_BIT_TO_BYTE 1024
|
||||
void update_memory_rate(const char *upper_fun)
|
||||
{
|
||||
struct sysinfo mem_info;
|
||||
unsigned long total;
|
||||
unsigned long free;
|
||||
unsigned long used;
|
||||
unsigned int uint_kb;
|
||||
|
||||
si_meminfo(&mem_info);
|
||||
uint_kb = mem_info.mem_unit / NIP_BIT_TO_BYTE;
|
||||
total = (unsigned long)mem_info.totalram * uint_kb;
|
||||
free = (unsigned long)mem_info.freeram * uint_kb;
|
||||
used = total - free;
|
||||
nip_dbg("%s call cur-func mem total: %ld KB, mem used: %ld KB", upper_fun, total, used);
|
||||
}
|
||||
|
||||
int nip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct nip_addr *nexthop;
|
||||
struct neighbour *neigh;
|
||||
int ret = 0;
|
||||
struct net_device *dev = skb_dst(skb)->dev;
|
||||
|
||||
skb->protocol = htons(ETH_P_NEWIP);
|
||||
skb->dev = dev;
|
||||
|
||||
/* prepare to build ethernet header */
|
||||
nexthop = nip_nexthop((struct nip_rt_info *)dst, &NIPCB(skb)->dstaddr);
|
||||
|
||||
rcu_read_lock_bh();
|
||||
|
||||
neigh = __nip_neigh_lookup_noref(dev, nexthop);
|
||||
if (unlikely(!neigh))
|
||||
neigh = __neigh_create(&nnd_tbl, nexthop, dev, false);
|
||||
if (!IS_ERR(neigh)) {
|
||||
int res = neigh_output(neigh, skb, false);
|
||||
|
||||
rcu_read_unlock_bh();
|
||||
return res;
|
||||
}
|
||||
nip_dbg("find neigh and create neigh failed");
|
||||
|
||||
rcu_read_unlock_bh();
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nip_forward(struct sk_buff *skb)
|
||||
{
|
||||
return nip_output(NULL, NULL, skb);
|
||||
}
|
||||
|
||||
static int nip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dst_output(net, sk, skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
int nip_send_skb(struct sk_buff *skb)
|
||||
{
|
||||
struct net *net;
|
||||
int err = 0;
|
||||
|
||||
net = skb->sk ? sock_net(skb->sk) : dev_net(skb_dst(skb)->dev);
|
||||
err = nip_local_out(net, skb->sk, skb);
|
||||
if (err) {
|
||||
if (err > 0)
|
||||
err = net_xmit_errno(err);
|
||||
nip_dbg("failed to out skb, err = %d", err);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
unsigned short nip_get_output_checksum(struct sk_buff *skb,
|
||||
struct nip_hdr_encap *head)
|
||||
{
|
||||
struct nip_pseudo_header nph = {0};
|
||||
u8 *udp_hdr = skb_transport_header(skb);
|
||||
unsigned short check_len = head->trans_hdr_len + head->usr_data_len;
|
||||
|
||||
nph.nexthdr = IPPROTO_UDP;
|
||||
nph.saddr = NIPCB(skb)->srcaddr;
|
||||
nph.daddr = NIPCB(skb)->dstaddr;
|
||||
nph.check_len = htons(check_len);
|
||||
return nip_check_sum_build(udp_hdr, check_len, &nph);
|
||||
}
|
||||
|
||||
static struct sk_buff *_nip_alloc_skb(struct sock *sk,
|
||||
struct nip_hdr_encap *head,
|
||||
struct nip_pkt_seg_info *seg_info,
|
||||
struct dst_entry *dst)
|
||||
{
|
||||
int len;
|
||||
int nip_hdr_len = get_nip_hdr_len(NIP_HDR_UDP, &head->saddr, &head->daddr);
|
||||
struct sk_buff *skb;
|
||||
|
||||
nip_hdr_len = nip_hdr_len == 0 ? NIP_HDR_MAX : nip_hdr_len;
|
||||
len = NIP_ETH_HDR_LEN + nip_hdr_len + head->trans_hdr_len + seg_info->mid_usr_pkt_len;
|
||||
skb = alloc_skb(len, 0);
|
||||
if (!skb) {
|
||||
nip_dbg("no space for skb");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
skb->protocol = htons(ETH_P_NEWIP);
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
skb->csum = 0;
|
||||
skb->sk = sk;
|
||||
|
||||
dst_hold(dst);
|
||||
nip_dbg("malloc_len=%d, dst->__refcnt=%u", len, atomic_read(&dst->__refcnt));
|
||||
skb_dst_set(skb, dst);
|
||||
memset(NIPCB(skb), 0, sizeof(struct ninet_skb_parm));
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int _nip_udp_single_output(struct sock *sk,
|
||||
struct nip_hdr_encap *head,
|
||||
struct nip_pkt_seg_info *seg_info,
|
||||
struct dst_entry *dst)
|
||||
{
|
||||
int len;
|
||||
int ret;
|
||||
struct msghdr *from = (struct msghdr *)head->usr_data;
|
||||
struct sk_buff *skb = _nip_alloc_skb(sk, head, seg_info, dst);
|
||||
unsigned short check = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(skb)) {
|
||||
nip_dbg("skb alloc fail");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Reserved Position of the Ethernet header (to be filled after the
|
||||
* Ethernet header is delivered to the link layer)
|
||||
*/
|
||||
skb_reserve(skb, NIP_ETH_HDR_LEN);
|
||||
|
||||
/* Fill in the Network-layer Header (newIP) */
|
||||
skb_reset_network_header(skb);
|
||||
head->hdr_buf = skb->data;
|
||||
nip_hdr_udp_encap(head);
|
||||
skb_reserve(skb, head->hdr_buf_pos);
|
||||
NIPCB(skb)->dstaddr = head->daddr;
|
||||
NIPCB(skb)->srcaddr = head->saddr;
|
||||
NIPCB(skb)->nexthdr = IPPROTO_UDP;
|
||||
|
||||
/* Fill in the Transport Layer Header (UDP) */
|
||||
skb_reset_transport_header(skb);
|
||||
nip_build_udp_hdr(head->sport, head->dport,
|
||||
htons(head->trans_hdr_len + head->usr_data_len),
|
||||
skb->data, htons(0));
|
||||
skb_reserve(skb, head->trans_hdr_len);
|
||||
len = copy_from_iter(skb->data, head->usr_data_len, &from->msg_iter);
|
||||
if (len < 0) {
|
||||
/* The DST has been set to the SKB. When the SKB is released,
|
||||
* the DST is automatically released
|
||||
*/
|
||||
nip_dbg("copy from iter fail (datalen=%u)", head->usr_data_len);
|
||||
kfree_skb(skb);
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
/* insert check sum */
|
||||
check = nip_get_output_checksum(skb, head);
|
||||
nip_build_udp_hdr(head->sport, head->dport,
|
||||
htons(head->trans_hdr_len + head->usr_data_len),
|
||||
skb->data - head->trans_hdr_len, htons(check));
|
||||
|
||||
/* Refresh the data/tail of the SKB after the packet copy is complete */
|
||||
skb_put(skb, head->usr_data_len);
|
||||
skb->data = skb_network_header(skb);
|
||||
skb->len = head->hdr_buf_pos + head->trans_hdr_len +
|
||||
head->usr_data_len;
|
||||
|
||||
/* Add the actual size of the current SKB to the SOCK send cache count
|
||||
* and set destructor to __sock_wfree to reduce the SOCK send cache size
|
||||
* when the SKB is released.
|
||||
*/
|
||||
skb->destructor = __sock_wfree;
|
||||
refcount_add(skb->truesize, &sk->sk_wmem_alloc);
|
||||
skb->priority = sk->sk_priority;
|
||||
|
||||
ret = nip_send_skb(skb);
|
||||
nip_dbg("output finish (ret=%d, datalen=%u)", ret, head->usr_data_len);
|
||||
update_memory_rate(__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _nip_udp_output(struct sock *sk, void *from, int datalen,
|
||||
int transhdrlen, const struct nip_addr *saddr,
|
||||
ushort sport, const struct nip_addr *daddr,
|
||||
ushort dport, struct dst_entry *dst)
|
||||
{
|
||||
int i;
|
||||
u32 ret = 0;
|
||||
u32 mtu = dst_mtu(dst);
|
||||
struct nip_pkt_seg_info seg_info = {0};
|
||||
struct nip_hdr_encap head = {0};
|
||||
int nip_hdr_len = get_nip_hdr_len(NIP_HDR_UDP, saddr, daddr);
|
||||
|
||||
head.saddr = *saddr;
|
||||
head.daddr = *daddr;
|
||||
head.sport = sport;
|
||||
head.dport = dport;
|
||||
head.usr_data = from;
|
||||
head.ttl = NIP_DEFAULT_TTL;
|
||||
head.nexthdr = IPPROTO_UDP;
|
||||
head.trans_hdr_len = transhdrlen;
|
||||
|
||||
nip_hdr_len = nip_hdr_len == 0 ? NIP_HDR_MAX : nip_hdr_len;
|
||||
nip_calc_pkt_frag_num(mtu, nip_hdr_len, datalen, &seg_info);
|
||||
|
||||
/* Send intermediate data segments */
|
||||
for (i = 0; i < seg_info.mid_pkt_num; i++) {
|
||||
head.usr_data_len = seg_info.mid_usr_pkt_len;
|
||||
ret = _nip_udp_single_output(sk, &head, &seg_info, dst);
|
||||
if (ret)
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Send the last data segment */
|
||||
if (seg_info.last_pkt_num) {
|
||||
head.usr_data_len = seg_info.last_usr_pkt_len;
|
||||
ret = _nip_udp_single_output(sk, &head, &seg_info, dst);
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nip_sk_dst_check(struct dst_entry *dst,
|
||||
struct flow_nip *fln)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (!dst)
|
||||
goto out;
|
||||
|
||||
if (fln->flowin_oif && fln->flowin_oif != dst->dev->ifindex)
|
||||
err = -EPERM;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* 1. Based on FLN, the routing table is searched to obtain the corresponding DST
|
||||
* 2. The newIP address of the source end is obtained based on the routing table
|
||||
* search result and stored in the fln->saddr
|
||||
*/
|
||||
static int nip_dst_lookup_tail(struct net *net, const struct sock *sk,
|
||||
struct dst_entry **dst, struct flow_nip *fln)
|
||||
{
|
||||
int err;
|
||||
struct nip_rt_info *rt;
|
||||
|
||||
if (!(*dst))
|
||||
*dst = nip_route_output(net, sk, fln);
|
||||
|
||||
err = (*dst)->error;
|
||||
if (err) {
|
||||
rt = NULL;
|
||||
nip_dbg("route output search error");
|
||||
goto out_err_release;
|
||||
}
|
||||
|
||||
err = nip_sk_dst_check(*dst, fln);
|
||||
if (err)
|
||||
goto out_err_release;
|
||||
|
||||
rt = (struct nip_rt_info *)*dst;
|
||||
if (*dst == &net->newip.nip_broadcast_entry->dst) {
|
||||
fln->saddr = fln->daddr;
|
||||
err = 0;
|
||||
} else {
|
||||
err = nip_route_get_saddr(net, rt, &fln->daddr, &fln->saddr);
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto out_err_release;
|
||||
|
||||
return 0;
|
||||
|
||||
out_err_release:
|
||||
dst_release(*dst);
|
||||
*dst = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct dst_entry *nip_dst_lookup_flow(struct net *net, const struct sock *sk,
|
||||
struct flow_nip *fln,
|
||||
const struct nip_addr *final_dst)
|
||||
{
|
||||
struct dst_entry *dst = NULL;
|
||||
int err;
|
||||
|
||||
err = nip_dst_lookup_tail(net, sk, &dst, fln);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
if (final_dst)
|
||||
fln->daddr = *final_dst;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
struct dst_entry *nip_sk_dst_lookup_flow(struct sock *sk, struct flow_nip *fln)
|
||||
{
|
||||
struct dst_entry *dst = NULL;
|
||||
int err;
|
||||
|
||||
err = nip_dst_lookup_tail(sock_net(sk), sk, &dst, fln);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
int tcp_nip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)
|
||||
{
|
||||
int err = -EHOSTUNREACH;
|
||||
struct net *net = sock_net(sk);
|
||||
struct nip_addr *saddr, *daddr;
|
||||
struct dst_entry *dst;
|
||||
struct flow_nip fln;
|
||||
struct nip_hdr_encap head = {0};
|
||||
unsigned char hdr_buf[NIP_HDR_MAX]; /* Cache the newIP header */
|
||||
|
||||
rcu_read_lock();
|
||||
skb->protocol = htons(ETH_P_NEWIP);
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
skb->csum = 0;
|
||||
saddr = &sk->sk_nip_rcv_saddr;
|
||||
daddr = &sk->sk_nip_daddr;
|
||||
|
||||
head.saddr = *saddr;
|
||||
head.daddr = *daddr;
|
||||
head.ttl = NIP_DEFAULT_TTL;
|
||||
head.nexthdr = IPPROTO_TCP;
|
||||
head.hdr_buf = hdr_buf;
|
||||
nip_hdr_comm_encap(&head);
|
||||
head.total_len = head.hdr_buf_pos + skb->len;
|
||||
nip_update_total_len(&head, htons(head.total_len));
|
||||
|
||||
fln.daddr = sk->sk_nip_daddr;
|
||||
dst = __sk_dst_check(sk, 0);
|
||||
if (!dst) {
|
||||
nip_dbg("no dst cache for sk, search newip rt");
|
||||
dst = nip_route_output(net, sk, &fln);
|
||||
if (!dst) {
|
||||
nip_dbg("cannot find dst");
|
||||
goto out;
|
||||
}
|
||||
if (dst->error)
|
||||
goto out_err_release;
|
||||
sk_dst_set(sk, dst);
|
||||
}
|
||||
skb_dst_set_noref(skb, dst);
|
||||
|
||||
/* build nwk header */
|
||||
skb_push(skb, head.hdr_buf_pos);
|
||||
memcpy(skb->data, head.hdr_buf, head.hdr_buf_pos);
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
NIPCB(skb)->srcaddr = *saddr;
|
||||
NIPCB(skb)->dstaddr = *daddr;
|
||||
NIPCB(skb)->nexthdr = head.nexthdr;
|
||||
|
||||
skb->priority = sk->sk_priority;
|
||||
head.total_len = skb->len;
|
||||
err = nip_send_skb(skb);
|
||||
if (err)
|
||||
nip_dbg("failed to send skb, skb->len=%u", head.total_len);
|
||||
else
|
||||
nip_dbg("send skb ok, skb->len=%u", head.total_len);
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
|
||||
out_err_release:
|
||||
dst_release(dst);
|
||||
dst = NULL;
|
||||
sk->sk_err_soft = -err;
|
||||
sk->sk_route_caps = 0;
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
void tcp_nip_actual_send_reset(struct sock *sk, struct sk_buff *skb, u32 seq,
|
||||
u32 ack_seq, u32 win, int rst, u32 priority)
|
||||
{
|
||||
const struct tcphdr *th = tcp_hdr(skb);
|
||||
struct tcphdr *t1;
|
||||
struct sk_buff *buff;
|
||||
struct flow_nip fln;
|
||||
struct net *net;
|
||||
struct nip_addr *saddr, *daddr;
|
||||
unsigned int tot_len = sizeof(struct tcphdr);
|
||||
struct nip_hdr_encap head = {0};
|
||||
unsigned char hdr_buf[NIP_HDR_MAX];
|
||||
struct dst_entry *dst;
|
||||
int err;
|
||||
|
||||
net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev);
|
||||
|
||||
/* alloc skb */
|
||||
buff = alloc_skb(MAX_TCP_HEADER, priority);
|
||||
if (!buff)
|
||||
/* If you add log here, there will be an alarm:
|
||||
* WARNING: Possible unnecessary 'out of memory' message
|
||||
*/
|
||||
return;
|
||||
|
||||
skb_reserve(buff, MAX_TCP_HEADER);
|
||||
|
||||
buff->sk = sk; // sk could be NULL
|
||||
saddr = &(NIPCB(skb)->dstaddr);
|
||||
daddr = &(NIPCB(skb)->srcaddr);
|
||||
|
||||
/* Fill in tcp header */
|
||||
t1 = skb_push(buff, sizeof(struct tcphdr));
|
||||
skb_reset_transport_header(buff);
|
||||
memset(t1, 0, sizeof(*t1));
|
||||
t1->dest = th->source;
|
||||
t1->source = th->dest;
|
||||
t1->doff = tot_len / TCP_NUM_4;
|
||||
t1->seq = htonl(seq);
|
||||
t1->ack_seq = htonl(ack_seq);
|
||||
t1->ack = !rst || !th->ack;
|
||||
t1->rst = rst;
|
||||
t1->window = htons(win);
|
||||
t1->check = htons(nip_get_output_checksum_tcp(buff, *saddr, *daddr));
|
||||
nip_dbg("host dport=%u, net dport=0x%x, host sport=%u, net sport=0x%x",
|
||||
ntohs(t1->dest), t1->dest, ntohs(t1->source), t1->source);
|
||||
nip_dbg("host seq=%u, net seq=0x%x, host ack_seq=%u, net ack_seq=0x%x",
|
||||
seq, t1->seq, ack_seq, t1->ack_seq);
|
||||
|
||||
buff->protocol = htons(ETH_P_NEWIP);
|
||||
buff->ip_summed = CHECKSUM_NONE;
|
||||
buff->csum = 0;
|
||||
|
||||
/* Fill in nip header */
|
||||
head.saddr = *saddr;
|
||||
head.daddr = *daddr;
|
||||
head.ttl = NIP_DEFAULT_TTL;
|
||||
head.nexthdr = IPPROTO_TCP;
|
||||
head.hdr_buf = hdr_buf;
|
||||
nip_hdr_comm_encap(&head);
|
||||
head.total_len = head.hdr_buf_pos + buff->len;
|
||||
nip_update_total_len(&head, htons(head.total_len));
|
||||
|
||||
/* Check routine */
|
||||
fln.daddr = *daddr;
|
||||
dst = nip_route_output(net, sk, &fln); // here, sk not used.
|
||||
if (!dst) {
|
||||
nip_dbg("cannot find dst");
|
||||
goto out;
|
||||
}
|
||||
skb_dst_set_noref(buff, dst);
|
||||
|
||||
/* Build newip header */
|
||||
skb_push(buff, head.hdr_buf_pos);
|
||||
memcpy(buff->data, head.hdr_buf, head.hdr_buf_pos);
|
||||
|
||||
skb_reset_network_header(buff);
|
||||
NIPCB(buff)->srcaddr = *saddr;
|
||||
NIPCB(buff)->dstaddr = *daddr;
|
||||
NIPCB(buff)->nexthdr = head.nexthdr;
|
||||
|
||||
buff->priority = priority;
|
||||
head.total_len = buff->len;
|
||||
err = nip_send_skb(buff);
|
||||
if (err)
|
||||
nip_dbg("failed to send skb, skb->len=%u", head.total_len);
|
||||
else
|
||||
nip_dbg("send skb ok, skb->len=%u", head.total_len);
|
||||
|
||||
out:
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* The NewIP to API glue.
|
||||
*
|
||||
* Based on net/ipv4/ip_sockglue.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/nip.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/nip.h>
|
||||
#include <net/nip_udp.h>
|
||||
#include <net/route.h>
|
||||
#include <net/nip_fib.h>
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
#define NIP_OPTNAME_MAX 255
|
||||
|
||||
static void __nip_set_sock_tos(struct sock *sk, int val)
|
||||
{
|
||||
sk->sk_priority = rt_tos2priority(val);
|
||||
sk_dst_reset(sk);
|
||||
}
|
||||
|
||||
static bool nip_setsockopt_needs_rtnl(int optname)
|
||||
{
|
||||
switch (optname) {
|
||||
case IP_MSFILTER:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool nip_getsockopt_needs_rtnl(int optname)
|
||||
{
|
||||
switch (optname) {
|
||||
case IP_MSFILTER:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int do_nip_setsockopt(struct sock *sk, int level, int optname,
|
||||
sockptr_t optval, unsigned int optlen)
|
||||
{
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
int val = 0;
|
||||
int err = 0;
|
||||
bool needs_rtnl = nip_setsockopt_needs_rtnl(optname);
|
||||
|
||||
if (optlen >= sizeof(int)) {
|
||||
if (copy_from_sockptr(&val, optval, sizeof(val)))
|
||||
return -EFAULT;
|
||||
} else if (optlen >= sizeof(char)) {
|
||||
unsigned char ucval;
|
||||
|
||||
if (copy_from_sockptr(&ucval, optval, sizeof(ucval)))
|
||||
return -EFAULT;
|
||||
val = (int)ucval;
|
||||
}
|
||||
|
||||
if (needs_rtnl)
|
||||
rtnl_lock();
|
||||
lock_sock(sk);
|
||||
|
||||
switch (optname) {
|
||||
case IP_TOS:
|
||||
inet->tos = val;
|
||||
__nip_set_sock_tos(sk, val);
|
||||
break;
|
||||
default:
|
||||
err = -ENOPROTOOPT;
|
||||
break;
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
if (needs_rtnl)
|
||||
rtnl_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int nip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
|
||||
unsigned int optlen)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (level != SOL_IP)
|
||||
return -ENOPROTOOPT;
|
||||
|
||||
err = do_nip_setsockopt(sk, level, optname, optval, optlen);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int do_nip_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
bool needs_rtnl = nip_getsockopt_needs_rtnl(optname);
|
||||
int val, err = 0;
|
||||
int len;
|
||||
|
||||
if (level != SOL_IP)
|
||||
return -EOPNOTSUPP;
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (needs_rtnl)
|
||||
rtnl_lock();
|
||||
lock_sock(sk);
|
||||
|
||||
switch (optname) {
|
||||
case IP_TOS:
|
||||
val = inet->tos;
|
||||
break;
|
||||
default:
|
||||
err = -ENOPROTOOPT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (len < sizeof(int) && len > 0 && val >= 0 && val <= NIP_OPTNAME_MAX) {
|
||||
unsigned char ucval = (unsigned char)val;
|
||||
|
||||
len = 1;
|
||||
if (put_user(len, optlen)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (copy_to_user(optval, &ucval, 1)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
len = min_t(unsigned int, sizeof(int), len);
|
||||
if (put_user(len, optlen)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (copy_to_user(optval, &val, len)) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
release_sock(sk);
|
||||
if (needs_rtnl)
|
||||
rtnl_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int nip_getsockopt(struct sock *sk, int level,
|
||||
int optname, char __user *optval, int __user *optlen)
|
||||
{
|
||||
return do_nip_getsockopt(sk, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,579 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* Neighbour Discovery for NewIP
|
||||
* Linux NewIP INET implementation
|
||||
*
|
||||
* Based on net/ipv6/ndisc.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/route.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/nip.h>
|
||||
#include <linux/nip_icmp.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/nip.h>
|
||||
#include <net/nip_udp.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/nndisc.h>
|
||||
#include <net/nip_route.h>
|
||||
#include <net/addrconf.h>
|
||||
#include <net/nip_fib.h>
|
||||
#include <net/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/flow.h>
|
||||
#include <net/inet_common.h>
|
||||
#include <net/nip_addrconf.h>
|
||||
#include <linux/newip_route.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include "nip_hdr.h"
|
||||
#include "nip_checksum.h"
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
/* NUD_INCOMPLETE
|
||||
* The neighbor request packet has been sent but no response has been received
|
||||
* NUD_REACHABLE
|
||||
* Reachable: Indicates that the neighbor is reachable
|
||||
* NUD_STAL
|
||||
* Idle state, which has not been confirmed for a long time,
|
||||
* and the idle time exceeds the rated time
|
||||
* NUD_DELAY
|
||||
* If the acknowledgment time expires but the idle time does not exceed the rated time,
|
||||
* you need to obtain the acknowledgment packet
|
||||
* NUD_PROBE
|
||||
* After NUD_DELAY does not receive confirmation for a long time, ARP request messages are sent
|
||||
* NUD_FAILED
|
||||
* The neighbor is unreachable
|
||||
* NUD_NOARP
|
||||
* Indicates the status of the neighbor that does not need the ARP status change
|
||||
* NUD_PERMANENT
|
||||
* Indicates that the status of the neighbor item is permanent and does not need to change
|
||||
* NUD_NONE
|
||||
* Initialization status of the neighbor item
|
||||
*/
|
||||
static void nndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
|
||||
|
||||
static u32 nndisc_hash(const void *pkey,
|
||||
const struct net_device *dev, __u32 *hash_rnd);
|
||||
static bool nndisc_key_eq(const struct neighbour *neigh, const void *pkey);
|
||||
static int nndisc_constructor(struct neighbour *neigh);
|
||||
|
||||
static void nndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
|
||||
{
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static const struct neigh_ops nndisc_generic_ops = {
|
||||
.family = AF_NINET,
|
||||
.solicit = nndisc_solicit,
|
||||
.output = neigh_resolve_output,
|
||||
.connected_output = neigh_connected_output,
|
||||
};
|
||||
|
||||
static const struct neigh_ops nndisc_hh_ops = {
|
||||
.family = AF_NINET,
|
||||
.solicit = nndisc_solicit,
|
||||
.error_report = nndisc_error_report,
|
||||
.output = neigh_resolve_output,
|
||||
.connected_output = neigh_resolve_output,
|
||||
};
|
||||
|
||||
static const struct neigh_ops nndisc_direct_ops = {
|
||||
.family = AF_NINET,
|
||||
.output = neigh_direct_output,
|
||||
.connected_output = neigh_direct_output,
|
||||
};
|
||||
|
||||
#define NIP_NEIGH_MCAST_PROBES 4
|
||||
#define NIP_NEIGH_UCAST_PROBES 4
|
||||
#define NIP_NEIGH_DELAY_PROBE_TIME (5 * HZ)
|
||||
#define NIP_NEIGH_GC_STALETIME (60 * HZ)
|
||||
#define NIP_NEIGH_QUEUE_LEN_BYTES (64 * 1024)
|
||||
#define NIP_NEIGH_PROXY_QLEN 64
|
||||
#define NIP_NEIGH_ANYCAST_DELAY (1 * HZ)
|
||||
#define NIP_NEIGH_PROXY_DELAY ((8 * HZ) / 10)
|
||||
#define NIP_NEIGH_GC_INTERVAL (30 * HZ)
|
||||
#define NIP_NEIGH_GC_THRESH_1 128
|
||||
#define NIP_NEIGH_GC_THRESH_2 512
|
||||
#define NIP_NEIGH_GC_THRESH_3 1024
|
||||
|
||||
struct neigh_table nnd_tbl = {
|
||||
.family = AF_NINET,
|
||||
.key_len = sizeof(struct nip_addr),
|
||||
.protocol = cpu_to_be16(ETH_P_NEWIP),
|
||||
.hash = nndisc_hash,
|
||||
.key_eq = nndisc_key_eq,
|
||||
.constructor = nndisc_constructor,
|
||||
.id = "nndisc_cache",
|
||||
.parms = {
|
||||
.tbl = &nnd_tbl,
|
||||
.reachable_time = ND_REACHABLE_TIME,
|
||||
.data = {
|
||||
[NEIGH_VAR_MCAST_PROBES] = NIP_NEIGH_MCAST_PROBES,
|
||||
[NEIGH_VAR_UCAST_PROBES] = NIP_NEIGH_UCAST_PROBES,
|
||||
[NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER,
|
||||
[NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME,
|
||||
[NEIGH_VAR_DELAY_PROBE_TIME] = NIP_NEIGH_DELAY_PROBE_TIME,
|
||||
[NEIGH_VAR_GC_STALETIME] = NIP_NEIGH_GC_STALETIME,
|
||||
[NEIGH_VAR_QUEUE_LEN_BYTES] = NIP_NEIGH_QUEUE_LEN_BYTES,
|
||||
[NEIGH_VAR_PROXY_QLEN] = NIP_NEIGH_PROXY_QLEN,
|
||||
[NEIGH_VAR_ANYCAST_DELAY] = NIP_NEIGH_ANYCAST_DELAY,
|
||||
[NEIGH_VAR_PROXY_DELAY] = NIP_NEIGH_PROXY_DELAY,
|
||||
},
|
||||
},
|
||||
.gc_interval = NIP_NEIGH_GC_INTERVAL,
|
||||
.gc_thresh1 = NIP_NEIGH_GC_THRESH_1,
|
||||
.gc_thresh2 = NIP_NEIGH_GC_THRESH_2,
|
||||
.gc_thresh3 = NIP_NEIGH_GC_THRESH_3,
|
||||
};
|
||||
|
||||
static u32 nndisc_hash(const void *pkey,
|
||||
const struct net_device *dev, __u32 *hash_rnd)
|
||||
{
|
||||
return nndisc_hashfn(pkey, dev, hash_rnd);
|
||||
}
|
||||
|
||||
static bool nndisc_key_eq(const struct neighbour *neigh, const void *pkey)
|
||||
{
|
||||
return neigh_key_eq800(neigh, pkey);
|
||||
}
|
||||
|
||||
static int nndisc_constructor(struct neighbour *neigh)
|
||||
{
|
||||
struct nip_addr *addr = (struct nip_addr *)&neigh->primary_key;
|
||||
struct net_device *dev = neigh->dev;
|
||||
struct ninet_dev *nin_dev;
|
||||
struct neigh_parms *parms;
|
||||
bool is_broadcast = (bool)nip_addr_eq(addr, &nip_broadcast_addr_arp);
|
||||
|
||||
nin_dev = nin_dev_get(dev);
|
||||
if (!nin_dev)
|
||||
return -EINVAL;
|
||||
|
||||
parms = nin_dev->nd_parms;
|
||||
__neigh_parms_put(neigh->parms);
|
||||
neigh->parms = neigh_parms_clone(parms);
|
||||
neigh->type = RTN_UNICAST;
|
||||
if (!dev->header_ops) {
|
||||
neigh->nud_state = NUD_NOARP;
|
||||
neigh->ops = &nndisc_direct_ops;
|
||||
neigh->output = neigh_direct_output;
|
||||
} else {
|
||||
if (is_broadcast ||
|
||||
(dev->flags & IFF_POINTOPOINT)) {
|
||||
neigh->nud_state = NUD_NOARP;
|
||||
memcpy(neigh->ha, dev->broadcast, dev->addr_len);
|
||||
} else if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) {
|
||||
neigh->nud_state = NUD_NOARP;
|
||||
memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
|
||||
if (dev->flags & IFF_LOOPBACK)
|
||||
neigh->type = RTN_LOCAL;
|
||||
}
|
||||
|
||||
if (dev->header_ops->cache)
|
||||
neigh->ops = &nndisc_hh_ops;
|
||||
else
|
||||
neigh->ops = &nndisc_generic_ops;
|
||||
|
||||
if (neigh->nud_state & NUD_VALID)
|
||||
neigh->output = neigh->ops->connected_output;
|
||||
else
|
||||
neigh->output = neigh->ops->output;
|
||||
}
|
||||
|
||||
nin_dev_put(nin_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nip_insert_nndisc_send_checksum(struct sk_buff *skb, u_short checksum)
|
||||
{
|
||||
#define NNDISC_CHECKSUM_BIAS 2
|
||||
*(__u16 *)(skb_transport_header(skb) + NNDISC_CHECKSUM_BIAS) =
|
||||
htons(checksum);
|
||||
}
|
||||
|
||||
unsigned short nip_get_nndisc_send_checksum(struct sk_buff *skb,
|
||||
struct nip_hdr_encap *head,
|
||||
int payload_len)
|
||||
{
|
||||
struct nip_pseudo_header nph = {0};
|
||||
|
||||
nph.nexthdr = head->nexthdr;
|
||||
nph.saddr = head->saddr;
|
||||
nph.daddr = head->daddr;
|
||||
nph.check_len = htons(payload_len);
|
||||
return nip_check_sum_build(skb_transport_header(skb),
|
||||
payload_len, &nph);
|
||||
}
|
||||
|
||||
bool nip_get_nndisc_rcv_checksum(struct sk_buff *skb,
|
||||
const u_char *transport_tail)
|
||||
{
|
||||
struct nip_pseudo_header nph = {0};
|
||||
unsigned short check_len = (unsigned short)(transport_tail - (skb_transport_header(skb)));
|
||||
|
||||
nph.nexthdr = NIPCB(skb)->nexthdr;
|
||||
nph.saddr = NIPCB(skb)->srcaddr;
|
||||
nph.daddr = NIPCB(skb)->dstaddr;
|
||||
nph.check_len = htons(check_len);
|
||||
|
||||
return nip_check_sum_parse(skb_transport_header(skb), check_len, &nph)
|
||||
== 0xffff ? true : false;
|
||||
}
|
||||
|
||||
static void nndisc_payload_ns_pack(const struct nip_addr *solicit,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct nnd_msg *msg = (struct nnd_msg *)skb->data;
|
||||
u_char *p = msg->data;
|
||||
|
||||
memset(&msg->icmph, 0, sizeof(msg->icmph));
|
||||
msg->icmph.nip_icmp_type = NIP_ARP_NS;
|
||||
msg->icmph.nip_icmp_cksum = 0;
|
||||
p = build_nip_addr(solicit, p);
|
||||
}
|
||||
|
||||
static struct dst_entry *nndisc_dst_alloc(struct net_device *dev)
|
||||
{
|
||||
struct nip_rt_info *rt;
|
||||
struct net *net = dev_net(dev);
|
||||
|
||||
rt = nip_dst_alloc(net, dev, 0);
|
||||
if (!rt)
|
||||
return NULL;
|
||||
|
||||
rt->dst.flags |= DST_HOST;
|
||||
rt->dst.input = nip_input;
|
||||
rt->dst.output = nip_output;
|
||||
atomic_set(&rt->dst.__refcnt, 1);
|
||||
|
||||
return &rt->dst;
|
||||
}
|
||||
|
||||
static int get_ns_payload_len(const struct nip_addr *solicit)
|
||||
{
|
||||
return sizeof(struct nip_icmp_hdr) + get_nip_addr_len(solicit);
|
||||
}
|
||||
|
||||
static int nndisc_send_skb(struct net_device *dev,
|
||||
struct sk_buff *skb, struct nip_hdr_encap *head,
|
||||
const int payload_len)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sock *sk = NULL;
|
||||
struct dst_entry *dst = NULL;
|
||||
u_short checksum = 0;
|
||||
|
||||
/* skip transport hdr */
|
||||
skb_reserve(skb, payload_len);
|
||||
|
||||
/* set skb->data to point network header */
|
||||
skb->data = skb_network_header(skb);
|
||||
skb->len = head->hdr_buf_pos + payload_len;
|
||||
|
||||
dst = nndisc_dst_alloc(dev);
|
||||
if (!dst) {
|
||||
kfree_skb(skb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* add check sum */
|
||||
checksum = nip_get_nndisc_send_checksum(skb, head, payload_len);
|
||||
nip_insert_nndisc_send_checksum(skb, checksum);
|
||||
|
||||
skb_dst_set(skb, dst);
|
||||
ret = dst_output(dev_net(skb->dev), sk, skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct sk_buff *nndisc_alloc_skb(struct net_device *dev,
|
||||
struct nip_hdr_encap *head, int payload_len)
|
||||
{
|
||||
struct sk_buff *skb = NULL;
|
||||
int len = NIP_ETH_HDR_LEN + NIP_HDR_MAX + payload_len;
|
||||
|
||||
skb = alloc_skb(len, 0);
|
||||
if (!skb)
|
||||
/* If you add log here, there will be an alarm:
|
||||
* WARNING: Possible unnecessary 'out of memory' message
|
||||
*/
|
||||
return skb;
|
||||
|
||||
skb->protocol = htons(ETH_P_NEWIP);
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
skb->csum = 0;
|
||||
skb->dev = dev;
|
||||
memset(NIPCB(skb), 0, sizeof(struct ninet_skb_parm));
|
||||
|
||||
NIPCB(skb)->dstaddr = head->daddr;
|
||||
NIPCB(skb)->srcaddr = head->saddr;
|
||||
NIPCB(skb)->nexthdr = head->nexthdr;
|
||||
/* reserve space for hardware header */
|
||||
skb_reserve(skb, NIP_ETH_HDR_LEN);
|
||||
skb_reset_network_header(skb);
|
||||
|
||||
/* build nwk header */
|
||||
head->hdr_buf = (unsigned char *)skb->data;
|
||||
nip_hdr_comm_encap(head);
|
||||
head->total_len = head->hdr_buf_pos + payload_len;
|
||||
nip_update_total_len(head, htons(head->total_len));
|
||||
skb_reserve(skb, head->hdr_buf_pos);
|
||||
skb_reset_transport_header(skb);
|
||||
return skb;
|
||||
}
|
||||
|
||||
static void nndisc_send_ns(struct net_device *dev,
|
||||
const struct nip_addr *solicit,
|
||||
const struct nip_addr *daddr,
|
||||
const struct nip_addr *saddr)
|
||||
{
|
||||
int ret;
|
||||
struct sk_buff *skb;
|
||||
int payload_len = get_ns_payload_len(solicit);
|
||||
struct nip_hdr_encap head = {0};
|
||||
|
||||
head.saddr = *saddr;
|
||||
head.daddr = *daddr;
|
||||
head.ttl = NIP_ARP_DEFAULT_TTL;
|
||||
head.nexthdr = IPPROTO_NIP_ICMP;
|
||||
|
||||
skb = nndisc_alloc_skb(dev, &head, payload_len);
|
||||
if (!skb)
|
||||
/* If you add log here, there will be an alarm:
|
||||
* WARNING: Possible unnecessary 'out of memory' message
|
||||
*/
|
||||
return;
|
||||
/* build ns header */
|
||||
nndisc_payload_ns_pack(solicit, skb);
|
||||
|
||||
ret = nndisc_send_skb(dev, skb, &head, payload_len);
|
||||
if (ret)
|
||||
nip_dbg("dst output fail");
|
||||
}
|
||||
|
||||
static void nndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = neigh->dev;
|
||||
struct nip_addr *target = (struct nip_addr *)&neigh->primary_key;
|
||||
struct nip_addr *saddr = NULL;
|
||||
struct ninet_dev *idev;
|
||||
|
||||
/* Obtain the NewIP address from the current dev as
|
||||
* the source address of the request packet
|
||||
*/
|
||||
rcu_read_lock();
|
||||
idev = __nin_dev_get(dev);
|
||||
if (idev) {
|
||||
read_lock_bh(&idev->lock);
|
||||
if (!list_empty(&idev->addr_list)) {
|
||||
struct ninet_ifaddr *ifp;
|
||||
|
||||
list_for_each_entry(ifp, &idev->addr_list, if_list) {
|
||||
saddr = &ifp->addr;
|
||||
nndisc_send_ns(dev, target,
|
||||
&nip_broadcast_addr_arp,
|
||||
saddr);
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&idev->lock);
|
||||
} else {
|
||||
nip_dbg("idev don't exist");
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void build_na_hdr(u_char *smac, u_char mac_len, struct sk_buff *skb)
|
||||
{
|
||||
struct nnd_msg *msg = (struct nnd_msg *)skb->data;
|
||||
u_char *p = msg->data;
|
||||
|
||||
memset(&msg->icmph, 0, sizeof(msg->icmph));
|
||||
msg->icmph.nip_icmp_type = NIP_ARP_NA;
|
||||
msg->icmph.nip_icmp_cksum = 0;
|
||||
*p = mac_len;
|
||||
p++;
|
||||
memcpy(p, smac, mac_len);
|
||||
}
|
||||
|
||||
static int get_na_payload_len(struct net_device *dev)
|
||||
{
|
||||
/* Icmp Header Length
|
||||
* Number of bytes in the MAC address length field
|
||||
* MAC Address Length
|
||||
*/
|
||||
return sizeof(struct nip_icmp_hdr) + 1 + dev->addr_len;
|
||||
}
|
||||
|
||||
static void nndisc_send_na(struct net_device *dev,
|
||||
const struct nip_addr *daddr,
|
||||
const struct nip_addr *saddr)
|
||||
{
|
||||
int ret;
|
||||
struct sk_buff *skb = NULL;
|
||||
int payload_len = get_na_payload_len(dev);
|
||||
u_char *smac = dev->dev_addr;
|
||||
struct nip_hdr_encap head = {0};
|
||||
|
||||
head.saddr = *saddr;
|
||||
head.daddr = *daddr;
|
||||
head.ttl = NIP_ARP_DEFAULT_TTL;
|
||||
head.nexthdr = IPPROTO_NIP_ICMP;
|
||||
|
||||
skb = nndisc_alloc_skb(dev, &head, payload_len);
|
||||
if (!skb)
|
||||
/* If you add log here, there will be an alarm:
|
||||
* WARNING: Possible unnecessary 'out of memory' message
|
||||
*/
|
||||
return;
|
||||
/* build na header */
|
||||
build_na_hdr(smac, dev->addr_len, skb);
|
||||
|
||||
ret = nndisc_send_skb(dev, skb, &head, payload_len);
|
||||
if (ret)
|
||||
nip_dbg("dst output fail");
|
||||
}
|
||||
|
||||
bool nip_addr_local(struct net_device *dev, struct nip_addr *addr)
|
||||
{
|
||||
struct ninet_dev *idev;
|
||||
bool ret = false;
|
||||
|
||||
rcu_read_lock();
|
||||
idev = __nin_dev_get(dev);
|
||||
if (!idev)
|
||||
goto out;
|
||||
|
||||
read_lock_bh(&idev->lock);
|
||||
if (!list_empty(&idev->addr_list)) {
|
||||
struct ninet_ifaddr *ifp;
|
||||
|
||||
list_for_each_entry(ifp, &idev->addr_list, if_list) {
|
||||
if (nip_addr_eq(addr, &ifp->addr)) {
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&idev->lock);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nndisc_rcv_ns(struct sk_buff *skb)
|
||||
{
|
||||
struct nnd_msg *msg = (struct nnd_msg *)skb_transport_header(skb);
|
||||
u_char *p = msg->data;
|
||||
u_char *lladdr;
|
||||
struct nip_addr addr = {0};
|
||||
struct neighbour *neigh;
|
||||
struct ethhdr *eth;
|
||||
struct net_device *dev = skb->dev;
|
||||
int err = 0;
|
||||
|
||||
p = decode_nip_addr(p, &addr);
|
||||
if (!p) {
|
||||
nip_dbg("failure when decode source address");
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (nip_addr_invalid(&addr)) {
|
||||
nip_dbg("icmp hdr addr invalid, bitlen=%u", addr.bitlen);
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!nip_addr_local(dev, &addr)) {
|
||||
err = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
eth = (struct ethhdr *)skb_mac_header(skb);
|
||||
lladdr = eth->h_source;
|
||||
|
||||
/* checksum parse */
|
||||
if (!nip_get_nndisc_rcv_checksum(skb, p)) {
|
||||
nip_dbg("ns ICMP checksum failed, drop the packet");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
neigh = __neigh_lookup(&nnd_tbl, &NIPCB(skb)->srcaddr, dev, lladdr || !dev->addr_len);
|
||||
if (neigh) {
|
||||
neigh_update(neigh, lladdr, NUD_STALE, NEIGH_UPDATE_F_OVERRIDE, 0);
|
||||
neigh_release(neigh);
|
||||
}
|
||||
|
||||
nndisc_send_na(dev, &NIPCB(skb)->srcaddr, &addr);
|
||||
out:
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
int nndisc_rcv_na(struct sk_buff *skb)
|
||||
{
|
||||
struct nnd_msg *msg = (struct nnd_msg *)skb_transport_header(skb);
|
||||
u_char *p = msg->data;
|
||||
u_char len;
|
||||
u8 lladdr[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
|
||||
struct net_device *dev = skb->dev;
|
||||
struct neighbour *neigh;
|
||||
|
||||
len = *p;
|
||||
p++;
|
||||
memset(lladdr, 0, ALIGN(MAX_ADDR_LEN, sizeof(unsigned long)));
|
||||
memcpy(lladdr, p, len);
|
||||
|
||||
if (!nip_get_nndisc_rcv_checksum(skb, p + len)) {
|
||||
nip_dbg("na ICMP checksum failed, drop the packet");
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
neigh = neigh_lookup(&nnd_tbl, &NIPCB(skb)->srcaddr, dev);
|
||||
if (neigh) {
|
||||
neigh_update(neigh, lladdr, NUD_REACHABLE, NEIGH_UPDATE_F_OVERRIDE, 0);
|
||||
neigh_release(neigh);
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
int nndisc_rcv(struct sk_buff *skb)
|
||||
{
|
||||
int ret = 0;
|
||||
struct nip_icmp_hdr *hdr = nip_icmp_header(skb);
|
||||
u8 type = hdr->nip_icmp_type;
|
||||
|
||||
switch (type) {
|
||||
case NIP_ARP_NS:
|
||||
ret = nndisc_rcv_ns(skb);
|
||||
break;
|
||||
case NIP_ARP_NA:
|
||||
ret = nndisc_rcv_na(skb);
|
||||
break;
|
||||
default:
|
||||
nip_dbg("nd packet type error");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __init nndisc_init(void)
|
||||
{
|
||||
neigh_table_init(NEIGH_NND_TABLE, &nnd_tbl);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* NewIP INET protocol dispatch tables.
|
||||
*
|
||||
* Based on net/ipv6/protocol.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <net/protocol.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
const struct ninet_protocol __rcu *ninet_protos[MAX_INET_PROTOS] __read_mostly;
|
||||
|
||||
int ninet_add_protocol(const struct ninet_protocol *prot,
|
||||
unsigned char protocol)
|
||||
{
|
||||
return !cmpxchg((const struct ninet_protocol **)&ninet_protos[protocol],
|
||||
NULL, prot) ? 0 : -1;
|
||||
}
|
||||
|
||||
int ninet_del_protocol(const struct ninet_protocol *prot,
|
||||
unsigned char protocol)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = (cmpxchg((const struct ninet_protocol **)&ninet_protos[protocol],
|
||||
prot, NULL) == prot) ? 0 : -1;
|
||||
|
||||
synchronize_net();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,330 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Definitions for the NewIP parameter module.
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <net/dst.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/tcp_nip.h>
|
||||
#include <net/inet_common.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errqueue.h>
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* Newip protocol name */
|
||||
/*********************************************************************************************/
|
||||
int g_af_ninet = AF_NINET;
|
||||
module_param_named(af_ninet, g_af_ninet, int, 0444);
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* Rto timeout timer period (HZ/n) */
|
||||
/*********************************************************************************************/
|
||||
/* RTT RTO in the small-delay scenario */
|
||||
int g_nip_rto = 5;
|
||||
module_param_named(nip_rto, g_nip_rto, int, 0644);
|
||||
|
||||
int get_nip_rto(void)
|
||||
{
|
||||
return g_nip_rto;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* TCP sending and receiving buffer configuration */
|
||||
/*********************************************************************************************/
|
||||
int g_nip_sndbuf = 1050000; // 1M
|
||||
module_param_named(nip_sndbuf, g_nip_sndbuf, int, 0644);
|
||||
|
||||
int get_nip_sndbuf(void)
|
||||
{
|
||||
return g_nip_sndbuf;
|
||||
}
|
||||
|
||||
int g_nip_rcvbuf = 2000000; // 2M
|
||||
module_param_named(nip_rcvbuf, g_nip_rcvbuf, int, 0644);
|
||||
|
||||
int get_nip_rcvbuf(void)
|
||||
{
|
||||
return g_nip_rcvbuf;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* Window configuration */
|
||||
/*********************************************************************************************/
|
||||
/* Maximum receiving window */
|
||||
bool g_wscale_enable = 1;
|
||||
module_param_named(wscale_enable, g_wscale_enable, bool, 0644);
|
||||
|
||||
bool get_wscale_enable(void)
|
||||
{
|
||||
return g_wscale_enable;
|
||||
}
|
||||
|
||||
/* Window scale configuration, 2^n */
|
||||
int g_wscale = 7;
|
||||
module_param_named(wscale, g_wscale, int, 0644);
|
||||
|
||||
int get_wscale(void)
|
||||
{
|
||||
return g_wscale;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* Enables the debugging of special scenarios */
|
||||
/*********************************************************************************************/
|
||||
/* After receiving n packets, an ACK packet is sent */
|
||||
int g_ack_num = 5;
|
||||
module_param_named(ack_num, g_ack_num, int, 0644);
|
||||
|
||||
int get_ack_num(void)
|
||||
{
|
||||
return g_ack_num;
|
||||
}
|
||||
|
||||
/* Reset the packet sending window threshold after receiving n ACK packets */
|
||||
int g_nip_ssthresh_reset = 10000000; // 10M
|
||||
module_param_named(nip_ssthresh_reset, g_nip_ssthresh_reset, int, 0644);
|
||||
|
||||
int get_nip_ssthresh_reset(void)
|
||||
{
|
||||
return g_nip_ssthresh_reset;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* Retransmission parameters after ACK */
|
||||
/*********************************************************************************************/
|
||||
/* Three DUP ACK packets indicates the number of retransmission packets */
|
||||
int g_dup_ack_retrans_num = 5;
|
||||
module_param_named(dup_ack_retrans_num, g_dup_ack_retrans_num, int, 0644);
|
||||
|
||||
int get_dup_ack_retrans_num(void)
|
||||
{
|
||||
return g_dup_ack_retrans_num;
|
||||
}
|
||||
|
||||
/* Common ACK Indicates the number of retransmissions */
|
||||
int g_ack_retrans_num = 5;
|
||||
module_param_named(ack_retrans_num, g_ack_retrans_num, int, 0644);
|
||||
|
||||
int get_ack_retrans_num(void)
|
||||
{
|
||||
return g_ack_retrans_num;
|
||||
}
|
||||
|
||||
int g_dup_ack_snd_max = 6;
|
||||
module_param_named(dup_ack_snd_max, g_dup_ack_snd_max, int, 0644);
|
||||
|
||||
int get_dup_ack_snd_max(void)
|
||||
{
|
||||
return g_dup_ack_snd_max;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* RTT timestamp parameters */
|
||||
/*********************************************************************************************/
|
||||
int g_rtt_tstamp_rto_up = 100; // rtt_tstamp >= 100 ==> shorten rto
|
||||
module_param_named(rtt_tstamp_rto_up, g_rtt_tstamp_rto_up, int, 0644);
|
||||
|
||||
int get_rtt_tstamp_rto_up(void)
|
||||
{
|
||||
return g_rtt_tstamp_rto_up;
|
||||
}
|
||||
|
||||
int g_rtt_tstamp_high = 30; // rtt_tstamp >= 30 ==> ssthresh = 100K
|
||||
module_param_named(rtt_tstamp_high, g_rtt_tstamp_high, int, 0644);
|
||||
|
||||
int get_rtt_tstamp_high(void)
|
||||
{
|
||||
return g_rtt_tstamp_high;
|
||||
}
|
||||
|
||||
int g_rtt_tstamp_mid_high = 20; // rtt_tstamp >= 20 ==> ssthresh = 250K
|
||||
module_param_named(rtt_tstamp_mid_high, g_rtt_tstamp_mid_high, int, 0644);
|
||||
|
||||
int get_rtt_tstamp_mid_high(void)
|
||||
{
|
||||
return g_rtt_tstamp_mid_high;
|
||||
}
|
||||
|
||||
/* rtt_tstamp >= 10 ==> ssthresh = 1M (500K ~ 1M)
|
||||
* rtt_tstamp < 10 ==> ssthresh = 1.5M
|
||||
*/
|
||||
int g_rtt_tstamp_mid_low = 10;
|
||||
module_param_named(rtt_tstamp_mid_low, g_rtt_tstamp_mid_low, int, 0644);
|
||||
|
||||
int get_rtt_tstamp_mid_low(void)
|
||||
{
|
||||
return g_rtt_tstamp_mid_low;
|
||||
}
|
||||
|
||||
int g_ack_to_nxt_snd_tstamp = 500;
|
||||
module_param_named(ack_to_nxt_snd_tstamp, g_ack_to_nxt_snd_tstamp, int, 0644);
|
||||
|
||||
int get_ack_to_nxt_snd_tstamp(void)
|
||||
{
|
||||
return g_ack_to_nxt_snd_tstamp;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* Window threshold parameters */
|
||||
/*********************************************************************************************/
|
||||
bool g_ssthresh_enable = 1;
|
||||
module_param_named(ssthresh_enable, g_ssthresh_enable, bool, 0644);
|
||||
|
||||
bool get_ssthresh_enable(void)
|
||||
{
|
||||
return g_ssthresh_enable;
|
||||
}
|
||||
|
||||
int g_nip_ssthresh_default = 300000; // 300K
|
||||
module_param_named(nip_ssthresh_default, g_nip_ssthresh_default, int, 0644);
|
||||
|
||||
int get_nip_ssthresh_default(void)
|
||||
{
|
||||
return g_nip_ssthresh_default;
|
||||
}
|
||||
|
||||
int g_ssthresh_high = 1500000; // rtt_tstamp < 10 ==> ssthresh = 1.5M
|
||||
module_param_named(ssthresh_high, g_ssthresh_high, int, 0644);
|
||||
|
||||
int get_ssthresh_high(void)
|
||||
{
|
||||
return g_ssthresh_high;
|
||||
}
|
||||
|
||||
int g_ssthresh_mid_high = 1000000; // rtt_tstamp >= 10 ==> ssthresh = 1M (500K ~ 1M)
|
||||
module_param_named(ssthresh_mid_high, g_ssthresh_mid_high, int, 0644);
|
||||
|
||||
int get_ssthresh_mid_high(void)
|
||||
{
|
||||
return g_ssthresh_mid_high;
|
||||
}
|
||||
|
||||
int g_ssthresh_mid_low = 250000; // rtt_tstamp >= 20 ==> ssthresh = 250K
|
||||
module_param_named(ssthresh_mid_low, g_ssthresh_mid_low, int, 0644);
|
||||
|
||||
int get_ssthresh_mid_low(void)
|
||||
{
|
||||
return g_ssthresh_mid_low;
|
||||
}
|
||||
|
||||
int g_ssthresh_low = 100000; // rtt_tstamp >= 30 ==> ssthresh = 100K
|
||||
module_param_named(ssthresh_low, g_ssthresh_low, int, 0644);
|
||||
|
||||
int get_ssthresh_low(void)
|
||||
{
|
||||
return g_ssthresh_low;
|
||||
}
|
||||
|
||||
int g_ssthresh_low_min = 10000; // rtt_tstamp >= 100 ==> ssthresh = 10K
|
||||
module_param_named(ssthresh_low_min, g_ssthresh_low_min, int, 0644);
|
||||
|
||||
int get_ssthresh_low_min(void)
|
||||
{
|
||||
return g_ssthresh_low_min;
|
||||
}
|
||||
|
||||
int g_ssthresh_high_step = 1;
|
||||
module_param_named(ssthresh_high_step, g_ssthresh_high_step, int, 0644);
|
||||
|
||||
int get_ssthresh_high_step(void)
|
||||
{
|
||||
return g_ssthresh_high_step;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* keepalive parameters */
|
||||
/*********************************************************************************************/
|
||||
int g_nip_idle_ka_probes_out = 20;
|
||||
module_param_named(nip_idle_ka_probes_out, g_nip_idle_ka_probes_out, int, 0644);
|
||||
|
||||
int get_nip_idle_ka_probes_out(void)
|
||||
{
|
||||
return g_nip_idle_ka_probes_out;
|
||||
}
|
||||
|
||||
int g_nip_keepalive_time = 25;
|
||||
module_param_named(nip_keepalive_time, g_nip_keepalive_time, int, 0644);
|
||||
|
||||
int get_nip_keepalive_time(void)
|
||||
{
|
||||
return g_nip_keepalive_time;
|
||||
}
|
||||
|
||||
int g_nip_keepalive_intvl = 25;
|
||||
module_param_named(nip_keepalive_intvl, g_nip_keepalive_intvl, int, 0644);
|
||||
|
||||
int get_nip_keepalive_intvl(void)
|
||||
{
|
||||
return g_nip_keepalive_intvl;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* probe parameters */
|
||||
/*********************************************************************************************/
|
||||
int g_nip_probe_max = 2000;
|
||||
module_param_named(nip_probe_max, g_nip_probe_max, int, 0644);
|
||||
|
||||
int get_nip_probe_max(void)
|
||||
{
|
||||
return g_nip_probe_max;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* window mode parameters */
|
||||
/*********************************************************************************************/
|
||||
bool g_nip_tcp_snd_win_enable;
|
||||
module_param_named(nip_tcp_snd_win_enable, g_nip_tcp_snd_win_enable, bool, 0644);
|
||||
|
||||
bool get_nip_tcp_snd_win_enable(void)
|
||||
{
|
||||
return g_nip_tcp_snd_win_enable;
|
||||
}
|
||||
|
||||
bool g_nip_tcp_rcv_win_enable = true;
|
||||
module_param_named(nip_tcp_rcv_win_enable, g_nip_tcp_rcv_win_enable, bool, 0644);
|
||||
|
||||
bool get_nip_tcp_rcv_win_enable(void)
|
||||
{
|
||||
return g_nip_tcp_rcv_win_enable;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* nip debug parameters */
|
||||
/*********************************************************************************************/
|
||||
/* Debugging for control DEBUG */
|
||||
bool g_nip_debug;
|
||||
module_param_named(nip_debug, g_nip_debug, bool, 0644);
|
||||
|
||||
bool get_nip_debug(void)
|
||||
{
|
||||
return g_nip_debug;
|
||||
}
|
||||
|
||||
/* Debugging of threshold change */
|
||||
bool g_rtt_ssthresh_debug;
|
||||
module_param_named(rtt_ssthresh_debug, g_rtt_ssthresh_debug, bool, 0644);
|
||||
|
||||
bool get_rtt_ssthresh_debug(void)
|
||||
{
|
||||
return g_rtt_ssthresh_debug;
|
||||
}
|
||||
|
||||
/* Debugging of packet retransmission after ACK */
|
||||
bool g_ack_retrans_debug;
|
||||
module_param_named(ack_retrans_debug, g_ack_retrans_debug, bool, 0644);
|
||||
|
||||
bool get_ack_retrans_debug(void)
|
||||
{
|
||||
return g_ack_retrans_debug;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Definitions for the NewIP parameter module.
|
||||
*/
|
||||
#ifndef _TCP_NIP_PARAMETER_H
|
||||
#define _TCP_NIP_PARAMETER_H
|
||||
|
||||
int get_nip_rto(void);
|
||||
int get_nip_sndbuf(void);
|
||||
int get_nip_rcvbuf(void);
|
||||
bool get_wscale_enable(void);
|
||||
int get_wscale(void);
|
||||
int get_ack_num(void);
|
||||
int get_nip_ssthresh_reset(void);
|
||||
int get_dup_ack_retrans_num(void);
|
||||
int get_ack_retrans_num(void);
|
||||
int get_dup_ack_snd_max(void);
|
||||
int get_rtt_tstamp_rto_up(void);
|
||||
int get_rtt_tstamp_high(void);
|
||||
int get_rtt_tstamp_mid_high(void);
|
||||
int get_rtt_tstamp_mid_low(void);
|
||||
int get_ack_to_nxt_snd_tstamp(void);
|
||||
bool get_ssthresh_enable(void);
|
||||
int get_nip_ssthresh_default(void);
|
||||
int get_ssthresh_high(void);
|
||||
int get_ssthresh_mid_high(void);
|
||||
int get_ssthresh_mid_low(void);
|
||||
int get_ssthresh_low(void);
|
||||
int get_ssthresh_low_min(void);
|
||||
int get_ssthresh_high_step(void);
|
||||
int get_nip_idle_ka_probes_out(void);
|
||||
int get_nip_keepalive_time(void);
|
||||
int get_nip_keepalive_intvl(void);
|
||||
int get_nip_probe_max(void);
|
||||
bool get_nip_tcp_snd_win_enable(void);
|
||||
bool get_nip_tcp_rcv_win_enable(void);
|
||||
bool get_nip_debug(void);
|
||||
bool get_rtt_ssthresh_debug(void);
|
||||
bool get_ack_retrans_debug(void);
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* nip debug parameters */
|
||||
/*********************************************************************************************/
|
||||
#define nip_dbg(fmt, ...) \
|
||||
do { \
|
||||
if (get_nip_debug()) \
|
||||
pr_crit(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/* Debugging of threshold change */
|
||||
#define ssthresh_dbg(fmt, ...) \
|
||||
do { \
|
||||
if (get_rtt_ssthresh_debug()) \
|
||||
pr_crit(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/* Debugging of packet retransmission after ACK */
|
||||
#define retrans_dbg(fmt, ...) \
|
||||
do { \
|
||||
if (get_ack_retrans_debug()) \
|
||||
pr_crit(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#endif /* _TCP_NIP_PARAMETER_H */
|
||||
@@ -0,0 +1,414 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Implementation of the Transmission Control Protocol(TCP).
|
||||
*
|
||||
* Based on net/ipv4/tcp_timer.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <net/tcp_nip.h>
|
||||
#include <linux/module.h>
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
/**
|
||||
* tcp_nip_orphan_retries() - Returns maximal number of retries on an orphaned socket
|
||||
* @sk: Pointer to the current socket.
|
||||
* @alive: bool, socket alive state
|
||||
*/
|
||||
static int tcp_nip_orphan_retries(struct sock *sk, bool alive)
|
||||
{
|
||||
int retries = sock_net(sk)->ipv4.sysctl_tcp_orphan_retries; /* May be zero. */
|
||||
|
||||
/* We know from an ICMP that something is wrong. */
|
||||
if (sk->sk_err_soft && !alive)
|
||||
retries = 0;
|
||||
|
||||
/* However, if socket sent something recently, select some safe
|
||||
* number of retries. 8 corresponds to >100 seconds with minimal
|
||||
* RTO of 200msec.
|
||||
*/
|
||||
if (retries == 0 && alive)
|
||||
retries = 8;
|
||||
return retries;
|
||||
}
|
||||
|
||||
void tcp_nip_delack_timer_handler(struct sock *sk)
|
||||
{
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
|
||||
if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) ||
|
||||
!(icsk->icsk_ack.pending & ICSK_ACK_TIMER))
|
||||
goto out;
|
||||
|
||||
if (time_after(icsk->icsk_ack.timeout, jiffies)) {
|
||||
sk_reset_timer(sk, &icsk->icsk_delack_timer, icsk->icsk_ack.timeout);
|
||||
goto out;
|
||||
}
|
||||
icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER;
|
||||
|
||||
if (inet_csk_ack_scheduled(sk)) {
|
||||
icsk->icsk_ack.ato = TCP_ATO_MIN;
|
||||
tcp_mstamp_refresh(tcp_sk(sk));
|
||||
tcp_nip_send_ack(sk);
|
||||
__NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKS);
|
||||
}
|
||||
|
||||
out:;
|
||||
}
|
||||
|
||||
static void tcp_nip_write_err(struct sock *sk)
|
||||
{
|
||||
sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT;
|
||||
sk->sk_error_report(sk);
|
||||
/* Releasing TCP Resources */
|
||||
tcp_nip_done(sk);
|
||||
__NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONTIMEOUT);
|
||||
}
|
||||
|
||||
static void tcp_nip_delack_timer(struct timer_list *t)
|
||||
{
|
||||
struct inet_connection_sock *icsk =
|
||||
from_timer(icsk, t, icsk_delack_timer);
|
||||
struct sock *sk = &icsk->icsk_inet.sk;
|
||||
|
||||
bh_lock_sock(sk);
|
||||
if (!sock_owned_by_user(sk)) {
|
||||
tcp_nip_delack_timer_handler(sk);
|
||||
} else {
|
||||
__NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED);
|
||||
/* deleguate our work to tcp_release_cb() */
|
||||
if (!test_and_set_bit(TCP_NIP_DELACK_TIMER_DEFERRED, &sk->sk_tsq_flags))
|
||||
sock_hold(sk);
|
||||
}
|
||||
bh_unlock_sock(sk);
|
||||
sock_put(sk);
|
||||
}
|
||||
|
||||
static bool retransmits_nip_timed_out(struct sock *sk,
|
||||
unsigned int boundary,
|
||||
unsigned int timeout,
|
||||
bool syn_set)
|
||||
{
|
||||
/* Newip does not support the calculation of the timeout period based on the timestamp.
|
||||
* Currently, it determines whether the timeout period is based on
|
||||
* the retransmission times
|
||||
*/
|
||||
nip_dbg("icsk->retransmits=%u, boundary=%u",
|
||||
inet_csk(sk)->icsk_retransmits, boundary);
|
||||
return inet_csk(sk)->icsk_retransmits > boundary;
|
||||
}
|
||||
|
||||
static int tcp_nip_write_timeout(struct sock *sk)
|
||||
{
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
struct net *net = sock_net(sk);
|
||||
int retry_until;
|
||||
bool syn_set = false;
|
||||
|
||||
if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
|
||||
retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries;
|
||||
syn_set = true;
|
||||
} else {
|
||||
retry_until = net->ipv4.sysctl_tcp_retries2;
|
||||
if (sock_flag(sk, SOCK_DEAD)) {
|
||||
const bool alive = icsk->icsk_rto < TCP_RTO_MAX;
|
||||
|
||||
/* In the case of SOCK_DEAD, the retry_until value is smaller */
|
||||
retry_until = tcp_nip_orphan_retries(sk, alive);
|
||||
}
|
||||
}
|
||||
|
||||
if (retransmits_nip_timed_out(sk, retry_until,
|
||||
syn_set ? 0 : icsk->icsk_user_timeout, syn_set)) {
|
||||
nip_dbg("tcp retransmit time out");
|
||||
tcp_nip_write_err(sk);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tcp_nip_retransmit_timer(struct sock *sk)
|
||||
{
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
struct tcp_nip_common *ntp = &tcp_nip_sk(sk)->common;
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
struct sk_buff *skb = tcp_write_queue_head(sk);
|
||||
struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
|
||||
struct net *net = sock_net(sk);
|
||||
u32 icsk_rto_last;
|
||||
|
||||
if (!tp->packets_out)
|
||||
return;
|
||||
|
||||
if (tcp_nip_write_queue_empty(sk))
|
||||
return;
|
||||
|
||||
tp->tlp_high_seq = 0;
|
||||
|
||||
if (tcp_nip_write_timeout(sk))
|
||||
return;
|
||||
|
||||
if (tcp_nip_retransmit_skb(sk, skb, 1) > 0) {
|
||||
if (!icsk->icsk_retransmits)
|
||||
icsk->icsk_retransmits = 1;
|
||||
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
|
||||
min(icsk->icsk_rto, TCP_RESOURCE_PROBE_INTERVAL),
|
||||
TCP_RTO_MAX);
|
||||
|
||||
nip_dbg("seq %u retransmit fail, win=%u, rto=%u, pkt_out=%u, icsk_backoff=%u",
|
||||
scb->seq, ntp->nip_ssthresh,
|
||||
icsk->icsk_rto, tp->packets_out, icsk->icsk_backoff);
|
||||
return;
|
||||
}
|
||||
|
||||
if (icsk->icsk_backoff < net->ipv4.sysctl_tcp_retries2)
|
||||
icsk->icsk_backoff++;
|
||||
icsk->icsk_retransmits++;
|
||||
|
||||
icsk_rto_last = icsk->icsk_rto;
|
||||
/* 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 (sk->sk_state == TCP_ESTABLISHED &&
|
||||
(tp->thin_lto || net->ipv4.sysctl_tcp_thin_linear_timeouts) &&
|
||||
tcp_stream_is_thin(tp) &&
|
||||
icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) {
|
||||
icsk->icsk_backoff = 0;
|
||||
icsk->icsk_rto = min(__tcp_set_rto(tp), TCP_RTO_MAX);
|
||||
} else {
|
||||
/* Use normal (exponential) backoff */
|
||||
icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
|
||||
}
|
||||
|
||||
nip_dbg("seq %u, win[%u-%u] rto[%u-%u] pkt_out=%u, icsk_backoff=%u, retransmits=%u",
|
||||
scb->seq, ntp->nip_ssthresh, get_ssthresh_low(),
|
||||
icsk_rto_last, icsk->icsk_rto, tp->packets_out, icsk->icsk_backoff,
|
||||
icsk->icsk_retransmits);
|
||||
|
||||
ntp->nip_ssthresh = get_ssthresh_low();
|
||||
|
||||
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
|
||||
}
|
||||
|
||||
void tcp_nip_probe_timer(struct sock *sk)
|
||||
{
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
int max_probes;
|
||||
int icsk_backoff;
|
||||
int icsk_probes_out;
|
||||
|
||||
if (tp->packets_out || !tcp_nip_send_head(sk)) {
|
||||
icsk->icsk_probes_out = 0;
|
||||
icsk->icsk_probes_tstamp = 0;
|
||||
icsk->icsk_backoff = 0; /* V4 no modified this line */
|
||||
nip_dbg("packets_out(%u) not 0 or send_head is NULL, cancel probe0 timer",
|
||||
tp->packets_out);
|
||||
return;
|
||||
}
|
||||
|
||||
/* default: sock_net(sk)->ipv4.sysctl_tcp_retries2 */
|
||||
max_probes = get_nip_probe_max(); /* fix session auto close */
|
||||
|
||||
if (sock_flag(sk, SOCK_DEAD)) {
|
||||
const bool alive = inet_csk_rto_backoff(icsk, TCP_RTO_MAX) < TCP_RTO_MAX;
|
||||
|
||||
max_probes = tcp_nip_orphan_retries(sk, alive);
|
||||
nip_dbg("sock dead, icsk_backoff=%u, max_probes=%u, alive=%u",
|
||||
icsk->icsk_backoff, max_probes, alive);
|
||||
if (!alive && icsk->icsk_backoff >= max_probes) {
|
||||
nip_dbg("will close session, icsk_backoff=%u, max_probes=%u",
|
||||
icsk->icsk_backoff, max_probes);
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
if (icsk->icsk_probes_out >= max_probes) {
|
||||
abort: icsk_backoff = icsk->icsk_backoff;
|
||||
icsk_probes_out = icsk->icsk_probes_out;
|
||||
nip_dbg("close session, probes_out=%u, icsk_backoff=%u, max_probes=%u",
|
||||
icsk_probes_out, icsk_backoff, max_probes);
|
||||
tcp_nip_write_err(sk);
|
||||
} else {
|
||||
icsk_backoff = icsk->icsk_backoff;
|
||||
icsk_probes_out = icsk->icsk_probes_out;
|
||||
nip_dbg("will send probe0, probes_out=%u, icsk_backoff=%u, max_probes=%u",
|
||||
icsk_probes_out, icsk_backoff, max_probes);
|
||||
/* Only send another probe if we didn't close things up. */
|
||||
tcp_nip_send_probe0(sk);
|
||||
}
|
||||
}
|
||||
|
||||
void tcp_nip_write_timer_handler(struct sock *sk)
|
||||
{
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
int event;
|
||||
|
||||
if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) || !icsk->icsk_pending)
|
||||
return;
|
||||
|
||||
if (time_after(icsk->icsk_timeout, jiffies)) {
|
||||
sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout);
|
||||
return;
|
||||
}
|
||||
tcp_mstamp_refresh(tcp_sk(sk));
|
||||
event = icsk->icsk_pending;
|
||||
|
||||
switch (event) {
|
||||
case ICSK_TIME_RETRANS:
|
||||
icsk->icsk_pending = 0;
|
||||
tcp_nip_retransmit_timer(sk);
|
||||
break;
|
||||
case ICSK_TIME_PROBE0:
|
||||
icsk->icsk_pending = 0;
|
||||
tcp_nip_probe_timer(sk);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tcp_nip_write_timer(struct timer_list *t)
|
||||
{
|
||||
struct inet_connection_sock *icsk =
|
||||
from_timer(icsk, t, icsk_retransmit_timer);
|
||||
struct sock *sk = &icsk->icsk_inet.sk;
|
||||
|
||||
bh_lock_sock(sk);
|
||||
if (!sock_owned_by_user(sk)) {
|
||||
tcp_nip_write_timer_handler(sk);
|
||||
} else {
|
||||
/* delegate our work to tcp_release_cb() */
|
||||
if (!test_and_set_bit(TCP_NIP_WRITE_TIMER_DEFERRED, &sk->sk_tsq_flags))
|
||||
sock_hold(sk);
|
||||
}
|
||||
bh_unlock_sock(sk);
|
||||
sock_put(sk);
|
||||
}
|
||||
|
||||
static bool tcp_nip_keepalive_is_timeout(struct sock *sk, u32 elapsed)
|
||||
{
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
struct tcp_nip_common *ntp = &tcp_nip_sk(sk)->common;
|
||||
u32 keepalive_time = keepalive_time_when(tp);
|
||||
bool is_timeout = false;
|
||||
|
||||
/* keepalive set by setsockopt */
|
||||
if (keepalive_time > HZ) {
|
||||
/* If the TCP_USER_TIMEOUT option is enabled, use that
|
||||
* to determine when to timeout instead.
|
||||
*/
|
||||
if ((icsk->icsk_user_timeout != 0 &&
|
||||
elapsed >= msecs_to_jiffies(icsk->icsk_user_timeout) &&
|
||||
ntp->nip_keepalive_out > 0) ||
|
||||
(icsk->icsk_user_timeout == 0 &&
|
||||
ntp->nip_keepalive_out >= keepalive_probes(tp))) {
|
||||
nip_dbg("normal keepalive timeout, keepalive_out=%u",
|
||||
ntp->nip_keepalive_out);
|
||||
tcp_nip_write_err(sk);
|
||||
is_timeout = true;
|
||||
}
|
||||
}
|
||||
|
||||
return is_timeout;
|
||||
}
|
||||
|
||||
static void tcp_nip_keepalive_timer(struct timer_list *t)
|
||||
{
|
||||
struct sock *sk = from_timer(sk, t, sk_timer);
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
struct tcp_nip_common *ntp = &tcp_nip_sk(sk)->common;
|
||||
u32 elapsed;
|
||||
|
||||
/* Only process if socket is not in use. */
|
||||
bh_lock_sock(sk);
|
||||
if (sock_owned_by_user(sk)) {
|
||||
/* Try again later. */
|
||||
inet_csk_reset_keepalive_timer(sk, HZ / TCP_NIP_KEEPALIVE_CYCLE_MS_DIVISOR);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sk->sk_state == TCP_LISTEN) {
|
||||
nip_dbg("keepalive on a LISTEN");
|
||||
goto out;
|
||||
}
|
||||
tcp_mstamp_refresh(tp);
|
||||
/* 2022-02-18
|
||||
* NewIP TCP doesn't have TIME_WAIT state, so socket in TCP_CLOSING
|
||||
* uses keepalive timer to release socket.
|
||||
*/
|
||||
if ((sk->sk_state == TCP_FIN_WAIT2 || sk->sk_state == TCP_CLOSING) &&
|
||||
sock_flag(sk, SOCK_DEAD)) {
|
||||
nip_dbg("finish wait, close sock, sk_state=%u", sk->sk_state);
|
||||
goto death;
|
||||
}
|
||||
|
||||
if (!sock_flag(sk, SOCK_KEEPOPEN) ||
|
||||
((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)))
|
||||
goto out;
|
||||
|
||||
elapsed = keepalive_time_when(tp);
|
||||
|
||||
/* It is alive without keepalive 8) */
|
||||
if (tp->packets_out || !tcp_write_queue_empty(sk))
|
||||
goto resched;
|
||||
|
||||
elapsed = keepalive_time_elapsed(tp);
|
||||
if (elapsed >= keepalive_time_when(tp)) {
|
||||
if (tcp_nip_keepalive_is_timeout(sk, elapsed))
|
||||
goto out;
|
||||
|
||||
if (tcp_nip_write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) {
|
||||
ntp->nip_keepalive_out++;
|
||||
ntp->idle_ka_probes_out++;
|
||||
elapsed = keepalive_intvl_when(tp);
|
||||
} else {
|
||||
/* If keepalive was lost due to local congestion,
|
||||
* try harder.
|
||||
*/
|
||||
elapsed = TCP_RESOURCE_PROBE_INTERVAL;
|
||||
}
|
||||
} else {
|
||||
/* It is tp->rcv_tstamp + keepalive_time_when(tp) */
|
||||
elapsed = keepalive_time_when(tp) - elapsed;
|
||||
}
|
||||
|
||||
sk_mem_reclaim(sk);
|
||||
|
||||
resched:
|
||||
inet_csk_reset_keepalive_timer(sk, elapsed);
|
||||
goto out;
|
||||
|
||||
death:
|
||||
tcp_nip_done(sk);
|
||||
|
||||
out:
|
||||
tcp_nip_keepalive_disable(sk);
|
||||
bh_unlock_sock(sk);
|
||||
sock_put(sk);
|
||||
}
|
||||
|
||||
void tcp_nip_init_xmit_timers(struct sock *sk)
|
||||
{
|
||||
inet_csk_init_xmit_timers(sk, &tcp_nip_write_timer, &tcp_nip_delack_timer,
|
||||
&tcp_nip_keepalive_timer);
|
||||
}
|
||||
|
||||
void tcp_nip_clear_xmit_timers(struct sock *sk)
|
||||
{
|
||||
inet_csk_clear_xmit_timers(sk);
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
*
|
||||
* NewIP INET
|
||||
* An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. NewIP INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* The User Datagram Protocol (NewIP UDP).
|
||||
*
|
||||
* Based on net/ipv4/udp.c
|
||||
* Based on net/ipv6/udp.c
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/nip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <net/addrconf.h>
|
||||
#include <net/busy_poll.h>
|
||||
#include <net/nip.h>
|
||||
#include <net/nip_udp.h>
|
||||
#include <net/nip_fib.h>
|
||||
#include <net/nip_addrconf.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/raw.h>
|
||||
#include <net/sock_reuseport.h>
|
||||
#include <net/udp.h>
|
||||
#include "nip_hdr.h"
|
||||
#include "nip_checksum.h"
|
||||
#include "tcp_nip_parameter.h"
|
||||
|
||||
static u32 nip_udp_portaddr_hash(const struct net *net,
|
||||
const struct nip_addr *niaddr,
|
||||
u_short port)
|
||||
{
|
||||
u32 hash;
|
||||
u32 mix = net_hash_mix(net);
|
||||
|
||||
/* use nip_addr_hash() to obtain a hash result of nip_addr */
|
||||
hash = jhash_1word(nip_addr_hash(niaddr), mix);
|
||||
|
||||
return hash ^ port;
|
||||
}
|
||||
|
||||
/* Called during the bind & sendto procedure, bind ports */
|
||||
int nip_udp_get_port(struct sock *sk, unsigned short snum)
|
||||
{
|
||||
unsigned int hash2_nulladdr, hash2_partial;
|
||||
|
||||
hash2_nulladdr = nip_udp_portaddr_hash(sock_net(sk), &nip_any_addr, snum);
|
||||
/* hash2_partial is the hash result of nip_addr only */
|
||||
hash2_partial = nip_udp_portaddr_hash(sock_net(sk), &sk->sk_nip_rcv_saddr, 0);
|
||||
|
||||
/* precompute partial secondary hash */
|
||||
udp_sk(sk)->udp_portaddr_hash = hash2_partial;
|
||||
return udp_lib_get_port(sk, snum, hash2_nulladdr);
|
||||
}
|
||||
|
||||
static int nip_udp_compute_score(struct sock *sk, struct net *net,
|
||||
const struct nip_addr *saddr, __be16 sport,
|
||||
const struct nip_addr *daddr, unsigned short hnum,
|
||||
int dif, int sdif)
|
||||
{
|
||||
int score = 0;
|
||||
struct inet_sock *inet;
|
||||
|
||||
if (!net_eq(sock_net(sk), net) ||
|
||||
udp_sk(sk)->udp_port_hash != hnum ||
|
||||
sk->sk_family != PF_NINET)
|
||||
return -1;
|
||||
|
||||
/* Destination port of the peer device
|
||||
* In the header sent by the peer end, it is the source port
|
||||
*/
|
||||
inet = inet_sk(sk);
|
||||
if (inet->inet_dport) {
|
||||
if (inet->inet_dport != sport)
|
||||
return -1;
|
||||
score++;
|
||||
}
|
||||
|
||||
/* Source ADDRESS of the local device
|
||||
* In the header sent by the peer device, it is the destination address
|
||||
*/
|
||||
if (!nip_addr_any(&sk->sk_nip_rcv_saddr)) {
|
||||
if (!nip_addr_eq(&sk->sk_nip_rcv_saddr, daddr))
|
||||
return -1;
|
||||
score++;
|
||||
}
|
||||
|
||||
/* Address of the peer device
|
||||
* In the packet header sent by the peer device, is the source ADDRESS
|
||||
*/
|
||||
if (!nip_addr_any(&sk->sk_nip_daddr)) {
|
||||
if (!nip_addr_eq(&sk->sk_nip_daddr, saddr))
|
||||
return -1;
|
||||
score++;
|
||||
}
|
||||
|
||||
/* Check the dev index */
|
||||
if (sk->sk_bound_dev_if) {
|
||||
bool dev_match = dif == sk->sk_bound_dev_if || sdif == sk->sk_bound_dev_if;
|
||||
|
||||
if (!dev_match)
|
||||
return -1;
|
||||
score++;
|
||||
}
|
||||
|
||||
if (sk->sk_incoming_cpu == raw_smp_processor_id())
|
||||
score++;
|
||||
return score;
|
||||
}
|
||||
|
||||
static struct sock *nip_udp_lib_lookup2(struct net *net,
|
||||
const struct nip_addr *saddr,
|
||||
u_short sport,
|
||||
const struct nip_addr *daddr,
|
||||
unsigned short hnum,
|
||||
int dif, int sdif,
|
||||
struct udp_hslot *hslot2,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct sock *sk;
|
||||
struct sock *result = NULL;
|
||||
int badness = -1;
|
||||
|
||||
udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
|
||||
int score = nip_udp_compute_score(sk, net, saddr, sport, daddr, hnum, dif, sdif);
|
||||
|
||||
if (score > badness) {
|
||||
result = sk;
|
||||
badness = score;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* rcu_read_lock() must be held */
|
||||
struct sock *__nip_udp_lib_lookup(struct net *net,
|
||||
const struct nip_addr *saddr, __be16 sport,
|
||||
const struct nip_addr *daddr, __be16 dport,
|
||||
int dif, int sdif, struct udp_table *udptable,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
unsigned short hnum = ntohs(dport);
|
||||
unsigned int hash2, slot2;
|
||||
struct udp_hslot *hslot2;
|
||||
struct sock *result;
|
||||
|
||||
hash2 = nip_udp_portaddr_hash(net, daddr, hnum);
|
||||
slot2 = hash2 & udptable->mask;
|
||||
hslot2 = &udptable->hash2[slot2];
|
||||
|
||||
/* Lookup connected or non-wildcard sockets */
|
||||
result = nip_udp_lib_lookup2(net, saddr, sport,
|
||||
daddr, hnum, dif, sdif,
|
||||
hslot2, skb);
|
||||
if (!IS_ERR_OR_NULL(result))
|
||||
goto done;
|
||||
|
||||
/* Lookup wildcard sockets */
|
||||
hash2 = nip_udp_portaddr_hash(net, &nip_any_addr, hnum);
|
||||
slot2 = hash2 & udptable->mask;
|
||||
hslot2 = &udptable->hash2[slot2];
|
||||
|
||||
result = nip_udp_lib_lookup2(net, saddr, sport,
|
||||
&nip_any_addr, hnum, dif, sdif,
|
||||
hslot2, skb);
|
||||
done:
|
||||
if (IS_ERR(result))
|
||||
return NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct sock *__nip_udp_lib_lookup_skb(struct sk_buff *skb,
|
||||
__be16 sport, __be16 dport,
|
||||
struct udp_table *udptable)
|
||||
{
|
||||
return __nip_udp_lib_lookup(dev_net(skb->dev),
|
||||
&NIPCB(skb)->srcaddr, sport,
|
||||
&NIPCB(skb)->dstaddr, dport, skb->skb_iif,
|
||||
0, udptable, skb);
|
||||
}
|
||||
|
||||
void udp_table_del(struct sock *sk)
|
||||
{
|
||||
udp_lib_unhash(sk);
|
||||
}
|
||||
|
||||
int nip_udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
||||
int noblock, int flags, int *addr_len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
unsigned int ulen, copied;
|
||||
int peeking, off, datalen;
|
||||
int err;
|
||||
|
||||
off = sk_peek_offset(sk, flags);
|
||||
peeking = off; /* Fetch the SKB from the queue */
|
||||
skb = __skb_recv_udp(sk, flags, noblock, &off, &err);
|
||||
if (!skb)
|
||||
return err;
|
||||
ulen = skb->len;
|
||||
copied = len;
|
||||
if (copied > ulen - off)
|
||||
copied = ulen - off;
|
||||
else if (copied < ulen)
|
||||
msg->msg_flags |= MSG_TRUNC;
|
||||
|
||||
/* copy data */
|
||||
datalen = copy_to_iter(skb->data, copied, &msg->msg_iter);
|
||||
if (datalen < 0) {
|
||||
nip_dbg("copy to iter in failure, len=%d", datalen);
|
||||
err = -EFAULT;
|
||||
return err;
|
||||
}
|
||||
|
||||
sock_recv_ts_and_drops(msg, sk, skb);
|
||||
/* Update information such as the timestamp received
|
||||
* by the last datagram in the transport control block
|
||||
*/
|
||||
/* copy the address */
|
||||
if (msg->msg_name) {
|
||||
DECLARE_SOCKADDR(struct sockaddr_nin *, sin, msg->msg_name);
|
||||
|
||||
sin->sin_family = AF_NINET;
|
||||
sin->sin_port = udp_hdr(skb)->source;
|
||||
sin->sin_addr = NIPCB(skb)->srcaddr;
|
||||
*addr_len = sizeof(*sin);
|
||||
}
|
||||
|
||||
err = copied;
|
||||
if (flags & MSG_TRUNC)
|
||||
err = ulen;
|
||||
|
||||
skb_consume_udp(sk, skb, peeking ? -err : err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void nip_udp_err(struct sk_buff *skb,
|
||||
struct ninet_skb_parm *opt,
|
||||
u8 type,
|
||||
u8 code, int offset,
|
||||
__be32 info)
|
||||
{
|
||||
}
|
||||
|
||||
static int __nip_udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
int rc;
|
||||
|
||||
sk_incoming_cpu_update(sk);
|
||||
|
||||
rc = __udp_enqueue_schedule_skb(sk, skb);
|
||||
if (rc < 0) {
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool nip_get_udp_input_checksum(struct sk_buff *skb)
|
||||
{
|
||||
struct nip_pseudo_header nph = {0};
|
||||
struct udphdr *udphead = udp_hdr(skb);
|
||||
unsigned short check_len = ntohs(udphead->len);
|
||||
|
||||
nph.nexthdr = NIPCB(skb)->nexthdr;
|
||||
nph.saddr = NIPCB(skb)->srcaddr;
|
||||
nph.daddr = NIPCB(skb)->dstaddr;
|
||||
nph.check_len = udphead->len;
|
||||
|
||||
return nip_check_sum_parse(skb_transport_header(skb), check_len, &nph)
|
||||
== 0xffff ? true : false;
|
||||
}
|
||||
|
||||
/* Udp packets are received at the network layer */
|
||||
int nip_udp_input(struct sk_buff *skb)
|
||||
{
|
||||
struct sock *sk;
|
||||
int rc = 0;
|
||||
struct udphdr *udphead = udp_hdr(skb);
|
||||
|
||||
if (!nip_get_udp_input_checksum(skb)) {
|
||||
nip_dbg("checksum failed, drop the packet");
|
||||
kfree_skb(skb);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
sk = __nip_udp_lib_lookup_skb(skb, udphead->source,
|
||||
udphead->dest, &udp_table);
|
||||
if (!sk) {
|
||||
nip_dbg("dport not match, drop the packet. sport=%u, dport=%u, data_len=%u",
|
||||
ntohs(udphead->source), ntohs(udphead->dest), ntohs(udphead->len));
|
||||
kfree_skb(skb);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
skb_pull(skb, sizeof(struct udphdr));
|
||||
skb->len = ntohs(udphead->len) - sizeof(struct udphdr);
|
||||
|
||||
skb_dst_drop(skb);
|
||||
/* enqueue */
|
||||
rc = __nip_udp_queue_rcv_skb(sk, skb);
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int nip_udp_output(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
{
|
||||
DECLARE_SOCKADDR(struct sockaddr_nin *, sin, msg->msg_name);
|
||||
struct flow_nip fln;
|
||||
u_short sport, dport;
|
||||
struct dst_entry *dst;
|
||||
int err = 0;
|
||||
struct inet_sock *inet;
|
||||
|
||||
if (!sin)
|
||||
/* Currently, udp socket Connect function is not implemented.
|
||||
* The destination address and port must be directly provided by Sendto
|
||||
*/
|
||||
return -EDESTADDRREQ;
|
||||
|
||||
if (sin->sin_family != AF_NINET) {
|
||||
nip_dbg("sin_family false");
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
if (nip_addr_invalid(&sin->sin_addr)) {
|
||||
nip_dbg("sin_addr false");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
inet = inet_sk(sk);
|
||||
/* Destination address, port (network order) must be specified when sendto */
|
||||
dport = sin->sin_port;
|
||||
fln.daddr = sin->sin_addr;
|
||||
sport = htons(inet->inet_num);
|
||||
|
||||
/* Check the dev index */
|
||||
fln.flowin_oif = sk->sk_bound_dev_if;
|
||||
|
||||
/* Query the route & Obtain the Saddr */
|
||||
dst = nip_sk_dst_lookup_flow(sk, &fln);
|
||||
if (IS_ERR(dst)) {
|
||||
err = PTR_ERR(dst);
|
||||
dst = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = _nip_udp_output(sk, msg, len,
|
||||
sizeof(struct udphdr), &fln.saddr,
|
||||
sport, &fln.daddr,
|
||||
dport, dst);
|
||||
|
||||
out:
|
||||
dst_release(dst);
|
||||
if (!err)
|
||||
return len;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Close the connection using */
|
||||
void nip_udp_destroy_sock(struct sock *sk)
|
||||
{
|
||||
udp_table_del(sk);
|
||||
ninet_destroy_sock(sk);
|
||||
}
|
||||
|
||||
/* socket option code for udp */
|
||||
int nip_udp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
|
||||
unsigned int optlen)
|
||||
{
|
||||
if (level == SOL_UDP || level == SOL_UDPLITE)
|
||||
return 0;
|
||||
return nip_setsockopt(sk, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int nip_udp_getsockopt(struct sock *sk, int level,
|
||||
int optname, char __user *optval,
|
||||
int __user *optlen)
|
||||
{
|
||||
if (level == SOL_UDP || level == SOL_UDPLITE)
|
||||
return 0;
|
||||
return nip_getsockopt(sk, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
static const struct ninet_protocol nip_udp_protocol = {
|
||||
.handler = nip_udp_input,
|
||||
.err_handler = nip_udp_err,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
/* Newip Udp related operations */
|
||||
struct proto nip_udp_prot = {
|
||||
.name = "nip_udp",
|
||||
.owner = THIS_MODULE,
|
||||
.close = udp_lib_close,
|
||||
.disconnect = udp_disconnect,
|
||||
.ioctl = udp_ioctl,
|
||||
.init = udp_init_sock,
|
||||
.destroy = nip_udp_destroy_sock,
|
||||
.setsockopt = nip_udp_setsockopt,
|
||||
.getsockopt = nip_udp_getsockopt,
|
||||
.sendmsg = nip_udp_output,
|
||||
.recvmsg = nip_udp_recvmsg,
|
||||
.backlog_rcv = __nip_udp_queue_rcv_skb,
|
||||
.hash = udp_lib_hash,
|
||||
.unhash = udp_lib_unhash,
|
||||
.get_port = nip_udp_get_port,
|
||||
.memory_allocated = &udp_memory_allocated,
|
||||
.sysctl_mem = sysctl_udp_mem,
|
||||
.obj_size = sizeof(struct nip_udp_sock),
|
||||
.h.udp_table = &udp_table,
|
||||
.diag_destroy = udp_abort,
|
||||
};
|
||||
|
||||
/* Example Create newip socket information */
|
||||
static struct inet_protosw nip_udp_protosw = {
|
||||
.type = SOCK_DGRAM,
|
||||
.protocol = IPPROTO_UDP,
|
||||
.prot = &nip_udp_prot,
|
||||
.ops = &ninet_dgram_ops,
|
||||
.flags = INET_PROTOSW_PERMANENT,
|
||||
};
|
||||
|
||||
/* Af_NINET initializes the call */
|
||||
int __init nip_udp_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ninet_add_protocol(&nip_udp_protocol, IPPROTO_UDP);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = ninet_register_protosw(&nip_udp_protosw);
|
||||
if (ret)
|
||||
goto out_nip_udp_protocol;
|
||||
out:
|
||||
return ret;
|
||||
|
||||
out_nip_udp_protocol:
|
||||
ninet_del_protocol(&nip_udp_protocol, IPPROTO_UDP);
|
||||
goto out;
|
||||
}
|
||||
|
||||
void nip_udp_exit(void)
|
||||
{
|
||||
ninet_unregister_protosw(&nip_udp_protosw);
|
||||
ninet_del_protocol(&nip_udp_protocol, IPPROTO_UDP);
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
require "bit32"
|
||||
--[[
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
Function : wireshark lua configure for NewIP protocol stack
|
||||
Author : yangyanjun
|
||||
Edit Date : 2022/5/27
|
||||
--]]
|
||||
|
||||
do -- lua begin
|
||||
|
||||
--协议名称为NewIP,在Packet Details窗格显示为NewIP
|
||||
-- create a new protocol
|
||||
local nip_proto_name = "NewIP"
|
||||
local nip_proto_desc = "NewIP Protocol"
|
||||
local nip_proto_obj = Proto(nip_proto_name, nip_proto_desc)
|
||||
|
||||
--[[
|
||||
NewIP协议字段定义
|
||||
ProtoField 参数:
|
||||
para1 [必选] - 字段的缩写名称(过滤器中使用的字符串)
|
||||
para2 [可选] - 字段的实际名称(出现在树中的字符串)
|
||||
para3 [可选] - 字段类型
|
||||
--]]
|
||||
--[[
|
||||
ProtoField.{type}(abbr, [name], [base], [valuestring], [mask], [desc])
|
||||
·type包括:uint8, uint16, uint24, uint32, uint64, framenum, float, double, string, stringz, bytes, bool, ipv4, ipv6, ether,oid, guid
|
||||
|
||||
abbr 字段的缩写名称(过滤器中使用的字符串)。
|
||||
name (optional) 字段的实际名称(出现在树中的字符串)。
|
||||
base (optional) base.DEC,base.HEX或base.OCT,base.DEC_HEX,base.HEX_DEC,base.UNIT_STRING或base.RANGE_STRING。
|
||||
valuestring (optional) 包含与值对应的文本的表,或包含与值 ({min, max, “string”}) 对应的范围字符串值表的表(如果基数为 )base.RANGE_STRING,
|
||||
或包含单位名称的表如果 base 是base.UNIT_STRING.
|
||||
mask (optional) 此字段的整数掩码。
|
||||
desc (optional) 字段说明。
|
||||
|
||||
--]]
|
||||
local _ttl = ProtoField.uint8 (nip_proto_name .. ".ttl", "ttl ( 1 Byte)", base.DEC)
|
||||
local _total_len = ProtoField.uint16(nip_proto_name .. ".total_len", "total_len ( 2 Byte)", base.DEC)
|
||||
local _nexthdr = ProtoField.uint8 (nip_proto_name .. ".nexthdr", "nexthdr ( 1 Byte)", base.DEC)
|
||||
local _daddr = ProtoField.bytes (nip_proto_name .. ".daddr", "daddr (1~8 Byte)", base.SPACE)
|
||||
local _saddr = ProtoField.bytes (nip_proto_name .. ".saddr", "saddr (1~8 Byte)", base.SPACE)
|
||||
local _hdr_len = ProtoField.uint8 (nip_proto_name .. ".hdr_len", "hdr_len ( 1 Byte)", base.DEC)
|
||||
local _trans_data = ProtoField.bytes (nip_proto_name .. ".trans_data", "trans_data", base.SPACE)
|
||||
|
||||
-- 将字段添加都协议中
|
||||
nip_proto_obj.fields = {
|
||||
_ttl,
|
||||
_total_len,
|
||||
_nexthdr,
|
||||
_daddr,
|
||||
_saddr,
|
||||
_hdr_len,
|
||||
_trans_data
|
||||
}
|
||||
--获取 _trans_data 解析器
|
||||
local _unknown_data_dis = Dissector.get("data")
|
||||
|
||||
--定义 bitmap1 子菜单
|
||||
-- create a new protocol
|
||||
local bitmap1_name = "bitmap1"
|
||||
local bitmap1_desc = "bitmap1"
|
||||
local bitmap1_obj = Proto(bitmap1_name, bitmap1_desc)
|
||||
|
||||
--[[
|
||||
bitmap1 子菜单字段定义
|
||||
ProtoField 参数:
|
||||
para1 [必选] - 字段的缩写名称(过滤器中使用的字符串)
|
||||
para2 [可选] - 字段的实际名称(出现在树中的字符串)
|
||||
para3 [可选] - 字段类型
|
||||
--]]
|
||||
local _bitmap1 = ProtoField.uint8(bitmap1_name .. ".bitmap1", "bitmap1", base.HEX)
|
||||
local _pkt_hdr_type = ProtoField.uint8(bitmap1_name .. ".pkt_hdr_type", "pkt_hdr_type ", base.DEC, Payload_type, 0x80) --_bitmap1的8bit
|
||||
local _include_ttl = ProtoField.uint8(bitmap1_name .. ".include_ttl", "include_ttl ", base.DEC, Payload_type, 0x40) --_bitmap1的7bit
|
||||
local _include_total_len = ProtoField.uint8(bitmap1_name .. ".include_total_len", "include_total_len", base.DEC, Payload_type, 0x20) --_bitmap1的6bit
|
||||
local _include_nexthdr = ProtoField.uint8(bitmap1_name .. ".include_nexthdr", "include_nexthdr ", base.DEC, Payload_type, 0x10) --_bitmap1的5bit
|
||||
local _include_reserve1 = ProtoField.uint8(bitmap1_name .. ".include_reserve1", "include_reserve1 ", base.DEC, Payload_type, 0x08) --_bitmap1的4bit
|
||||
local _include_daddr = ProtoField.uint8(bitmap1_name .. ".include_daddr", "include_daddr ", base.DEC, Payload_type, 0x04) --_bitmap1的3bit
|
||||
local _include_saddr = ProtoField.uint8(bitmap1_name .. ".include_saddr", "include_saddr ", base.DEC, Payload_type, 0x02) --_bitmap1的2bit
|
||||
local _include_bitmap2 = ProtoField.uint8(bitmap1_name .. ".include_bitmap2", "include_bitmap2 ", base.DEC, Payload_type, 0x01) --_bitmap1的1bit
|
||||
|
||||
-- 将字段添加都协议中
|
||||
bitmap1_obj.fields = {
|
||||
_bitmap1, _pkt_hdr_type, _include_ttl, _include_total_len, _include_nexthdr,
|
||||
_include_reserve1, _include_daddr, _include_saddr, _include_bitmap2
|
||||
}
|
||||
|
||||
--定义 bitmap2 子菜单
|
||||
-- create a new protocol
|
||||
local bitmap2_name = "bitmap2"
|
||||
local bitmap2_desc = "bitmap2"
|
||||
local bitmap2_obj = Proto(bitmap2_name, bitmap2_desc)
|
||||
|
||||
--[[
|
||||
bitmap2 子菜单字段定义
|
||||
ProtoField 参数:
|
||||
para1 [必选] - 字段的缩写名称(过滤器中使用的字符串)
|
||||
para2 [可选] - 字段的实际名称(出现在树中的字符串)
|
||||
para3 [可选] - 字段类型
|
||||
--]]
|
||||
local _bitmap2 = ProtoField.uint8(bitmap2_name .. ".bitmap2", "bitmap2", base.HEX)
|
||||
local _include_hdr_len = ProtoField.uint8(bitmap2_name .. ".include_hdr_len", "include_hdr_len ", base.DEC, Payload_type, 0x80) --_bitmap2的8bit
|
||||
local _include_reserve2 = ProtoField.uint8(bitmap2_name .. ".include_reserve2", "include_reserve2", base.DEC, Payload_type, 0x40) --_bitmap2的7bit
|
||||
local _include_reserve3 = ProtoField.uint8(bitmap2_name .. ".include_reserve3", "include_reserve3", base.DEC, Payload_type, 0x20) --_bitmap2的6bit
|
||||
local _include_reserve4 = ProtoField.uint8(bitmap2_name .. ".include_reserve4", "include_reserve4", base.DEC, Payload_type, 0x10) --_bitmap2的5bit
|
||||
local _include_reserve5 = ProtoField.uint8(bitmap2_name .. ".include_reserve5", "include_reserve5", base.DEC, Payload_type, 0x08) --_bitmap2的4bit
|
||||
local _include_reserve6 = ProtoField.uint8(bitmap2_name .. ".include_reserve6", "include_reserve6", base.DEC, Payload_type, 0x04) --_bitmap2的3bit
|
||||
local _include_reserve7 = ProtoField.uint8(bitmap2_name .. ".include_reserve7", "include_reserve7", base.DEC, Payload_type, 0x02) --_bitmap2的2bit
|
||||
local _include_bitmap3 = ProtoField.uint8(bitmap2_name .. ".include_bitmap3", "include_bitmap3 ", base.DEC, Payload_type, 0x01) --_bitmap2的1bit
|
||||
|
||||
-- 将字段添加都协议中
|
||||
bitmap2_obj.fields = {
|
||||
_bitmap2, _include_hdr_len, _include_reserve2, _include_reserve3, _include_reserve4,
|
||||
_include_reserve5, _include_reserve6, _include_reserve7, _include_bitmap3
|
||||
}
|
||||
|
||||
--定义 nd icmp 子菜单
|
||||
-- create a new protocol
|
||||
local nd_icmp_name = "nd_icmp"
|
||||
local nd_icmp_desc = "nd_icmp"
|
||||
local nd_icmp_obj = Proto(nd_icmp_name, nd_icmp_desc)
|
||||
|
||||
--[[
|
||||
nd_icmp 子菜单字段定义
|
||||
ProtoField 参数:
|
||||
para1 [必选] - 字段的缩写名称(过滤器中使用的字符串)
|
||||
para2 [可选] - 字段的实际名称(出现在树中的字符串)
|
||||
para3 [可选] - 字段类型
|
||||
--]]
|
||||
local _type = ProtoField.uint8 (nd_icmp_name .. ".type", "type ( 1 Byte)", base.DEC)
|
||||
local _code = ProtoField.uint8 (nd_icmp_name .. ".code", "code ( 1 Byte)", base.DEC)
|
||||
local _checksum = ProtoField.uint16(nd_icmp_name .. ".checksum", "checksum( 2 Byte)", base.HEX)
|
||||
local _rs_daddr = ProtoField.bytes (nd_icmp_name .. ".rs_daddr", "rs_daddr(1~8 Byte)", base.SPACE)
|
||||
local _mac_len = ProtoField.uint8 (nd_icmp_name .. ".mac_len", "mac_len ( 1 Byte)", base.DEC)
|
||||
local _mac = ProtoField.bytes (nd_icmp_name .. ".mac", "mac ( 6 Byte)", base.SPACE)
|
||||
|
||||
-- 将字段添加都协议中
|
||||
nd_icmp_obj.fields = {
|
||||
_type, _code, _checksum, _rs_daddr, _mac_len, _mac
|
||||
}
|
||||
|
||||
--[[
|
||||
下面定义 newip 解析器的主函数
|
||||
第一个参数是 tvb 类型,表示的是需要此解析器解析的数据
|
||||
第二个参数是 pinfo 类型,是协议解析树上的信息,包括 UI 上的显示
|
||||
第三个参数是 treeitem 类型,表示上一级解析树
|
||||
--]]
|
||||
function nip_dissector(tvb, pinfo, treeitem)
|
||||
--设置一些 UI 上面的信息
|
||||
pinfo.cols.protocol:set(nip_proto_name)
|
||||
pinfo.cols.info:set(nip_proto_desc)
|
||||
|
||||
local offset = 0
|
||||
local tvb_len = tvb:len()
|
||||
local nexthdr = 0
|
||||
|
||||
-- 在上一级解析树上创建 nip 的根节点
|
||||
local nip_tree = treeitem:add(nip_proto_obj, tvb:range(tvb_len))
|
||||
|
||||
local bitmap1 = tvb(offset, 1):uint() --表示从报文缓冲区0开始取1个字节
|
||||
local pkt_hdr_type = bit.band(bit.rshift(bitmap1, 7), 0x00000001) --右移 7 位 与 0x01 相与,获取 pkt_hdr_type 位
|
||||
local include_ttl = bit.band(bit.rshift(bitmap1, 6), 0x00000001) --右移 6 位 与 0x01 相与,获取 include_ttl 位
|
||||
local include_total_len = bit.band(bit.rshift(bitmap1, 5), 0x00000001) --右移 5 位 与 0x01 相与,获取 include_total_len 位
|
||||
local include_nexthdr = bit.band(bit.rshift(bitmap1, 4), 0x00000001) --右移 4 位 与 0x01 相与,获取 include_nexthdr 位
|
||||
local include_daddr = bit.band(bit.rshift(bitmap1, 2), 0x00000001) --右移 2 位 与 0x01 相与,获取 include_daddr 位
|
||||
local include_saddr = bit.band(bit.rshift(bitmap1, 1), 0x00000001) --右移 1 位 与 0x01 相与,获取 include_saddr 位
|
||||
local include_bitmap2 = bit.band(bitmap1, 0x00000001) --获取 include_bitmap2 位
|
||||
|
||||
--nip报头无效(0表示有效)
|
||||
if pkt_hdr_type ~= 0 then
|
||||
return false
|
||||
else
|
||||
--bitmap1子菜单
|
||||
local bitmap1_tree = nip_tree:add(bitmap1_obj, tvb:range(tvb_len))
|
||||
bitmap1_tree:add(_bitmap1, bitmap1)
|
||||
bitmap1_tree:add(_pkt_hdr_type, bitmap1):append_text(" (".."0-New IP; 1-Reserve"..")")
|
||||
bitmap1_tree:add(_include_ttl, bitmap1)
|
||||
bitmap1_tree:add(_include_total_len, bitmap1)
|
||||
bitmap1_tree:add(_include_nexthdr, bitmap1)
|
||||
bitmap1_tree:add(_include_reserve1, bitmap1)
|
||||
bitmap1_tree:add(_include_daddr, bitmap1)
|
||||
bitmap1_tree:add(_include_saddr, bitmap1)
|
||||
bitmap1_tree:add(_include_bitmap2, bitmap1)
|
||||
offset = offset + 1 --_bitmap1 占用1字节
|
||||
end
|
||||
|
||||
local include_hdr_len = 0
|
||||
if include_bitmap2 ~= 0 then
|
||||
--bitmap2子菜单
|
||||
local bitmap2_tree = nip_tree:add(bitmap2_obj, tvb:range(tvb_len))
|
||||
local bitmap2 = tvb(offset, 1):uint()
|
||||
include_hdr_len = bit.band(bit.rshift(bitmap2, 7), 0x00000001) --右移 7 位 与 0x01 相与,获取 include_hdr_len 位
|
||||
offset = offset + 1 --_bitmap2 占用1字节
|
||||
|
||||
bitmap2_tree:add(_bitmap2, bitmap2)
|
||||
bitmap2_tree:add(_include_hdr_len, bitmap2)
|
||||
bitmap2_tree:add(_include_reserve2, bitmap2)
|
||||
bitmap2_tree:add(_include_reserve3, bitmap2)
|
||||
bitmap2_tree:add(_include_reserve4, bitmap2)
|
||||
bitmap2_tree:add(_include_reserve5, bitmap2)
|
||||
bitmap2_tree:add(_include_reserve6, bitmap2)
|
||||
bitmap2_tree:add(_include_reserve7, bitmap2)
|
||||
bitmap2_tree:add(_include_bitmap3, bitmap2)
|
||||
end
|
||||
|
||||
if include_ttl ~= 0 then
|
||||
nip_tree:add(_ttl, tvb(offset, 1))
|
||||
offset = offset + 1 --_ttl 占用1字节
|
||||
end
|
||||
|
||||
if include_total_len ~= 0 then
|
||||
nip_tree:add(_total_len, tvb(offset, 2))
|
||||
offset = offset + 2 --_total_len 占用2字节
|
||||
end
|
||||
|
||||
if include_nexthdr ~= 0 then
|
||||
nexthdr = tvb(offset, 1):uint()
|
||||
nip_tree:add(_nexthdr, tvb(offset, 1))
|
||||
offset = offset + 1 --_nexthdr 占用1字节
|
||||
end
|
||||
|
||||
if include_daddr ~= 0 then
|
||||
local first_addr = tvb(offset, 1):uint()
|
||||
local addr_len = get_nip_addr_len (first_addr)
|
||||
if addr_len == 0 then
|
||||
return false
|
||||
end
|
||||
nip_tree:add(_daddr, tvb(offset, addr_len))
|
||||
offset = offset + addr_len --_daddr 占用 addr_len 字节
|
||||
end
|
||||
|
||||
if include_saddr ~= 0 then
|
||||
local first_addr = tvb(offset, 1):uint()
|
||||
local addr_len = get_nip_addr_len (first_addr)
|
||||
if addr_len == 0 then
|
||||
return false
|
||||
end
|
||||
nip_tree:add(_saddr, tvb(offset, addr_len))
|
||||
offset = offset + addr_len --_daddr 占用 addr_len 字节
|
||||
end
|
||||
|
||||
if include_hdr_len ~= 0 then
|
||||
nip_tree:add(_hdr_len, tvb(offset, 1))
|
||||
offset = offset + 1 --_hdr_len 占用1字节
|
||||
end
|
||||
|
||||
--根据next header 确定上层协议
|
||||
local trans_data = tvb(offset, tvb_len - offset)
|
||||
if (nexthdr == 177) then
|
||||
local nd_icmp_tree = nip_tree:add(nd_icmp_obj, tvb:range(tvb_len))
|
||||
local type = tvb(offset, 1):uint()
|
||||
nd_icmp_tree:add(_type, tvb(offset, 1))
|
||||
offset = offset + 1
|
||||
nd_icmp_tree:add(_code, tvb(offset, 1))
|
||||
offset = offset + 1
|
||||
nd_icmp_tree:add(_checksum, tvb(offset, 1))
|
||||
offset = offset + 1
|
||||
if type == 1 then
|
||||
local first_addr = tvb(offset, 1):uint()
|
||||
local addr_len = get_nip_addr_len (first_addr)
|
||||
if addr_len == 0 then
|
||||
return false
|
||||
end
|
||||
nd_icmp_tree:add(_rs_daddr, tvb(offset, addr_len))
|
||||
offset = offset + addr_len --_rs_daddr 占用 addr_len 字节
|
||||
pinfo.cols.protocol = "ND request based NewIP"
|
||||
else
|
||||
nd_icmp_tree:add(_mac_len, tvb(offset, 1))
|
||||
offset = offset + 1
|
||||
nd_icmp_tree:add(_mac, tvb(offset, 6))
|
||||
offset = offset + 6
|
||||
pinfo.cols.protocol = "ND response based NewIP"
|
||||
end
|
||||
elseif (nexthdr == 6) then
|
||||
Dissector.get("tcp"):call(trans_data:tvb(), pinfo, treeitem)
|
||||
pinfo.cols.protocol = "TCP based NewIP"
|
||||
elseif (nexthdr == 17) then
|
||||
Dissector.get("udp"):call(trans_data:tvb(), pinfo, treeitem)
|
||||
pinfo.cols.protocol = "UDP based NewIP"
|
||||
else
|
||||
nip_tree:add(_trans_data, trans_data)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
下面定义 NewIP 解析器的主函数,这个函数由 wireshark调用
|
||||
第一个参数是 Tvb 类型,表示的是需要此解析器解析的数据
|
||||
第二个参数是 Pinfo 类型,是协议解析树上的信息,包括 UI 上的显示
|
||||
第三个参数是 TreeItem 类型,表示上一级解析树
|
||||
--]]
|
||||
function nip_proto_obj.dissector(tvb, pinfo, treeitem)
|
||||
if nip_dissector(tvb, pinfo, treeitem) then
|
||||
--valid NewIP diagram
|
||||
else
|
||||
--不是NewIP协议(其他未知协议)时,直接输出报文数据
|
||||
_unknown_data_dis:call(tvb, pinfo, treeitem)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--向 wireshark 注册协议插件被调用的条件
|
||||
local ipn_encap_table = DissectorTable.get("ethertype")
|
||||
ipn_encap_table:add(0xEADD, nip_proto_obj)
|
||||
|
||||
--NewIP地址长度计算
|
||||
function get_nip_addr_len (first_addr)
|
||||
if first_addr <= 0xDC then
|
||||
return 1
|
||||
elseif first_addr >= 0xDD and first_addr <= 0xF0 then
|
||||
return 2
|
||||
elseif first_addr == 0xF1 then
|
||||
return 3
|
||||
elseif first_addr == 0xF2 then
|
||||
return 5
|
||||
elseif first_addr == 0xF3 then
|
||||
return 7
|
||||
elseif first_addr == 0xFE then
|
||||
return 8
|
||||
elseif first_addr == 0xFF then
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
end -- lua end
|
||||
Reference in New Issue
Block a user