├── README.md ├── control ├── copying ├── dhcpd.conf.nat44 ├── dhcpd.conf.nonat ├── modules ├── Makefile ├── a.h ├── ivi_config.h ├── ivi_ioctl.c ├── ivi_ioctl.h ├── ivi_map.c ├── ivi_map.h ├── ivi_map_tcp.c ├── ivi_map_tcp.h ├── ivi_module.c ├── ivi_nf.c ├── ivi_nf.h ├── ivi_rule.c ├── ivi_rule.h ├── ivi_rule6.c ├── ivi_rule6.h ├── ivi_xmit.c └── ivi_xmit.h ├── radvd.conf ├── readme ├── stopall ├── utils ├── Makefile └── ivictl.c ├── zxhgw-addr ├── zyhgw-E ├── zyhgw-E44 ├── zyhgw-T └── zyhgw-T44 /README.md: -------------------------------------------------------------------------------- 1 | MAP 2 | ======= 3 | 4 | 5 | MAP is an open source CPE implementation of draft-ietf-softwire-map and 6 | draft-ietf-softwire-map-t. It runs on Linux and Openwrt. 7 | 8 | MAP is a mechanism for transporting IPv4 packets across an IPv6 network 9 | using IP translation (MAP-T) or encapsulation (MAP-E), and a generic 10 | mechanism for mapping between IPv6 addresses and IPv4 addresses and 11 | transport layer ports. It is defined in 12 | https://datatracker.ietf.org/doc/draft-ietf-softwire-map/ and 13 | https://datatracker.ietf.org/doc/draft-ietf-softwire-map-t/ 14 | 15 | 16 | A typical MAP use case is shown in the Figure below. 17 | 18 | User N 19 | Private IPv4 20 | | Network 21 | | 22 | o--+---------------O 23 | | | MAP CE | 24 | | +-----+--------+ | 25 | | NAPT44| MAP | | 26 | | +-----+ | | |\ ,--------, ,~-----------, 27 | | +--------+ | \ ,' '. ,' `, 28 | O------------------O / \ O---------O / \ 29 | | IPv6 only | | MAP | / Public \ 30 | | Network |--+ Border +- ( IPv4 ) 31 | | (MAP Domain) | | Relay | \ Network / 32 | O------------------O \ / O---------O \ / 33 | | MAP CE | /". ,' `. ,' 34 | | +-----+--------+ | / `----+--'` '-----------' 35 | | NAPT44| MAP | |/ 36 | | +-----+ | | 37 | | | +--------+ | 38 | O---.--------------O 39 | | 40 | User M 41 | Private IPv4 42 | Network 43 | 44 | ### Interoperation and Backwards Compatibility 45 | 46 | This implementation is used on MAP CE and can be configured with/without NAPT44 function. 47 | The interoperation between this implementation and Cisco ASR 1K/9K has been tested 48 | successfully with either encapsulation mode or translation mode. 49 | See http://blogs.cisco.com/sp/real-world-demonstration-of-map-for-ipv6/ for more details. 50 | 51 | Moreover, we have tested the CE implementation in CERNET/CERNET2 environment and the result 52 | shows that a unified MAP CE can be configured to support MAP-T, MAP-E, 53 | and backward compatible with stateless NAT64, stateful NAT64 and dual-stack lite. Please refer to 54 | http://datatracker.ietf.org/doc/draft-xli-softwire-map-testing for further reading. 55 | 56 | ### A Short Instruction on the Usage of MAP 57 | 58 | In the repository, the directory 'modules' contains the code for generating the MAP kernel module, 59 | while the directory 'utils' contains an utility to configure MAP parameters. 60 | You can read 'readme' for the detailed usage of the utility. 61 | 62 | As four examples, script files 'zyhgw-T44' and 'zyhgw-T' show how to configure the translation mode 63 | with/without NAT44; 64 | while 'zyhgw-E44' and 'zyhgw-E' show how to configure the encapsulation mode with/without NAT44. 65 | To stop the module, just execute the script file 'stopall'. 66 | 67 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | start() { 4 | if [ ! -f modules/ivi.ko ] ; then 5 | echo "Error: please make modules first." 6 | exit 1 7 | fi 8 | if ( lsmod | grep "ivi" ) ; then 9 | echo "Error: modules exist, run 'control restart' instead." 10 | exit 1 11 | fi 12 | echo "Starting IVI modules: " 13 | insmod modules/ivi.ko 14 | echo "insmod ivi.ko" 15 | if [ ! -e /dev/ivi ] ; then 16 | mknod /dev/ivi c 24 0 17 | echo "mknod /dev/ivi c 24 0" 18 | fi 19 | return 0 20 | } 21 | 22 | stop() { 23 | if ( lsmod | grep "ivi" ) ; then 24 | echo "Stopping IVI modules: " 25 | rmmod ivi 26 | echo "rmmod ivi" 27 | rm /dev/ivi 28 | echo "rm /dev/ivi" 29 | else 30 | echo "Error: modules do not exist." 31 | fi 32 | return 0 33 | } 34 | 35 | case "$1" in 36 | start) 37 | start 38 | ;; 39 | stop) 40 | stop 41 | ;; 42 | restart|reload) 43 | stop 44 | start 45 | ;; 46 | *) 47 | echo "Usage: control {start|stop|restart|reload}" 48 | exit 1 49 | esac 50 | 51 | exit 0 52 | -------------------------------------------------------------------------------- /copying: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /dhcpd.conf.nat44: -------------------------------------------------------------------------------- 1 | 2 | default-lease-time 600; 3 | max-lease-time 7200; 4 | 5 | option subnet-mask 255.255.255.0; 6 | option broadcast-address 192.168.1.255; 7 | option routers 192.168.1.1; 8 | option domain-name-servers 192.168.1.1; 9 | #option domain-name-servers 202.112.0.23; 10 | 11 | 12 | option domain-name "net.edu.cn"; 13 | 14 | subnet 192.168.1.0 netmask 255.255.255.0 { 15 | range 192.168.1.2 192.168.1.254; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /dhcpd.conf.nonat: -------------------------------------------------------------------------------- 1 | 2 | default-lease-time 600; 3 | max-lease-time 7200; 4 | 5 | option subnet-mask 255.255.255.240; 6 | option broadcast-address 202.38.102.143; 7 | option routers 202.38.102.129; 8 | option domain-name-servers 202.38.102.129; 9 | 10 | option domain-name "net.edu.cn"; 11 | 12 | subnet 202.38.102.128 netmask 255.255.255.240 { 13 | range 202.38.102.130 202.38.102.130; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /modules/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += ivi.o 2 | ivi-objs := ivi_rule.o ivi_rule6.o ivi_map.o ivi_map_tcp.o ivi_xmit.o ivi_nf.o ivi_ioctl.o ivi_module.o 3 | KERNELDIR := /lib/modules/$(shell uname -r)/build 4 | PWD := $(shell pwd) 5 | 6 | all: 7 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 8 | 9 | clean: 10 | rm -rf *.ko *.o *.mod.c core Module.symvers Module.markers modules.order .*.cmd .tmp_versions 11 | -------------------------------------------------------------------------------- /modules/a.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * a.h : 4 | * 5 | * Aligning Functions are Forked When Compiling Linksys Images. 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Yuncheng Zhu 14 | * Wentao Shang 15 | * Guoliang Han 16 | * 17 | * Contributions: 18 | * 19 | * This file is part of MAP-T/MAP-E Kernel Module. 20 | * 21 | * Permission to use, copy, modify, and distribute this software for any 22 | * purpose with or without fee is hereby granted, provided that the above 23 | * copyright notice and this permission notice appear in all copies. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with MAP-T/MAP-E Kernel Module. If not, see 27 | * . 28 | * 29 | * For more versions, please send an email to to 30 | * obtain an password to access the svn server. 31 | * 32 | * LIC: GPLv2 33 | * 34 | ************************************************************************/ 35 | 36 | #ifndef _LINUX_UNALIGNED_LE_STRUCT_H 37 | #define _LINUX_UNALIGNED_LE_STRUCT_H 38 | 39 | #include "packed_struct.h" 40 | #include 41 | 42 | static inline u16 get_unaligned_be16(const void *p) 43 | { 44 | return __get_unaligned_cpu16((const u8 *)p); 45 | } 46 | 47 | static inline u32 get_unaligned_be32(const void *p) 48 | { 49 | return __get_unaligned_cpu32((const u8 *)p); 50 | } 51 | 52 | static inline u64 get_unaligned_be64(const void *p) 53 | { 54 | return __get_unaligned_cpu64((const u8 *)p); 55 | } 56 | 57 | static inline void put_unaligned_be16(u16 val, void *p) 58 | { 59 | __put_unaligned_cpu16(val, p); 60 | } 61 | 62 | static inline void put_unaligned_be32(u32 val, void *p) 63 | { 64 | __put_unaligned_cpu32(val, p); 65 | } 66 | 67 | static inline void put_unaligned_be64(u64 val, void *p) 68 | { 69 | __put_unaligned_cpu64(val, p); 70 | } 71 | 72 | #endif /* _LINUX_UNALIGNED_LE_STRUCT_H */ 73 | 74 | -------------------------------------------------------------------------------- /modules/ivi_config.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_config.h : 4 | * 5 | * MAP-T/MAP-E Configuration Header File 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Yuncheng Zhu 14 | * Wentao Shang 15 | * Guoliang Han 16 | * 17 | * Contributions: 18 | * 19 | * This file is part of MAP-T/MAP-E Kernel Module. 20 | * 21 | * Permission to use, copy, modify, and distribute this software for any 22 | * purpose with or without fee is hereby granted, provided that the above 23 | * copyright notice and this permission notice appear in all copies. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with MAP-T/MAP-E Kernel Module. If not, see 27 | * . 28 | * 29 | * For more versions, please send an email to to 30 | * obtain an password to access the svn server. 31 | * 32 | * LIC: GPLv2 33 | * 34 | ************************************************************************/ 35 | 36 | #ifndef IVI_CONFIG_H 37 | #define IVI_CONFIG_H 38 | 39 | #include 40 | #ifdef __KERNEL__ 41 | #include 42 | #endif 43 | 44 | #define ADDR_FMT_NONE 0 // DMR format 45 | #define ADDR_FMT_MAPT 1 // BMR/FMR format 46 | #define ADDR_FMT_MAPX_CPE 2 // MAP CPE format with no eabits 47 | 48 | #define MAP_T 0 // Header translation 49 | #define MAP_E 1 // Header encapsulation mode 1: BR address is specified as a /128 50 | 51 | #define TCP_MAX_LOOP_NUM 20 52 | #define UDP_MAX_LOOP_NUM 6 53 | 54 | #ifndef IFNAMSIZ 55 | #define IFNAMSIZ 16 56 | #endif 57 | 58 | // comment this line out if you don't want to compile this code for the Linksys environment 59 | //#define LINKSYS_COMPILE 60 | //#define TP_LINK_COMPILE 61 | 62 | #ifdef LINKSYS_COMPILE 63 | static inline u32 get_unaligned_be32(const void *p) { 64 | u32 tmp; 65 | memcpy(&tmp, p, 4); 66 | return tmp; 67 | } 68 | #endif 69 | 70 | #ifndef NIP4 71 | 72 | #define NIP4_FMT "%u.%u.%u.%u" 73 | 74 | #ifdef TP_LINK_COMPILE 75 | #define NIP4(addr) \ 76 | ((unsigned char *)&addr)[0], \ 77 | ((unsigned char *)&addr)[1], \ 78 | ((unsigned char *)&addr)[2], \ 79 | ((unsigned char *)&addr)[3] 80 | #else 81 | #define NIP4(addr) \ 82 | ((unsigned char *)&addr)[3], \ 83 | ((unsigned char *)&addr)[2], \ 84 | ((unsigned char *)&addr)[1], \ 85 | ((unsigned char *)&addr)[0] 86 | #endif 87 | 88 | #endif 89 | 90 | #ifndef NIP6 91 | #define NIP6(addr) \ 92 | ntohs((addr).s6_addr16[0]), \ 93 | ntohs((addr).s6_addr16[1]), \ 94 | ntohs((addr).s6_addr16[2]), \ 95 | ntohs((addr).s6_addr16[3]), \ 96 | ntohs((addr).s6_addr16[4]), \ 97 | ntohs((addr).s6_addr16[5]), \ 98 | ntohs((addr).s6_addr16[6]), \ 99 | ntohs((addr).s6_addr16[7]) 100 | #define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" 101 | #endif 102 | 103 | struct rule_info { 104 | __u32 prefix4; 105 | int plen4; 106 | struct in6_addr prefix6; 107 | int plen6; 108 | __u16 ratio; 109 | __u16 adjacent; 110 | __u8 format; 111 | __u8 transport; 112 | }; 113 | 114 | #ifdef __KERNEL__ 115 | 116 | // comment this line out if you don't want to track any debug information 117 | //#define IVI_DEBUG 118 | 119 | // comment this line out if you don't want to track any debug information of tcp connection state 120 | //#define IVI_DEBUG_TCP 121 | 122 | // comment this line out if you don't want to track any debug information of rule mapping 123 | //#define IVI_DEBUG_RULE 124 | 125 | // comment this line out if you don't want to track any debug information of port mapping 126 | //#define IVI_DEBUG_MAP 127 | //#define IVI_DEBUG_MAP_TCP 128 | 129 | enum { 130 | IVI_MODE_HGW = 0, // Home gateway 131 | IVI_MODE_HGW_NAT44, // Home gateway with NAT44 132 | }; 133 | 134 | #define IVI_HTABLE_SIZE 32 135 | #define GOLDEN_RATIO_16 0x9e37 136 | #define GOLDEN_RATIO_32 0x9e370001 137 | 138 | // Generic hash function for a 16 bit value, see 'Introduction to Algorithms, 2nd Edition' Section 11.3.2 139 | static inline int port_hashfn(__be16 port) 140 | { 141 | unsigned int m = port * GOLDEN_RATIO_16; 142 | return ((m & 0xf800) >> 11); // extract highest 6 bits as hash result 143 | } 144 | 145 | // Generic hash function for a 32 bit value, see 'Introduction to Algorithms, 2nd Edition' Section 11.3.2 146 | static inline int v4addr_port_hashfn(__be32 addr, __be16 port) 147 | { 148 | __be32 m = addr + port; 149 | m *= GOLDEN_RATIO_32; 150 | return ((m & 0xf8000000) >> 27); 151 | } 152 | 153 | #endif /* __KERNEL__ */ 154 | 155 | #endif /* IVI_CONFIG_H */ 156 | -------------------------------------------------------------------------------- /modules/ivi_ioctl.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_ioctl.c : 4 | * 5 | * MAP-T/MAP-E Configuration Interface Kernel Module 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Guoliang Han 14 | * Yuncheng Zhu 15 | * Wentao Shang 16 | * 17 | * 18 | * Contributions: 19 | * 20 | * This file is part of MAP-T/MAP-E Kernel Module. 21 | * 22 | * Permission to use, copy, modify, and distribute this software for any 23 | * purpose with or without fee is hereby granted, provided that the above 24 | * copyright notice and this permission notice appear in all copies. 25 | * 26 | * You should have received a copy of the GNU General Public License 27 | * along with MAP-T/MAP-E Kernel Module. If not, see 28 | * . 29 | * 30 | * For more versions, please send an email to to 31 | * obtain an password to access the svn server. 32 | * 33 | * LIC: GPLv2 34 | * 35 | ************************************************************************/ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "ivi_nf.h" 44 | #include "ivi_xmit.h" 45 | #include "ivi_ioctl.h" 46 | #include "ivi_rule.h" 47 | #include "ivi_rule6.h" 48 | #include "ivi_config.h" 49 | 50 | static long ivi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { 51 | int retval = 0; 52 | struct net_device *dev; 53 | char temp[IVI_IOCTL_LEN]; 54 | struct rule_info rule; 55 | 56 | switch (cmd) { 57 | case IVI_IOC_V4DEV: 58 | if (copy_from_user(temp, (char *)arg, IVI_IOCTL_LEN) > 0) { 59 | return -EACCES; 60 | } 61 | temp[IVI_IOCTL_LEN - 1] = 0; 62 | dev = dev_get_by_name(&init_net, temp); 63 | if (dev == NULL) { 64 | return -ENODEV; 65 | } 66 | retval = nf_getv4dev(dev); 67 | printk(KERN_INFO "ivi_ioctl: v4 device set to %s.\n", temp); 68 | break; 69 | 70 | case IVI_IOC_V6DEV: 71 | if (copy_from_user(temp, (char *)arg, IVI_IOCTL_LEN) > 0) { 72 | return -EACCES; 73 | } 74 | temp[IVI_IOCTL_LEN - 1] = 0; 75 | dev = dev_get_by_name(&init_net, temp); 76 | if (dev == NULL) { 77 | return -ENODEV; 78 | } 79 | retval = nf_getv6dev(dev); 80 | printk(KERN_INFO "ivi_ioctl: v6 device set to %s.\n", temp); 81 | break; 82 | 83 | case IVI_IOC_START: 84 | retval = nf_running(1); 85 | break; 86 | 87 | case IVI_IOC_STOP: 88 | retval = nf_running(0); 89 | break; 90 | 91 | case IVI_IOC_V4NET: 92 | if (copy_from_user(&v4address, (__be32 *)arg, sizeof(__be32)) > 0) { 93 | return -EACCES; 94 | } 95 | printk(KERN_INFO "ivi_ioctl: v4 address set to %08x.\n", v4address); 96 | break; 97 | 98 | case IVI_IOC_V4MASK: 99 | if (copy_from_user(&v4mask, (__be32 *)arg, sizeof(__be32)) > 0) { 100 | return -EACCES; 101 | } 102 | printk(KERN_INFO "ivi_ioctl: v4 address mask set to %08x.\n", v4mask); 103 | break; 104 | 105 | case IVI_IOC_V6NET: 106 | if (copy_from_user(v6prefix, (__u8 *)arg, 16) > 0) { 107 | return -EACCES; 108 | } 109 | printk(KERN_INFO "ivi_ioctl: v6 prefix set to %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x.\n", 110 | ntohs(((__be16 *)v6prefix)[0]), ntohs(((__be16 *)v6prefix)[1]), ntohs(((__be16 *)v6prefix)[2]), ntohs(((__be16 *)v6prefix)[3]), 111 | ntohs(((__be16 *)v6prefix)[4]), ntohs(((__be16 *)v6prefix)[5]), ntohs(((__be16 *)v6prefix)[6]), ntohs(((__be16 *)v6prefix)[7])); 112 | break; 113 | 114 | case IVI_IOC_V6MASK: 115 | if (copy_from_user(&v6prefixlen, (__be32 *)arg, sizeof(__be32)) > 0) { 116 | return -EACCES; 117 | } 118 | printk(KERN_INFO "ivi_ioctl: v6 prefix length set to %d.\n", v6prefixlen); 119 | break; 120 | 121 | case IVI_IOC_V4PUB: 122 | if (copy_from_user(&v4publicaddr, (__be32 *)arg, sizeof(__be32)) > 0) { 123 | return -EACCES; 124 | } 125 | printk(KERN_INFO "ivi_ioctl: v4 public address set to %08x.\n", v4publicaddr); 126 | break; 127 | 128 | case IVI_IOC_V4PUBMASK: 129 | if (copy_from_user(&v4publicmask, (__be32 *)arg, sizeof(__be32)) > 0) { 130 | return -EACCES; 131 | } 132 | printk(KERN_INFO "ivi_ioctl: v4 public address mask set to %08x.\n", v4publicmask); 133 | break; 134 | 135 | case IVI_IOC_NAT: 136 | ivi_mode = IVI_MODE_HGW_NAT44; 137 | printk(KERN_INFO "ivi_ioctl: ivi_mode set to hgw with nat44 enabled.\n"); 138 | break; 139 | 140 | case IVI_IOC_NONAT: 141 | ivi_mode = IVI_MODE_HGW; 142 | printk(KERN_INFO "ivi_ioctl: ivi_mode set to hgw with nat44 disabled.\n"); 143 | break; 144 | 145 | case IVI_IOC_HGW_MAPX: 146 | hgw_fmt = ADDR_FMT_MAPX_CPE; 147 | printk(KERN_INFO "ivi_ioctl: addr_fmt set to %d.\n", hgw_fmt); 148 | break; 149 | 150 | case IVI_IOC_ADJACENT: 151 | if (copy_from_user(&hgw_adjacent, (u16 *)arg, sizeof(u16)) > 0) { 152 | return -EACCES; 153 | } 154 | printk(KERN_INFO "ivi_ioctl: adjacent set to %d.\n", hgw_adjacent); 155 | break; 156 | 157 | case IVI_IOC_MAPT: 158 | if (copy_from_user(&hgw_ratio, (u16 *)arg, sizeof(u16)) > 0) { 159 | return -EACCES; 160 | } 161 | printk(KERN_INFO "ivi_ioctl: ratio set to %d.\n", hgw_ratio); 162 | if (copy_from_user(&hgw_offset, ((u16 *)arg) + 1, sizeof(u16)) > 0) { 163 | return -EACCES; 164 | } 165 | printk(KERN_INFO "ivi_ioctl: offset set to %d.\n", hgw_offset); 166 | 167 | hgw_suffix = hgw_offset; 168 | printk(KERN_INFO "ivi_ioctl: suffix set to %04x.\n", hgw_suffix); 169 | hgw_fmt = ADDR_FMT_MAPT; 170 | printk(KERN_INFO "ivi_ioctl: addr_fmt set to %d.\n", hgw_fmt); 171 | break; 172 | 173 | case IVI_IOC_MSS_LIMIT: 174 | if (copy_from_user(&mss_limit, (u16 *)arg, sizeof(u16)) > 0) { 175 | return -EACCES; 176 | } 177 | printk(KERN_INFO "ivi_ioctl: mss limit set to %d.\n", mss_limit); 178 | break; 179 | 180 | case IVI_IOC_ADD_RULE: 181 | if (copy_from_user(&rule, (void *)arg, sizeof(struct rule_info)) > 0) { 182 | return -EACCES; 183 | } 184 | if (ivi_rule_insert(&rule) != 0) { 185 | printk(KERN_DEBUG "ivi_ioctl: fail to insert " NIP4_FMT "/%d -> " NIP6_FMT "/%d\n", 186 | NIP4(rule.prefix4), rule.plen4, NIP6(rule.prefix6), rule.plen6); 187 | return -EINVAL; 188 | } 189 | if (ivi_rule6_insert(&rule) != 0) { 190 | printk(KERN_DEBUG "ivi_ioctl: fail to insert " NIP6_FMT " -> %d, address format %d\n", 191 | NIP6(rule.prefix6), rule.plen6, rule.format); 192 | return -EINVAL; 193 | } 194 | break; 195 | 196 | case IVI_IOC_TRANSPT: 197 | if (copy_from_user(&hgw_transport, (u8 *)arg, sizeof(u8)) > 0) { 198 | return -EACCES; 199 | } 200 | printk(KERN_INFO "ivi_ioctl: transport set to %d.\n", hgw_transport); 201 | break; 202 | 203 | default: 204 | retval = -ENOTTY; 205 | } 206 | return retval; 207 | } 208 | 209 | static int ivi_open(struct inode *inode, struct file *file) { 210 | #ifdef IVI_DEBUG 211 | printk(KERN_DEBUG "IVI: virtual device is opened for ioctl.\n"); 212 | #endif 213 | return 0; 214 | } 215 | 216 | static int ivi_release(struct inode *inode, struct file *file) { 217 | #ifdef IVI_DEBUG 218 | printk(KERN_DEBUG "IVI: virtual device is closed.\n"); 219 | #endif 220 | return 0; 221 | } 222 | 223 | struct file_operations ivi_ops = { 224 | .owner = THIS_MODULE, 225 | .unlocked_ioctl = ivi_ioctl, 226 | .open = ivi_open, 227 | .release = ivi_release, 228 | }; 229 | 230 | int ivi_ioctl_init(void) { 231 | int retval; 232 | if ((retval = register_chrdev(IVI_IOCTL, IVI_DEVNAME, &ivi_ops)) < 0) { 233 | printk(KERN_ERR "IVI: failed to register ioctl as character device, code %d.\n", retval); 234 | } 235 | #ifdef IVI_DEBUG 236 | printk(KERN_DEBUG "IVI: ivi_ioctl loaded with return value %d.\n", retval); 237 | #endif 238 | return retval; 239 | } 240 | 241 | void ivi_ioctl_exit(void) { 242 | unregister_chrdev(IVI_IOCTL, IVI_DEVNAME); 243 | #ifdef IVI_DEBUG 244 | printk(KERN_DEBUG "IVI: ivi_ioctl unloaded.\n"); 245 | #endif 246 | } 247 | -------------------------------------------------------------------------------- /modules/ivi_ioctl.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_ioctl.h : 4 | * 5 | * This file is the header file for the 'ivi_ioctl.c' file, 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Guoliang Han 14 | * Yuncheng Zhu 15 | * Wentao Shang 16 | * 17 | * 18 | * Contributions: 19 | * 20 | * This file is part of MAP-T/MAP-E Kernel Module. 21 | * 22 | * Permission to use, copy, modify, and distribute this software for any 23 | * purpose with or without fee is hereby granted, provided that the above 24 | * copyright notice and this permission notice appear in all copies. 25 | * 26 | * You should have received a copy of the GNU General Public License 27 | * along with MAP-T/MAP-E Kernel Module. If not, see 28 | * . 29 | * 30 | * For more versions, please send an email to to 31 | * obtain an password to access the svn server. 32 | * 33 | * LIC: GPLv2 34 | * 35 | ************************************************************************/ 36 | 37 | 38 | #ifndef IVI_IOCTL_H 39 | #define IVI_IOCTL_H 40 | 41 | #include "ivi_config.h" 42 | 43 | #define IVI_DEVNAME "ivi" 44 | 45 | #define IVI_IOCTL 24 46 | 47 | #define IVI_IOC_V4DEV _IOW(IVI_IOCTL, 0x10, int) 48 | #define IVI_IOC_V6DEV _IOW(IVI_IOCTL, 0x11, int) 49 | #define IVI_IOC_START _IO(IVI_IOCTL, 0x12) 50 | #define IVI_IOC_STOP _IO(IVI_IOCTL, 0x13) 51 | 52 | #define IVI_IOC_V4NET _IOW(IVI_IOCTL, 0x14, int) 53 | #define IVI_IOC_V4MASK _IOW(IVI_IOCTL, 0x15, int) 54 | #define IVI_IOC_V6NET _IOW(IVI_IOCTL, 0x16, int) 55 | #define IVI_IOC_V6MASK _IOW(IVI_IOCTL, 0x17, int) 56 | #define IVI_IOC_V4PUB _IOW(IVI_IOCTL, 0x18, int) 57 | #define IVI_IOC_V4PUBMASK _IOW(IVI_IOCTL, 0x1f, int) 58 | 59 | #define IVI_IOC_NAT _IO(IVI_IOCTL, 0x19) 60 | #define IVI_IOC_NONAT _IO(IVI_IOCTL, 0x1a) 61 | #define IVI_IOC_HGW_MAPX _IOW(IVI_IOCTL, 0x29, int) 62 | 63 | #define IVI_IOC_MAPT _IOW(IVI_IOCTL, 0x1e, int) 64 | 65 | #define IVI_IOC_MSS_LIMIT _IOW(IVI_IOCTL, 0x1d, int) 66 | 67 | #define IVI_IOC_ADJACENT _IOW(IVI_IOCTL, 0x20, int) 68 | 69 | #define IVI_IOC_ADD_RULE _IOW(IVI_IOCTL, 0x21, int) 70 | 71 | #define IVI_IOC_TRANSPT _IOW(IVI_IOCTL, 0x23, int) 72 | 73 | #define IVI_IOCTL_LEN 32 74 | 75 | #ifdef __KERNEL__ 76 | 77 | extern int ivi_ioctl_init(void); 78 | extern void ivi_ioctl_exit(void); 79 | 80 | #endif 81 | 82 | #endif /* IVI_IOCTL_H */ 83 | 84 | -------------------------------------------------------------------------------- /modules/ivi_map.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_map.c : 4 | * 5 | * This file defines the generic mapping list data structure and basic 6 | * operations, which will be used in other modules. 'ivi_map' module 7 | * will be installed first when running './control start' command. 8 | * 9 | * Copyright (C) 2013 CERNET Network Center 10 | * All rights reserved. 11 | * 12 | * Design and coding: 13 | * Xing Li 14 | * Congxiao Bao 15 | * Guoliang Han 16 | * Yuncheng Zhu 17 | * Wentao Shang 18 | * 19 | * 20 | * Contributions: 21 | * 22 | * This file is part of MAP-T/MAP-E Kernel Module. 23 | * 24 | * Permission to use, copy, modify, and distribute this software for any 25 | * purpose with or without fee is hereby granted, provided that the above 26 | * copyright notice and this permission notice appear in all copies. 27 | * 28 | * You should have received a copy of the GNU General Public License 29 | * along with MAP-T/MAP-E Kernel Module. If not, see 30 | * . 31 | * 32 | * For more versions, please send an email to to 33 | * obtain an password to access the svn server. 34 | * 35 | * LIC: GPLv2 36 | * 37 | ************************************************************************/ 38 | 39 | #include "ivi_map.h" 40 | 41 | struct map_list udp_list; 42 | struct map_list icmp_list; 43 | 44 | 45 | /* ratio and offset together indicate the port pool range */ 46 | u16 hgw_ratio = 1; 47 | 48 | u16 hgw_offset = 0; 49 | 50 | u16 hgw_suffix = 0; 51 | 52 | u16 hgw_adjacent = 1024; // draft-ietf-softwire-map-05 specifies the default PSID offset is 6. 53 | 54 | /* list operations */ 55 | 56 | // Get current size of the list, must be protected by spin lock when calling this function 57 | static inline int get_list_port_num(struct map_list *list) 58 | { 59 | return list->port_num; 60 | } 61 | 62 | // Init list 63 | static void init_map_list(struct map_list *list, time_t timeout) 64 | { 65 | int i; 66 | spin_lock_init(&list->lock); 67 | for (i = 0; i < IVI_HTABLE_SIZE; i++) { 68 | INIT_HLIST_HEAD(&list->out_chain[i]); 69 | INIT_HLIST_HEAD(&list->in_chain[i]); 70 | INIT_HLIST_HEAD(&list->dest_chain[i]); 71 | } 72 | list->size = 0; 73 | list->port_num = 0; 74 | list->last_alloc_port = 0; 75 | list->timeout = timeout; 76 | } 77 | 78 | // Check whether a newport is in use now, must be protected by spin lock when calling this function 79 | static int port_in_use(__be16 port, struct map_list *list) 80 | { 81 | int ret = 0; 82 | int hash; 83 | struct map_tuple *iter; 84 | struct hlist_node *temp; 85 | 86 | hash = port_hashfn(port); 87 | if (!hlist_empty(&list->in_chain[hash])) { 88 | hlist_for_each_entry(iter, temp, &list->in_chain[hash], in_node) { 89 | if (iter->newport == port) { 90 | ret = 1; 91 | break; 92 | } 93 | } 94 | } 95 | 96 | return ret; 97 | } 98 | 99 | // Add a new map, the pointer to the new map_tuple is returned on success, must be protected by spin lock when calling this function 100 | static struct map_tuple* add_new_map(__be32 oldaddr, __be16 oldp, __be32 dstaddr, __be16 newp, struct map_list *list) 101 | { 102 | struct map_tuple *map; 103 | int hash; 104 | map = (struct map_tuple*)kmalloc(sizeof(struct map_tuple), GFP_ATOMIC); 105 | if (map == NULL) { 106 | printk(KERN_ERR "add_new_map: kmalloc failed for map_tuple.\n"); 107 | return NULL; 108 | } 109 | 110 | map->oldaddr = oldaddr; 111 | map->oldport = oldp; 112 | map->dstaddr = dstaddr; 113 | map->newport = newp; 114 | do_gettimeofday(&map->timer); 115 | 116 | hash = v4addr_port_hashfn(oldaddr, oldp); 117 | hlist_add_head(&map->out_node, &list->out_chain[hash]); 118 | hash = port_hashfn(newp); 119 | hlist_add_head(&map->in_node, &list->in_chain[hash]); 120 | hash = v4addr_port_hashfn(dstaddr, 0); 121 | hlist_add_head(&map->dest_node, &list->dest_chain[hash]); 122 | 123 | list->size++; 124 | 125 | return map; 126 | } 127 | 128 | // Refresh the timer for each map_tuple, must NOT acquire spin lock when calling this function 129 | void refresh_map_list(struct map_list *list) 130 | { 131 | struct map_tuple *iter, *i0; 132 | struct hlist_node *loop, *l0; 133 | struct hlist_node *temp, *t0; 134 | struct timeval now; 135 | time_t delta; 136 | int i, flag; 137 | do_gettimeofday(&now); 138 | 139 | spin_lock_bh(&list->lock); 140 | // Iterate all the map_tuple through out_chain only, in_chain contains the same info. 141 | for (i = 0; i < IVI_HTABLE_SIZE; i++) { 142 | hlist_for_each_entry_safe(iter, loop, temp, &list->out_chain[i], out_node) { 143 | delta = now.tv_sec - iter->timer.tv_sec; 144 | if (delta >= list->timeout) { 145 | #ifdef IVI_DEBUG_MAP 146 | printk(KERN_INFO "refresh_map_list: time out map " NIP4_FMT ":%d -> " NIP4_FMT " ------> %d on out_chain[%d]\n", NIP4(iter->oldaddr), iter->oldport, NIP4(iter->dstaddr), iter->newport, i); 147 | #endif 148 | 149 | hlist_del(&iter->out_node); 150 | hlist_del(&iter->in_node); 151 | hlist_del(&iter->dest_node); 152 | list->size--; 153 | 154 | flag = 0; // indicating whether list->port_num needs to be substracted by 1. 155 | hlist_for_each_entry_safe(i0, l0, t0, &list->in_chain[port_hashfn(iter->newport)], in_node) { 156 | if (i0->newport == iter->newport) { 157 | #ifdef IVI_DEBUG_MAP 158 | printk(KERN_INFO "refresh_map_list: newport %d is still used by someone(" NIP4_FMT ":%d -> " NIP4_FMT "). port_num is still %d\n", iter->newport, NIP4(i0->oldaddr), i0->oldport, NIP4(i0->dstaddr), list->port_num); 159 | #endif 160 | flag = 1; 161 | break; 162 | } 163 | } 164 | if (!flag) { 165 | list->port_num--; 166 | #ifdef IVI_DEBUG_MAP 167 | printk(KERN_INFO "refresh_map_list: port_num is decreased by 1 to %d(%d)\n", list->port_num, iter->newport); 168 | #endif 169 | } 170 | 171 | kfree(iter); 172 | } 173 | } 174 | } 175 | spin_unlock_bh(&list->lock); 176 | } 177 | 178 | // Clear the entire list, must NOT acquire spin lock when calling this function 179 | void free_map_list(struct map_list *list) 180 | { 181 | struct map_tuple *iter; 182 | struct hlist_node *loop; 183 | struct hlist_node *temp; 184 | int i; 185 | 186 | spin_lock_bh(&list->lock); 187 | // Iterate all the map_tuple through out_chain only, in_chain contains the same info. 188 | for (i = 0; i < IVI_HTABLE_SIZE; i++) { 189 | hlist_for_each_entry_safe(iter, loop, temp, &list->out_chain[i], out_node) { 190 | hlist_del(&iter->out_node); 191 | hlist_del(&iter->in_node); 192 | hlist_del(&iter->dest_node); 193 | list->size--; 194 | 195 | printk(KERN_INFO "free_map_list: delete map " NIP4_FMT ":%d -> " NIP4_FMT " ------> %d on out_chain[%d]\n", NIP4(iter->oldaddr), iter->oldport, NIP4(iter->dstaddr), iter->newport, i); 196 | 197 | kfree(iter); 198 | } 199 | } 200 | list->port_num = 0; 201 | spin_unlock_bh(&list->lock); 202 | } 203 | 204 | /* mapping operations */ 205 | 206 | // Get mapped port for outflow packet, input and output are in host byte order, return -1 if failed 207 | int get_outflow_map_port(struct map_list *list, __be32 oldaddr, __be16 oldp, __be32 dstaddr, u16 ratio, u16 adjacent, u16 offset, __be16 *newp) 208 | { 209 | int hash, reusing, status, start_port; 210 | __be16 retport; 211 | struct map_tuple *multiplex_state; 212 | struct map_tuple *iter; 213 | struct hlist_node *loop; 214 | struct hlist_node *temp; 215 | 216 | *newp = 0; 217 | reusing = 0; 218 | status = 0; 219 | retport = 0; 220 | ratio = fls(ratio) - 1; 221 | adjacent = fls(adjacent) - 1; 222 | start_port = ((1 << (ratio + adjacent)) > 1024) ? 1 << (ratio + adjacent) : 1024; // the ports below start_port are reserved for system ports. 223 | 224 | refresh_map_list(list); 225 | spin_lock_bh(&list->lock); 226 | 227 | hash = v4addr_port_hashfn(oldaddr, oldp); 228 | if (!hlist_empty(&list->out_chain[hash])) { 229 | hlist_for_each_entry(iter, temp, &list->out_chain[hash], out_node) { 230 | if (iter->oldport == oldp && iter->oldaddr == oldaddr) { 231 | if (iter->dstaddr == dstaddr) { 232 | retport = iter->newport; 233 | do_gettimeofday(&iter->timer); 234 | #ifdef IVI_DEBUG_MAP 235 | //printk(KERN_INFO "get_outflow_map_port: find map " NIP4_FMT ":%d -> " NIP4_FMT " ------> %d on out_chain[%d]\n", NIP4(iter->oldaddr), iter->oldport, NIP4(iter->dstaddr), iter->newport, hash); 236 | #endif 237 | goto out; 238 | } 239 | else if (reusing == 0) { // src addr & port same, while dest addr & port different: reuse the mapped port (Endpoint-independent) 240 | retport = iter->newport; 241 | reusing = 1; 242 | #ifdef IVI_DEBUG_MAP 243 | printk(KERN_INFO "get_outflow_map_port: port %d can be multiplexed with source address " NIP4_FMT ":%d\n", retport, NIP4(oldaddr), oldp); 244 | #endif 245 | } 246 | 247 | } 248 | } 249 | } 250 | 251 | if (retport == 0 && reusing == 0) { 252 | __be16 rover_j, rover_k; 253 | int dsthash, i, rand_j, chance; 254 | struct hlist_node *loop0, *temp0; 255 | 256 | status = 0; 257 | chance = UDP_MAX_LOOP_NUM; 258 | 259 | // Now we have to find a mapping whose src & dest are both different to multiplex: 260 | dsthash = v4addr_port_hashfn(dstaddr, 0); 261 | while (1) { // we want to generate an integer between [1, 31] 262 | get_random_bytes(&rand_j, sizeof(int)); 263 | rand_j = (rand_j >= 0) ? rand_j : -rand_j; 264 | rand_j -= (rand_j >> 5) << 5; 265 | if (rand_j) break; 266 | } 267 | 268 | /* hash is a random number between [0,31] except dsthash, so MAYBE its newport can be multiplexed because 269 | dest_chain[hash] is impossible to have the same destination with this packet.*/ 270 | hash = (dsthash + rand_j >= 32) ? (dsthash + rand_j - 32) : (dsthash + rand_j); 271 | 272 | for (i = 0; i < 31 && chance > 0; i++) { 273 | if (!hlist_empty(&list->dest_chain[hash])) { 274 | hlist_for_each_entry_safe(multiplex_state, loop0, temp0, &list->dest_chain[hash], dest_node) { 275 | retport = multiplex_state->newport; 276 | status = 1; 277 | 278 | /* don't worry:) we have to check whether this port has been multiplexed by another 279 | connection with the same destination */ 280 | if (!hlist_empty(&list->dest_chain[dsthash])) { 281 | hlist_for_each_entry_safe(iter, loop, temp, &list->dest_chain[dsthash], dest_node) { 282 | if (iter->dstaddr == dstaddr && iter->newport == retport) { 283 | status = 0; // this port cannot be multiplexed 284 | break; 285 | } 286 | } 287 | } 288 | if (status == 1) { // this port can be multiplexed 289 | #ifdef IVI_DEBUG_MAP 290 | printk(KERN_INFO "get_outflow_map_port: multiplex port %d on dest_chain[%d], round %d\n", retport, hash, i + 1); 291 | #endif 292 | i = 31; // go directly to create a new mapping 293 | break; 294 | } 295 | } 296 | if (status == 0) { 297 | //printk(KERN_DEBUG "ooops, you have only %d chance left now~\n", chance); 298 | chance--; 299 | } 300 | } 301 | else { 302 | if (++hash >= 32) 303 | hash = 0; 304 | if (hash == dsthash) { 305 | if (++hash >= 32) 306 | hash = 0; 307 | } 308 | } 309 | } 310 | 311 | if (status == 0) { 312 | // If it's so lucky to reach here, we have to generate a new port 313 | if (get_list_port_num(list) >= ((65536 - start_port)>>ratio)) { 314 | spin_unlock_bh(&list->lock); 315 | printk(KERN_INFO "get_outflow_map_port: map list full.\n"); 316 | return -1; 317 | } 318 | 319 | if (ratio == 0) 320 | retport = oldp; // In 1:1 mapping mode, use old port directly. 321 | 322 | else { 323 | int remaining; 324 | __be16 low, high; 325 | 326 | low = (__u16)((start_port - 1) >> (ratio + adjacent)) + 1; 327 | high = (__u16)(65536 >> (ratio + adjacent)) - 1; 328 | remaining = (high - low) + 1; 329 | 330 | if (list->last_alloc_port != 0) { 331 | rover_j = list->last_alloc_port >> (ratio + adjacent); 332 | rover_k = list->last_alloc_port - ((list->last_alloc_port >> adjacent) << adjacent) + 1; 333 | if (rover_k == (1 << adjacent)) { 334 | rover_j++; 335 | rover_k = 0; 336 | if (rover_j > high) 337 | rover_j = low; 338 | } 339 | } else { 340 | rover_j = low; 341 | rover_k = 0; 342 | } 343 | 344 | do { 345 | retport = (rover_j << (ratio + adjacent)) + (offset << adjacent) + rover_k; 346 | 347 | if (!port_in_use(retport, list)) 348 | break; 349 | 350 | rover_k++; 351 | if (rover_k == (1 << adjacent)) { 352 | rover_j++; 353 | remaining--; 354 | rover_k = 0; 355 | if (rover_j > high) 356 | rover_j = low; 357 | } 358 | } while (remaining > 0); 359 | 360 | if (remaining <= 0) { 361 | spin_unlock_bh(&list->lock); 362 | #ifdef IVI_DEBUG_MAP 363 | printk(KERN_INFO "get_outflow_map_port: failed to assign a new map port for " NIP4_FMT ":%d -> " NIP4_FMT "\n", NIP4(oldaddr), oldp, NIP4(dstaddr)); 364 | #endif 365 | return -1; 366 | } 367 | } 368 | } 369 | } 370 | 371 | if (add_new_map(oldaddr, oldp, dstaddr, retport, list) == NULL) { 372 | spin_unlock_bh(&list->lock); 373 | return -1; 374 | } 375 | 376 | if (status == 0 && reusing == 0) { // we generated a new mapping port 377 | list->last_alloc_port = retport; 378 | list->port_num++; 379 | } 380 | 381 | #ifdef IVI_DEBUG_MAP 382 | printk(KERN_INFO "add_new_map: add new map (" NIP4_FMT ":%d -> " NIP4_FMT " -------> %d), list_len = %d, port_num = %d\n", NIP4(oldaddr), oldp, NIP4(dstaddr), retport, list->size, list->port_num); 383 | #endif 384 | 385 | out: 386 | *newp = retport; 387 | spin_unlock_bh(&list->lock); 388 | return (retport == 0 ? -1 : 0); 389 | } 390 | 391 | // Get mapped port and address for inflow packet, input and output are in host bypt order, return -1 if failed 392 | int get_inflow_map_port(struct map_list *list, __be16 newp, __be32 dstaddr, __be32* oldaddr, __be16 *oldp) 393 | { 394 | struct map_tuple *iter; 395 | struct hlist_node *temp; 396 | int ret, hash; 397 | 398 | refresh_map_list(list); 399 | spin_lock_bh(&list->lock); 400 | 401 | ret = 1; 402 | *oldp = 0; 403 | *oldaddr = 0; 404 | 405 | hash = port_hashfn(newp); 406 | hlist_for_each_entry(iter, temp, &list->in_chain[hash], in_node) { 407 | if (iter->newport == newp && iter->dstaddr == dstaddr) { 408 | *oldaddr = iter->oldaddr; 409 | *oldp = iter->oldport; 410 | do_gettimeofday(&iter->timer); 411 | #ifdef IVI_DEBUG_MAP 412 | //printk(KERN_INFO "get_inflow_map_port: find map " NIP4_FMT ":%d -> " NIP4_FMT 413 | // " ------> %d on in_chain[%d]\n", NIP4(iter->oldaddr), 414 | // iter->oldport, NIP4(iter->dstaddr), iter->newport, hash); 415 | #endif 416 | ret = 0; 417 | break; 418 | } 419 | } 420 | 421 | if (ret == 1) { // fail to find a mapping either in list. 422 | #ifdef IVI_DEBUG_MAP_TCP 423 | printk(KERN_INFO "get_inflow_map_port: in_chain[%d] empty.\n", hash); 424 | #endif 425 | 426 | ret = -1; 427 | } 428 | 429 | spin_unlock_bh(&list->lock); 430 | return ret; 431 | } 432 | 433 | 434 | int ivi_map_init(void) { 435 | init_map_list(&udp_list, 15); 436 | init_map_list(&icmp_list, 15); 437 | #ifdef IVI_DEBUG 438 | printk(KERN_DEBUG "IVI: ivi_map loaded.\n"); 439 | #endif 440 | return 0; 441 | } 442 | 443 | void ivi_map_exit(void) { 444 | free_map_list(&udp_list); 445 | free_map_list(&icmp_list); 446 | #ifdef IVI_DEBUG 447 | printk(KERN_DEBUG "IVI: ivi_map unloaded.\n"); 448 | #endif 449 | } 450 | -------------------------------------------------------------------------------- /modules/ivi_map.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_map.h : 4 | * 5 | * This file is the header file for the 'ivi_map.c' file, 6 | * which contains all the system header files and definitions 7 | * used in the 'ivi_map.c' file. 8 | * 9 | * Copyright (C) 2013 CERNET Network Center 10 | * All rights reserved. 11 | * 12 | * Design and coding: 13 | * Xing Li 14 | * Congxiao Bao 15 | * Guoliang Han 16 | * Yuncheng Zhu 17 | * Wentao Shang 18 | * 19 | * Contributions: 20 | * 21 | * This file is part of MAP-T/MAP-E Kernel Module. 22 | * 23 | * Permission to use, copy, modify, and distribute this software for any 24 | * purpose with or without fee is hereby granted, provided that the above 25 | * copyright notice and this permission notice appear in all copies. 26 | * 27 | * You should have received a copy of the GNU General Public License 28 | * along with MAP-T/MAP-E Kernel Module. If not, see 29 | * . 30 | * 31 | * For more versions, please send an email to to 32 | * obtain an password to access the svn server. 33 | * 34 | * LIC: GPLv2 35 | * 36 | ************************************************************************/ 37 | 38 | #ifndef IVI_MAP_H 39 | #define IVI_MAP_H 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "ivi_config.h" 48 | #include "ivi_map_tcp.h" 49 | 50 | /* map entry structure */ 51 | struct map_tuple { 52 | struct hlist_node out_node; // Inserted to out_chain 53 | struct hlist_node in_node; // Inserted to in_chain 54 | struct hlist_node dest_node; // Inserted to dest_chain 55 | __be32 oldaddr; 56 | __be16 oldport; 57 | __be32 dstaddr; 58 | __be16 newport; 59 | struct timeval timer; 60 | }; 61 | 62 | /* map list structure */ 63 | struct map_list { 64 | spinlock_t lock; 65 | struct hlist_head out_chain[IVI_HTABLE_SIZE]; // Map table from oldport to newport 66 | struct hlist_head in_chain[IVI_HTABLE_SIZE]; // Map table from newport to oldport 67 | struct hlist_head dest_chain[IVI_HTABLE_SIZE]; // Map table with destination and newport 68 | int size; 69 | int port_num; // Number of MAP ports allocated in the map list 70 | __be16 last_alloc_port; // Save the last allocate port number 71 | time_t timeout; 72 | }; 73 | 74 | /* global map list variables */ 75 | extern u16 hgw_ratio; 76 | extern u16 hgw_offset; 77 | extern u16 hgw_suffix; 78 | extern u16 hgw_adjacent; 79 | 80 | extern struct map_list udp_list; 81 | extern struct map_list icmp_list; 82 | 83 | 84 | /* list operations */ 85 | extern void refresh_map_list(struct map_list *list); 86 | extern void free_map_list(struct map_list *list); 87 | 88 | /* mapping operations */ 89 | extern int get_outflow_map_port(struct map_list *list, __be32 oldaddr, __be16 oldp, __be32 dstaddr, u16 ratio, u16 adjacent, u16 offset, __be16 *newp); 90 | extern int get_inflow_map_port(struct map_list *list, __be16 newp, __be32 dstaddr, __be32* oldaddr, __be16 *oldp); 91 | 92 | extern int ivi_map_init(void); 93 | extern void ivi_map_exit(void); 94 | 95 | #endif /* IVI_MAP_H */ 96 | -------------------------------------------------------------------------------- /modules/ivi_map_tcp.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_map_tcp.c : 4 | * 5 | * This file is the header file for the 'ivi_map_tcp.c' file. 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Guoliang Han 14 | * Yuncheng Zhu 15 | * Wentao Shang 16 | * 17 | * 18 | * Contributions: 19 | * 20 | * This file is part of MAP-T/MAP-E Kernel Module. 21 | * 22 | * Permission to use, copy, modify, and distribute this software for any 23 | * purpose with or without fee is hereby granted, provided that the above 24 | * copyright notice and this permission notice appear in all copies. 25 | * 26 | * You should have received a copy of the GNU General Public License 27 | * along with MAP-T/MAP-E Kernel Module. If not, see 28 | * . 29 | * 30 | * For more versions, please send an email to to 31 | * obtain an password to access the svn server. 32 | * 33 | * LIC: GPLv2 34 | * 35 | ************************************************************************/ 36 | 37 | #ifndef IVI_MAP_TCP_H 38 | #define IVI_MAP_TCP_H 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | //#include "a.h" 50 | 51 | #include "ivi_config.h" 52 | #include "ivi_map.h" 53 | 54 | /* map list structure */ 55 | struct tcp_map_list { 56 | spinlock_t lock; 57 | struct hlist_head out_chain[IVI_HTABLE_SIZE]; // Map table from oldport to newport 58 | struct hlist_head in_chain[IVI_HTABLE_SIZE]; // Map table from newport to oldport 59 | struct hlist_head dest_chain[IVI_HTABLE_SIZE]; // Map table with destination and newport 60 | int size; // Number of mappings in the list 61 | int port_num; // Number of MAP ports allocated in the map list 62 | int state_seq; // Sequence number of the mapping(never decreased) 63 | __be16 last_alloc_port; // Save the last allocated port number 64 | }; 65 | 66 | // Packet flow direction 67 | typedef enum _PACKET_DIR { 68 | PACKET_DIR_LOCAL = 0, // Sent from local to remote 69 | PACKET_DIR_REMOTE, // Sent from remote to local 70 | PACKET_DIR_MAX 71 | } PACKET_DIR, *PPACKET_DIR; 72 | 73 | typedef enum _TCP_STATUS { 74 | TCP_STATUS_NONE = 0, // Initial state: 0 75 | TCP_STATUS_SYN_SENT, // SYN only packet sent: 1 76 | TCP_STATUS_SYN_RECV, // SYN-ACK packet sent: 2 77 | TCP_STATUS_ESTABLISHED, // ACK packet sent: 3 78 | TCP_STATUS_FIN_WAIT, // FIN packet sent: 4 79 | TCP_STATUS_CLOSE_WAIT, // ACK sent after FIN received: 5 80 | TCP_STATUS_LAST_ACK, // FIN sent after FIN received: 6 81 | TCP_STATUS_TIME_WAIT, // Last ACK sent: 7 82 | TCP_STATUS_CLOSE, // Connection closed: 8 83 | TCP_STATUS_SYN_SENT2, // SYN only packet received after SYN sent, simultaneous open: 9 84 | TCP_STATUS_MAX, 85 | TCP_STATUS_IGNORE 86 | } TCP_STATUS, *PTCP_STATUS; 87 | 88 | typedef struct _TCP_STATE_INFO { 89 | u_int32_t End; 90 | u_int32_t MaxEnd; 91 | u_int32_t MaxWindow; 92 | u_int32_t MaxAck; 93 | u_int8_t Scale; 94 | u_int8_t Options; 95 | } TCP_STATE_INFO, *PTCP_STATE_INFO; 96 | 97 | typedef struct _TCP_STATE_CONTEXT { 98 | struct hlist_node out_node; // Inserted to out_chain 99 | struct hlist_node in_node; // Inserted to in_chain 100 | struct hlist_node dest_node; // Inserted to dest_chain 101 | 102 | int state_seq; 103 | 104 | // Indexes pointing back to port hash table 105 | __be32 oldaddr; 106 | __be16 oldport; 107 | __be32 dstaddr; 108 | __be16 dstport; 109 | __be16 newport; 110 | 111 | // TCP state info 112 | TCP_STATE_INFO Seen[PACKET_DIR_MAX]; // Seen[0] for local state, Seen[1] for remote state 113 | struct timeval StateSetTime; // The time when the current state is set 114 | unsigned int StateTimeOut; // Timeout value for the current state 115 | TCP_STATUS Status; 116 | // For detecting retransmitted packets 117 | PACKET_DIR LastDir; 118 | u_int8_t RetransCount; 119 | u_int8_t LastControlBits; 120 | u_int32_t LastWindow; 121 | u_int32_t LastSeq; 122 | u_int32_t LastAck; 123 | u_int32_t LastEnd; 124 | } TCP_STATE_CONTEXT, *PTCP_STATE_CONTEXT; 125 | 126 | extern struct tcp_map_list tcp_list; 127 | extern struct hlist_node *pf_state; 128 | extern struct hlist_node *tcp_state; 129 | 130 | extern void init_tcp_map_list(void); 131 | 132 | extern void refresh_tcp_map_list(int); 133 | 134 | extern void free_tcp_map_list(void); 135 | 136 | extern int port_reserve(__be16); 137 | 138 | /* mapping operations */ 139 | extern int get_outflow_tcp_map_port(__be32 oldaddr, __be16 oldp, __be32 dstaddr, __be16 dstp, u16 ratio, u16 adjacent, u16 offset, struct tcphdr *th, __u32 len, __be16 *newp); 140 | extern int get_inflow_tcp_map_port(__be16 newp, __be32 dstaddr, __be16 dstp, struct tcphdr *th, __u32 len, __be32 *oldaddr, __be16 *oldp); 141 | 142 | extern int ivi_map_tcp_init(void); 143 | extern void ivi_map_tcp_exit(void); 144 | 145 | #endif /* IVI_MAP_TCP_H */ 146 | -------------------------------------------------------------------------------- /modules/ivi_module.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_module.c : 4 | * 5 | * MAP-T/MAP-E kernel module initiation and parameters set. 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Yuncheng Zhu 14 | * Wentao Shang 15 | * Guoliang Han 16 | * 17 | * Contributions: 18 | * 19 | * This file is part of MAP-T/MAP-E Kernel Module. 20 | * 21 | * Permission to use, copy, modify, and distribute this software for any 22 | * purpose with or without fee is hereby granted, provided that the above 23 | * copyright notice and this permission notice appear in all copies. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with MAP-T/MAP-E Kernel Module. If not, see 27 | * . 28 | * 29 | * For more versions, please send an email to to 30 | * obtain an password to access the svn server. 31 | * 32 | * LIC: GPLv2 33 | * 34 | ************************************************************************/ 35 | 36 | #include 37 | 38 | #include "ivi_rule.h" 39 | #include "ivi_rule6.h" 40 | #include "ivi_map.h" 41 | #include "ivi_map_tcp.h" 42 | #include "ivi_nf.h" 43 | #include "ivi_ioctl.h" 44 | 45 | static int __init ivi_module_init(void) { 46 | int retval = 0; 47 | if ((retval = ivi_rule_init()) < 0) { 48 | return retval; 49 | } 50 | if ((retval = ivi_rule6_init()) < 0) { 51 | return retval; 52 | } 53 | if ((retval = ivi_map_init()) < 0) { 54 | return retval; 55 | } 56 | if ((retval = ivi_map_tcp_init()) < 0) { 57 | return retval; 58 | } 59 | if ((retval = ivi_nf_init()) < 0) { 60 | return retval; 61 | } 62 | if ((retval = ivi_ioctl_init()) < 0) { 63 | return retval; 64 | } 65 | return 0; 66 | } 67 | module_init(ivi_module_init); 68 | 69 | static void __exit ivi_module_exit(void) { 70 | ivi_ioctl_exit(); 71 | ivi_nf_exit(); 72 | ivi_map_tcp_exit(); 73 | ivi_map_exit(); 74 | ivi_rule6_exit(); 75 | ivi_rule_exit(); 76 | } 77 | module_exit(ivi_module_exit); 78 | 79 | MODULE_LICENSE("GPL"); 80 | MODULE_AUTHOR("ZHU Yuncheng "); 81 | MODULE_AUTHOR("Wentao Shang "); 82 | MODULE_AUTHOR("Guoliang Han "); 83 | MODULE_DESCRIPTION("MAP-T/MAP-E Kernel Module"); 84 | -------------------------------------------------------------------------------- /modules/ivi_nf.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_nf.c : 4 | * 5 | * MAP-T/MAP-E Packet Processing based on Netfilter 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Yuncheng Zhu 14 | * Wentao Shang 15 | * Guoliang Han 16 | * 17 | * Contributions: 18 | * 19 | * This file is part of MAP-T/MAP-E Kernel Module. 20 | * 21 | * Permission to use, copy, modify, and distribute this software for any 22 | * purpose with or without fee is hereby granted, provided that the above 23 | * copyright notice and this permission notice appear in all copies. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with MAP-T/MAP-E Kernel Module. If not, see 27 | * . 28 | * 29 | * For more versions, please send an email to to 30 | * obtain an password to access the svn server. 31 | * 32 | * LIC: GPLv2 33 | * 34 | ************************************************************************/ 35 | 36 | #include "ivi_nf.h" 37 | 38 | struct net_device *v4_dev, *v6_dev; 39 | 40 | static int running; 41 | 42 | unsigned int nf_hook4(unsigned int hooknum, struct sk_buff *skb, 43 | const struct net_device *in, const struct net_device *out, 44 | int (*okfn)(struct sk_buff *)) { 45 | 46 | if ((!running) || (in != v4_dev)) { 47 | return NF_ACCEPT; 48 | } 49 | 50 | if (ivi_v4v6_xmit(skb) == 0) { 51 | return NF_DROP; 52 | } 53 | else { 54 | return NF_ACCEPT; 55 | } 56 | } 57 | 58 | unsigned int nf_hook6(unsigned int hooknum, struct sk_buff *skb, 59 | const struct net_device *in, const struct net_device *out, 60 | int (*okfn)(struct sk_buff *)) { 61 | 62 | if ((!running) || (in != v6_dev)) { 63 | return NF_ACCEPT; 64 | } 65 | 66 | if (ivi_v6v4_xmit(skb) == 0) { 67 | return NF_DROP; 68 | } 69 | else { 70 | return NF_ACCEPT; 71 | } 72 | } 73 | 74 | struct nf_hook_ops v4_ops = { 75 | list : { NULL, NULL }, 76 | hook : nf_hook4, 77 | owner : THIS_MODULE, 78 | pf : PF_INET, 79 | hooknum : NF_INET_PRE_ROUTING, 80 | priority: NF_IP_PRI_FIRST, 81 | }; 82 | 83 | struct nf_hook_ops v6_ops = { 84 | list : { NULL, NULL }, 85 | hook : nf_hook6, 86 | owner : THIS_MODULE, 87 | pf : PF_INET6, 88 | hooknum : NF_INET_PRE_ROUTING, 89 | priority: NF_IP6_PRI_FIRST, 90 | }; 91 | 92 | int nf_running(const int run) { 93 | running = run; 94 | #ifdef IVI_DEBUG 95 | printk(KERN_DEBUG "nf_running: set running state to %d.\n", running); 96 | #endif 97 | return running; 98 | } 99 | 100 | int nf_getv4dev(struct net_device *dev) { 101 | v4_dev = dev; 102 | return 0; 103 | } 104 | 105 | int nf_getv6dev(struct net_device *dev) { 106 | v6_dev = dev; 107 | return 0; 108 | } 109 | 110 | int ivi_nf_init(void) { 111 | running = 0; 112 | v4_dev = NULL; 113 | v6_dev = NULL; 114 | 115 | nf_register_hook(&v4_ops); 116 | nf_register_hook(&v6_ops); 117 | 118 | #ifdef IVI_DEBUG 119 | printk(KERN_DEBUG "IVI: ivi_nf loaded.\n"); 120 | #endif 121 | return 0; 122 | } 123 | 124 | void ivi_nf_exit(void) { 125 | running = 0; 126 | 127 | nf_unregister_hook(&v4_ops); 128 | nf_unregister_hook(&v6_ops); 129 | 130 | if (v4_dev) 131 | dev_put(v4_dev); 132 | 133 | if (v6_dev) 134 | dev_put(v6_dev); 135 | 136 | #ifdef IVI_DEBUG 137 | printk(KERN_DEBUG "IVI: ivi_nf unloaded.\n"); 138 | #endif 139 | } 140 | -------------------------------------------------------------------------------- /modules/ivi_nf.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_nf.h : 4 | * 5 | * This file is the header file for the 'ivi_nf.c' file. 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Yuncheng Zhu 14 | * Wentao Shang 15 | * Guoliang Han 16 | * 17 | * Contributions: 18 | * 19 | * This file is part of MAP-T/MAP-E Kernel Module. 20 | * 21 | * Permission to use, copy, modify, and distribute this software for any 22 | * purpose with or without fee is hereby granted, provided that the above 23 | * copyright notice and this permission notice appear in all copies. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with MAP-T/MAP-E Kernel Module. If not, see 27 | * . 28 | * 29 | * For more versions, please send an email to to 30 | * obtain an password to access the svn server. 31 | * 32 | * LIC: GPLv2 33 | * 34 | ************************************************************************/ 35 | 36 | 37 | #ifndef IVI_NF_H 38 | #define IVI_NF_H 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include "ivi_config.h" 50 | #include "ivi_map.h" 51 | #include "ivi_xmit.h" 52 | 53 | extern int nf_getv4dev(struct net_device *dev); 54 | extern int nf_getv6dev(struct net_device *dev); 55 | extern int nf_running(const int run); 56 | 57 | extern int ivi_nf_init(void); 58 | extern void ivi_nf_exit(void); 59 | 60 | extern struct net_device *v4_dev, *v6_dev; 61 | 62 | #endif /* IVI_NF_H */ 63 | -------------------------------------------------------------------------------- /modules/ivi_rule.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_rule.c : 4 | * 5 | * MAP-T/MAP-E 4to6 Prefix Mapping Kernel Module 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Wentao Shang 14 | * Yuncheng Zhu 15 | * Guoliang Han 16 | * 17 | * Contributions: 18 | * 19 | * This file is part of MAP-T/MAP-E Kernel Module. 20 | * 21 | * Permission to use, copy, modify, and distribute this software for any 22 | * purpose with or without fee is hereby granted, provided that the above 23 | * copyright notice and this permission notice appear in all copies. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with MAP-T/MAP-E Kernel Module. If not, see 27 | * . 28 | * 29 | * For more versions, please send an email to to 30 | * obtain an password to access the svn server. 31 | * 32 | * LIC: GPLv2 33 | * 34 | ************************************************************************/ 35 | 36 | #include "ivi_rule.h" 37 | 38 | #define KEYLENGTH 32 39 | 40 | typedef u32 t_key; 41 | 42 | #define T_TNODE 0 43 | #define T_LEAF 1 44 | #define NODE_TYPE_MASK 0x1UL 45 | #define NODE_TYPE(node) ((node)->parent & NODE_TYPE_MASK) 46 | 47 | #define IS_TNODE(n) (!(n->parent & T_LEAF)) 48 | #define IS_LEAF(n) (n->parent & T_LEAF) 49 | 50 | static const int halve_threshold = 25; 51 | static const int inflate_threshold = 50; 52 | static const int halve_threshold_root = 15; 53 | static const int inflate_threshold_root = 30; 54 | 55 | struct tentry { 56 | unsigned long parent; 57 | t_key key; 58 | }; 59 | 60 | struct tnode { 61 | unsigned long parent; 62 | t_key key; 63 | unsigned char pos; 64 | unsigned char bits; 65 | unsigned int full_children; 66 | unsigned int empty_children; 67 | struct tentry *child[0]; 68 | }; 69 | 70 | struct tleaf_info { 71 | struct hlist_node node; 72 | int plen; 73 | u32 mask_plen; 74 | struct in6_addr prefix6; 75 | int prefix6_len; 76 | u16 ratio; 77 | u16 adjacent; 78 | u8 format; 79 | u8 transport; 80 | }; 81 | 82 | struct tleaf { 83 | unsigned long parent; 84 | t_key key; 85 | struct hlist_head head; 86 | }; 87 | 88 | static struct tentry *trie = NULL; 89 | static spinlock_t trie_lock; 90 | 91 | #ifdef IVI_DEBUG 92 | /* Memory counter */ 93 | static int balance = 0; 94 | #endif 95 | 96 | static inline struct tnode* node_parent(const struct tentry *node) 97 | { 98 | return (struct tnode *)(node->parent & ~NODE_TYPE_MASK); 99 | } 100 | 101 | static inline void node_set_parent(struct tentry *node, const struct tnode *ptr) 102 | { 103 | node->parent = (unsigned long)ptr | NODE_TYPE(node); 104 | } 105 | 106 | static inline struct tentry* tnode_get_child(const struct tnode *tn, unsigned int i) 107 | { 108 | return (tn->child[i]); 109 | } 110 | 111 | static inline int tnode_child_length(const struct tnode *tn) 112 | { 113 | return 1 << tn->bits; 114 | } 115 | 116 | static inline t_key mask_pfx(t_key k, unsigned int l) 117 | { 118 | return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l); 119 | } 120 | 121 | static inline t_key tkey_extract_bits(t_key a, unsigned int offset, unsigned int bits) 122 | { 123 | if (offset < KEYLENGTH) 124 | return ((t_key)(a << offset)) >> (KEYLENGTH - bits); 125 | else 126 | return 0; 127 | } 128 | 129 | static inline int tkey_equals(t_key a, t_key b) 130 | { 131 | return a == b; 132 | } 133 | 134 | static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b) 135 | { 136 | if (bits == 0 || offset >= KEYLENGTH) 137 | return 1; 138 | bits = bits > KEYLENGTH ? KEYLENGTH : bits; 139 | return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0; 140 | } 141 | 142 | static inline int tkey_mismatch(t_key a, int offset, t_key b) 143 | { 144 | t_key diff = a ^ b; 145 | int i = offset; 146 | 147 | if (!diff) 148 | return 0; 149 | while ((diff << i) >> (KEYLENGTH-1) == 0) 150 | i++; 151 | return i; 152 | } 153 | 154 | /* Caller must free or store all the children of tnode 'n' 155 | * before calling this function to free it. 156 | */ 157 | static inline void tnode_free(struct tnode *n) 158 | { 159 | if (!n) 160 | return; 161 | 162 | kfree(n); 163 | #ifdef IVI_DEBUG 164 | balance--; 165 | #endif 166 | } 167 | 168 | static inline void tleaf_info_free(struct tleaf_info *li) 169 | { 170 | if (!li) 171 | return; 172 | 173 | kfree(li); 174 | #ifdef IVI_DEBUG 175 | balance--; 176 | #endif 177 | } 178 | 179 | static inline void tleaf_free(struct tleaf *l) 180 | { 181 | if (!l) 182 | return; 183 | 184 | kfree(l); 185 | #ifdef IVI_DEBUG 186 | balance--; 187 | #endif 188 | } 189 | 190 | static void tentry_free(struct tentry *node) 191 | { 192 | if (!node) 193 | return; 194 | 195 | if (IS_LEAF(node)) 196 | tleaf_free((struct tleaf *)node); 197 | else 198 | tnode_free((struct tnode *)node); 199 | } 200 | 201 | static void tnode_clean_free(struct tnode *tn) 202 | { 203 | int i; 204 | struct tentry *tofree; 205 | 206 | if (!tn) 207 | return; 208 | 209 | for (i = 0; i < tnode_child_length(tn); i++) { 210 | tofree = tn->child[i]; 211 | if (tofree) 212 | tentry_free(tofree); 213 | } 214 | tnode_free(tn); 215 | } 216 | 217 | static struct tleaf *tleaf_new(void) 218 | { 219 | struct tleaf *l = (struct tleaf *)kmalloc(sizeof(struct tleaf), GFP_ATOMIC); 220 | #ifdef IVI_DEBUG 221 | balance++; 222 | #endif 223 | if (l) { 224 | l->parent = T_LEAF; 225 | INIT_HLIST_HEAD(&l->head); 226 | } 227 | return l; 228 | } 229 | 230 | static struct tleaf_info *tleaf_info_new(int plen) 231 | { 232 | struct tleaf_info *li = (struct tleaf_info *)kzalloc(sizeof(struct tleaf_info), GFP_ATOMIC); 233 | #ifdef IVI_DEBUG 234 | balance++; 235 | #endif 236 | if (li) { 237 | li->plen = plen; 238 | li->mask_plen = ntohl(inet_make_mask(plen)); 239 | INIT_HLIST_NODE(&li->node); 240 | } 241 | return li; 242 | } 243 | 244 | 245 | static struct tnode *tnode_new(t_key key, int pos, int bits) 246 | { 247 | size_t size = sizeof(struct tnode) + (sizeof(struct tentry *) << bits); 248 | struct tnode *tn = (struct tnode *)kzalloc(size, GFP_ATOMIC); 249 | #ifdef IVI_DEBUG 250 | balance++; 251 | #endif 252 | 253 | if (tn) { 254 | tn->parent = T_TNODE; 255 | tn->pos = pos; 256 | tn->bits = bits; 257 | tn->key = key; 258 | tn->full_children = 0; 259 | tn->empty_children = 1 << bits; 260 | } 261 | 262 | return tn; 263 | } 264 | 265 | /* 266 | * Check whether a tnode 'chi' is "full", i.e. it is an internal node 267 | * and no bits are skipped. 268 | */ 269 | static inline int tnode_full(const struct tnode *tn, const struct tentry *chi) 270 | { 271 | struct tnode *n; 272 | 273 | if (chi == NULL || IS_LEAF(chi)) 274 | return 0; 275 | 276 | n = (struct tnode *)chi; 277 | 278 | return n->pos == tn->pos + tn->bits; 279 | } 280 | 281 | /* 282 | * Add a child at position i overwriting the old value. 283 | * Caller must store the old pointer value if it is not NULL, 284 | * otherwise the old memory will be lost. 285 | * Update the value of full_children and empty_children. 286 | */ 287 | static void tnode_put_child_reorg(struct tnode *tn, int i, struct tentry *n, int wasfull) 288 | { 289 | struct tentry *chi = tn->child[i]; 290 | int isfull; 291 | 292 | /* update emptyChildren */ 293 | if (n == NULL && chi != NULL) 294 | tn->empty_children++; 295 | else if (n != NULL && chi == NULL) 296 | tn->empty_children--; 297 | 298 | /* update fullChildren */ 299 | if (wasfull == -1) 300 | wasfull = tnode_full(tn, chi); 301 | 302 | isfull = tnode_full(tn, n); 303 | if (wasfull && !isfull) 304 | tn->full_children--; 305 | else if (!wasfull && isfull) 306 | tn->full_children++; 307 | 308 | if (n) 309 | node_set_parent(n, tn); 310 | 311 | tn->child[i] = n; 312 | } 313 | 314 | static inline void put_child(struct tnode *tn, int i, struct tentry *n) 315 | { 316 | tnode_put_child_reorg(tn, i, n, -1); 317 | } 318 | 319 | static struct tentry *resize(struct tnode *tn); 320 | static struct tnode *inflate(struct tnode *tn); 321 | static struct tnode *halve(struct tnode *tn); 322 | 323 | static struct tnode *inflate(struct tnode *tn) 324 | { 325 | struct tnode *oldtnode = tn; 326 | int olen = tnode_child_length(tn); 327 | int i; 328 | 329 | tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1); 330 | 331 | if (!tn) 332 | return NULL; 333 | 334 | /* Create new internal tnode if necessary, with its children left empty */ 335 | for (i = 0; i < olen; i++) { 336 | struct tnode *inode; 337 | inode = (struct tnode *)tnode_get_child(oldtnode, i); 338 | if (tnode_full(oldtnode, (struct tentry *)inode) && inode->bits > 1) { 339 | struct tnode *left, *right; 340 | t_key m; 341 | 342 | m = ~0U << (KEYLENGTH - 1) >> inode->pos; 343 | 344 | left = tnode_new(inode->key & (~m), inode->pos + 1, inode->bits - 1); 345 | if (!left) { 346 | tnode_free(tn); 347 | return NULL; 348 | } 349 | 350 | right = tnode_new(inode->key | m, inode->pos + 1, inode->bits - 1); 351 | if (!right) { 352 | tnode_free(left); 353 | tnode_free(tn); 354 | return NULL; 355 | } 356 | 357 | /* Insert the *doubled* internal tnodes */ 358 | put_child(tn, 2*i, (struct tentry *)left); 359 | put_child(tn, 2*i+1, (struct tentry *)right); 360 | } 361 | } 362 | 363 | /* Fill in the children of the *doubled* internal tnodes */ 364 | for (i = 0; i < olen; i++) { 365 | struct tnode *inode; 366 | struct tentry *node = tnode_get_child(oldtnode, i); 367 | struct tnode *left, *right; 368 | int size, j; 369 | 370 | /* An empty child */ 371 | if (node == NULL) 372 | continue; 373 | 374 | /* A leaf or an internal node with skipped bits */ 375 | if (IS_LEAF(node) || ((struct tnode *)node)->pos > tn->pos + tn->bits) { 376 | if (tkey_extract_bits(node->key, oldtnode->pos + oldtnode->bits, 1) == 0) 377 | put_child(tn, 2*i, node); 378 | else 379 | put_child(tn, 2*i+1, node); 380 | continue; 381 | } 382 | 383 | /* An internal (full) node with two children */ 384 | inode = (struct tnode *) node; 385 | 386 | if (inode->bits == 1) { 387 | put_child(tn, 2*i, inode->child[0]); 388 | put_child(tn, 2*i+1, inode->child[1]); 389 | tnode_free(inode); 390 | continue; 391 | } 392 | 393 | /* An internal (full) node with more than two children */ 394 | left = (struct tnode *)tnode_get_child(tn, 2*i); 395 | put_child(tn, 2*i, NULL); /* Temporarily remove */ 396 | 397 | right = (struct tnode *)tnode_get_child(tn, 2*i+1); 398 | put_child(tn, 2*i+1, NULL); /* Temporarily remove */ 399 | 400 | size = tnode_child_length(left); 401 | for (j = 0; j < size; j++) { 402 | put_child(left, j, inode->child[j]); 403 | put_child(right, j, inode->child[j + size]); 404 | } 405 | 406 | put_child(tn, 2*i, resize(left)); /* Restore */ 407 | put_child(tn, 2*i+1, resize(right)); /* Restore */ 408 | 409 | tnode_free(inode); 410 | } 411 | tnode_free(oldtnode); 412 | return tn; 413 | } 414 | 415 | static struct tnode *halve(struct tnode *tn) 416 | { 417 | struct tnode *oldtnode = tn; 418 | struct tentry *left, *right; 419 | int i; 420 | int olen = tnode_child_length(tn); 421 | 422 | tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1); 423 | 424 | if (!tn) 425 | return NULL; 426 | 427 | /* Create new internal tnode if necessary, with its children left empty */ 428 | for (i = 0; i < olen; i += 2) { 429 | left = tnode_get_child(oldtnode, i); 430 | right = tnode_get_child(oldtnode, i+1); 431 | 432 | /* Two nonempty children */ 433 | if (left && right) { 434 | struct tnode *newn; 435 | /* Create a *full* tnode */ 436 | newn = tnode_new(left->key, tn->pos + tn->bits, 1); 437 | if (!newn) { 438 | tnode_clean_free(tn); 439 | return NULL; 440 | } 441 | put_child(tn, i/2, (struct tentry *)newn); 442 | } 443 | } 444 | 445 | for (i = 0; i < olen; i += 2) { 446 | struct tnode *newBinNode; 447 | 448 | left = tnode_get_child(oldtnode, i); 449 | right = tnode_get_child(oldtnode, i+1); 450 | 451 | /* At least one of the children is empty */ 452 | if (left == NULL) { 453 | if (right == NULL) /* Both are empty */ 454 | continue; 455 | put_child(tn, i/2, right); 456 | continue; 457 | } 458 | 459 | if (right == NULL) { 460 | put_child(tn, i/2, left); 461 | continue; 462 | } 463 | 464 | /* Two nonempty children */ 465 | newBinNode = (struct tnode *)tnode_get_child(tn, i/2); 466 | put_child(tn, i/2, NULL); /* Temporarily remove */ 467 | put_child(newBinNode, 0, left); 468 | put_child(newBinNode, 1, right); 469 | put_child(tn, i/2, resize(newBinNode)); /* Restore */ 470 | } 471 | tnode_free(oldtnode); 472 | return tn; 473 | } 474 | 475 | #define MAX_WORK 10 476 | static struct tentry *resize(struct tnode *tn) 477 | { 478 | int i; 479 | struct tnode *old_tn; 480 | int inflate_threshold_use; 481 | int halve_threshold_use; 482 | int max_work; 483 | 484 | if (!tn) 485 | return NULL; 486 | 487 | /* No children */ 488 | if (tn->empty_children == tnode_child_length(tn)) { 489 | tnode_free(tn); 490 | return NULL; 491 | } 492 | /* One child */ 493 | if (tn->empty_children == tnode_child_length(tn) - 1) 494 | goto one_child; 495 | 496 | /* 497 | * Double as long as the resulting node has a number of 498 | * nonempty nodes that are above the threshold. 499 | */ 500 | 501 | /* Keep root node larger */ 502 | if (!node_parent((struct tentry *)tn)) { 503 | inflate_threshold_use = inflate_threshold_root; 504 | halve_threshold_use = halve_threshold_root; 505 | } else { 506 | inflate_threshold_use = inflate_threshold; 507 | halve_threshold_use = halve_threshold; 508 | } 509 | 510 | max_work = MAX_WORK; 511 | while ((tn->full_children > 0 && max_work-- && 512 | 50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) 513 | >= inflate_threshold_use * tnode_child_length(tn))) { 514 | 515 | old_tn = tn; 516 | tn = inflate(tn); 517 | 518 | if (!tn) { 519 | tn = old_tn; 520 | break; 521 | } 522 | } 523 | 524 | /* Return if at least one inflate is run */ 525 | if (max_work != MAX_WORK) 526 | return (struct tentry *)tn; 527 | 528 | /* 529 | * Halve as long as the number of empty children in this 530 | * node is above threshold. 531 | */ 532 | 533 | max_work = MAX_WORK; 534 | while (tn->bits > 1 && max_work-- && 535 | 100 * (tnode_child_length(tn) - tn->empty_children) < 536 | halve_threshold_use * tnode_child_length(tn)) { 537 | 538 | old_tn = tn; 539 | tn = halve(tn); 540 | 541 | if (!tn) { 542 | tn = old_tn; 543 | break; 544 | } 545 | } 546 | 547 | /* Only one child remains */ 548 | if (tn->empty_children == tnode_child_length(tn) - 1) { 549 | one_child: 550 | for (i = 0; i < tnode_child_length(tn); i++) { 551 | struct tentry *n; 552 | n = tn->child[i]; 553 | if (!n) 554 | continue; 555 | 556 | /* compress one level */ 557 | node_set_parent(n, NULL); 558 | tnode_free(tn); 559 | return n; 560 | } 561 | } 562 | return (struct tentry *)tn; 563 | } 564 | 565 | static void trie_rebalance(struct tnode *tn) 566 | { 567 | int wasfull; 568 | t_key cindex, key; 569 | struct tnode *tp; 570 | 571 | key = tn->key; 572 | 573 | while (tn != NULL && (tp = node_parent((struct tentry *)tn)) != NULL) { 574 | cindex = tkey_extract_bits(key, tp->pos, tp->bits); 575 | wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); 576 | 577 | tn = (struct tnode *)resize((struct tnode *)tn); 578 | 579 | tnode_put_child_reorg((struct tnode *)tp, cindex, (struct tentry *)tn, wasfull); 580 | 581 | tp = node_parent((struct tentry *) tn); 582 | if (!tp) 583 | trie = (struct tentry *)tn; 584 | 585 | if (!tp) 586 | break; 587 | tn = tp; 588 | } 589 | 590 | /* Handle last (top) tnode */ 591 | if (IS_TNODE(tn)) 592 | tn = (struct tnode *)resize((struct tnode *)tn); 593 | 594 | trie = (struct tentry *)tn; 595 | } 596 | 597 | static struct tleaf_info *find_leaf_info(struct tleaf *l, int plen) 598 | { 599 | struct tleaf_info *p; 600 | struct hlist_node *temp; 601 | 602 | if (!l) 603 | return NULL; 604 | 605 | hlist_for_each_entry(p, temp, &l->head, node) { 606 | if (p->plen == plen) 607 | return p; 608 | } 609 | return NULL; 610 | } 611 | 612 | static void insert_leaf_info(struct tleaf *l, struct tleaf_info *li) 613 | { 614 | struct tleaf_info *p = NULL; 615 | struct tleaf_info *last = NULL; 616 | struct hlist_head *head = &l->head; 617 | struct hlist_node *temp; 618 | 619 | if (hlist_empty(head)) { 620 | hlist_add_head(&li->node, head); 621 | } else { 622 | hlist_for_each_entry(p, temp, head, node) { 623 | if (li->plen > p->plen) 624 | break; 625 | 626 | last = p; 627 | } 628 | if (last) 629 | hlist_add_after(&last->node, &li->node); 630 | else 631 | hlist_add_before(&li->node, &p->node); 632 | } 633 | } 634 | 635 | static struct tleaf *fib_find_node(unsigned int key) 636 | { 637 | int pos; 638 | struct tnode *tn; 639 | struct tentry *n; 640 | 641 | pos = 0; 642 | n = trie; 643 | 644 | while (n != NULL && NODE_TYPE(n) == T_TNODE) { 645 | tn = (struct tnode *) n; 646 | if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { 647 | pos = tn->pos + tn->bits; 648 | n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits)); 649 | } else 650 | break; 651 | } 652 | 653 | /* Case we have found a leaf. Compare prefixes */ 654 | if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) 655 | return (struct tleaf *)n; 656 | 657 | return NULL; 658 | } 659 | 660 | static int check_leaf(struct tleaf *l, t_key key, struct in6_addr *prefix6, int *plen4, int *plen6, u16 *ratio, u16 *adjacent, u8 *fmt, u8 *transpt) 661 | { 662 | struct tleaf_info *li; 663 | struct hlist_head *head = &l->head; 664 | struct hlist_node *temp; 665 | hlist_for_each_entry(li, temp, head, node) { 666 | if (l->key == (key & li->mask_plen)) { 667 | *prefix6 = li->prefix6; 668 | if (plen4) 669 | *plen4 = li->plen; 670 | if (plen6) 671 | *plen6 = li->prefix6_len; 672 | if (ratio) 673 | *ratio = li->ratio; 674 | if (adjacent) 675 | *adjacent = li->adjacent; 676 | if (fmt) 677 | *fmt = li->format; 678 | if (transpt) 679 | *transpt = li->transport; 680 | #ifdef IVI_DEBUG_RULE 681 | printk(KERN_DEBUG "ivi_rule_lookup: " NIP4_FMT "/%d -> " NIP6_FMT "/%d, ratio = %d, adjacent = %d, addr-format %d, transport %d\n", 682 | NIP4(key), li->plen, NIP6(li->prefix6), li->prefix6_len, li->ratio, li->adjacent, li->format, li->transport); 683 | #endif 684 | return 0; 685 | } 686 | } 687 | return 1; 688 | } 689 | 690 | int ivi_rule_lookup(u32 key, struct in6_addr *prefix6, int *plen4, int *plen6, u16 *ratio, u16 *adjacent, u8 *fmt, u8 *transpt) 691 | { 692 | int ret; 693 | struct tentry *n; 694 | struct tnode *pn; 695 | unsigned int pos, bits; 696 | unsigned int chopped_off; 697 | t_key cindex = 0; 698 | unsigned int current_prefix_length = KEYLENGTH; 699 | struct tnode *cn; 700 | t_key pref_mismatch; 701 | 702 | spin_lock_bh(&trie_lock); 703 | 704 | n = trie; 705 | if (!n) 706 | goto failed; 707 | 708 | /* Just a leaf? */ 709 | if (IS_LEAF(n)) { 710 | ret = check_leaf((struct tleaf *)n, key, prefix6, plen4, plen6, ratio, adjacent, fmt, transpt); 711 | goto found; 712 | } 713 | 714 | pn = (struct tnode *)n; 715 | chopped_off = 0; 716 | 717 | while (pn) { 718 | pos = pn->pos; 719 | bits = pn->bits; 720 | 721 | if (!chopped_off) 722 | cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length), pos, bits); 723 | 724 | n = tnode_get_child(pn, cindex); 725 | 726 | if (n == NULL) { 727 | goto backtrace; 728 | } 729 | 730 | if (IS_LEAF(n)) { 731 | ret = check_leaf((struct tleaf *)n, key, prefix6, plen4, plen6, ratio, adjacent, fmt, transpt); 732 | if (ret > 0) 733 | goto backtrace; 734 | goto found; 735 | } 736 | 737 | cn = (struct tnode *)n; 738 | 739 | if (current_prefix_length < pos + bits) { 740 | if (tkey_extract_bits(cn->key, current_prefix_length, 741 | cn->pos - current_prefix_length) 742 | || !(cn->child[0])) 743 | goto backtrace; 744 | } 745 | 746 | pref_mismatch = mask_pfx(cn->key ^ key, cn->pos); 747 | 748 | if (pref_mismatch) { 749 | int mp = KEYLENGTH - fls(pref_mismatch); 750 | 751 | if (tkey_extract_bits(cn->key, mp, cn->pos - mp) != 0) 752 | goto backtrace; 753 | 754 | if (current_prefix_length >= cn->pos) 755 | current_prefix_length = mp; 756 | } 757 | 758 | pn = (struct tnode *)n; /* Descend */ 759 | chopped_off = 0; 760 | continue; 761 | 762 | backtrace: 763 | chopped_off++; 764 | 765 | /* As zero don't change the child key (cindex) */ 766 | while ((chopped_off <= pn->bits) 767 | && !(cindex & (1<<(chopped_off-1)))) 768 | chopped_off++; 769 | 770 | /* Decrease current_... with bits chopped off */ 771 | if (current_prefix_length > pn->pos + pn->bits - chopped_off) 772 | current_prefix_length = pn->pos + pn->bits - chopped_off; 773 | 774 | /* 775 | * Either we do the actual chop off according or if we have 776 | * chopped off all bits in this tnode walk up to our parent. 777 | */ 778 | if (chopped_off <= pn->bits) { 779 | cindex &= ~(1 << (chopped_off-1)); 780 | } else { 781 | struct tnode *parent = node_parent((struct tentry *) pn); 782 | if (!parent) 783 | goto failed; 784 | 785 | /* Get Child's index */ 786 | cindex = tkey_extract_bits(pn->key, parent->pos, parent->bits); 787 | pn = parent; 788 | chopped_off = 0; 789 | goto backtrace; 790 | } 791 | } 792 | failed: 793 | ret = 1; 794 | found: 795 | spin_unlock_bh(&trie_lock); 796 | return ret; 797 | } 798 | 799 | static struct tleaf_info* trie_insert_node(u32 key, u32 plen) 800 | { 801 | int pos, newpos; 802 | int missbit; 803 | struct tleaf *l; 804 | struct tleaf_info *li = NULL; 805 | struct tentry *n; 806 | struct tnode *tp = NULL, *tn = NULL; 807 | t_key cindex; 808 | 809 | pos = 0; 810 | n = (struct tentry *)trie; 811 | 812 | while (n != NULL && NODE_TYPE(n) == T_TNODE) { 813 | tn = (struct tnode *)n; 814 | if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) { 815 | tp = tn; 816 | pos = tn->pos + tn->bits; 817 | n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits)); 818 | } else 819 | break; 820 | } 821 | 822 | /* 823 | * n ----> NULL, LEAF or TNODE 824 | * 825 | * tp is n's (parent) ----> NULL or TNODE 826 | */ 827 | 828 | /* Case 1: n is a leaf. Compare prefixes */ 829 | if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) { 830 | l = (struct tleaf *)n; 831 | li = tleaf_info_new(plen); 832 | if (!li) 833 | return NULL; 834 | 835 | insert_leaf_info(l, li); 836 | return li; 837 | } 838 | l = tleaf_new(); 839 | 840 | if (!l) 841 | return NULL; 842 | 843 | l->key = key; 844 | li = tleaf_info_new(plen); 845 | 846 | if (!li) { 847 | tleaf_free(l); 848 | return NULL; 849 | } 850 | 851 | insert_leaf_info(l, li); 852 | 853 | if (trie != NULL && n == NULL) { 854 | /* Case 2: n is NULL while we have root, just insert a new leaf */ 855 | node_set_parent((struct tentry *)l, tp); 856 | cindex = tkey_extract_bits(key, tp->pos, tp->bits); 857 | put_child((struct tnode *)tp, cindex, (struct tentry *)l); 858 | } else { 859 | /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */ 860 | /* 861 | * Add a new tnode here 862 | * If root is NULL, first tnode need some special handling 863 | */ 864 | if (tp) 865 | pos = tp->pos + tp->bits; 866 | else 867 | pos = 0; 868 | 869 | if (n) { 870 | newpos = tkey_mismatch(key, pos, n->key); 871 | tn = tnode_new(n->key, newpos, 1); 872 | } else { 873 | newpos = 0; 874 | tn = tnode_new(key, newpos, 1); /* First tnode (root) */ 875 | } 876 | 877 | if (tn == NULL) 878 | return NULL; 879 | 880 | node_set_parent((struct tentry *)tn, tp); 881 | 882 | missbit = tkey_extract_bits(key, newpos, 1); 883 | put_child(tn, missbit, (struct tentry *)l); 884 | put_child(tn, 1 - missbit, n); 885 | 886 | if (tp) { 887 | cindex = tkey_extract_bits(key, tp->pos, tp->bits); 888 | put_child((struct tnode *)tp, cindex, (struct tentry *)tn); 889 | } else { 890 | trie = (struct tentry *)tn; 891 | tp = tn; 892 | } 893 | } 894 | /* Re-balance the trie */ 895 | trie_rebalance(tp); 896 | return li; 897 | } 898 | 899 | int ivi_rule_insert(struct rule_info *rule) 900 | { 901 | u32 key, mask; 902 | int plen; 903 | struct tleaf *l; 904 | struct tleaf_info *li; 905 | 906 | if ((rule->plen4 > 32) || (rule->plen6 > 128)) 907 | return -1; 908 | 909 | plen = rule->plen4; 910 | mask = ntohl(inet_make_mask(plen)); 911 | key = rule->prefix4 & mask; 912 | 913 | spin_lock_bh(&trie_lock); 914 | l = fib_find_node(key); 915 | li = find_leaf_info(l, plen); 916 | if (li) { 917 | // Update satellite data. 918 | li->prefix6 = rule->prefix6; 919 | li->prefix6_len = rule->plen6; 920 | li->ratio = rule->ratio; 921 | li->adjacent = rule->adjacent; 922 | li->format = rule->format; 923 | li->transport = rule->transport; 924 | } else { 925 | li = trie_insert_node(key, plen); 926 | // Insert satellite data. 927 | li->prefix6 = rule->prefix6; 928 | li->prefix6_len = rule->plen6; 929 | li->ratio = rule->ratio; 930 | li->adjacent = rule->adjacent; 931 | li->format = rule->format; 932 | li->transport = rule->transport; 933 | } 934 | spin_unlock_bh(&trie_lock); 935 | #ifdef IVI_DEBUG_RULE 936 | printk(KERN_DEBUG "ivi_rule_insert: " NIP4_FMT "/%d -> " NIP6_FMT "/%d, ratio %d, adjacent %d, addr-format %d, transport %d\n", 937 | NIP4(rule->prefix4), rule->plen4, NIP6(rule->prefix6), rule->plen6, rule->ratio, rule->adjacent, rule->format, rule->transport); 938 | #endif 939 | return 0; 940 | } 941 | 942 | static void trie_leaf_remove(struct tleaf *l) 943 | { 944 | struct tnode *tp = node_parent((struct tentry *)l); 945 | 946 | if (tp) { 947 | t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits); 948 | put_child((struct tnode *)tp, cindex, NULL); 949 | trie_rebalance(tp); 950 | } else 951 | trie = NULL; 952 | 953 | tleaf_free(l); 954 | } 955 | 956 | int ivi_rule_delete(struct rule_info *rule) 957 | { 958 | u32 key, mask; 959 | int plen, ret; 960 | struct tleaf *l; 961 | struct tleaf_info *li; 962 | 963 | ret = -1; 964 | 965 | key = rule->prefix4; 966 | plen = rule->plen4; 967 | 968 | if (plen > 32) 969 | goto out; 970 | 971 | mask = ntohl(inet_make_mask(plen)); 972 | key = key & mask; 973 | 974 | spin_lock_bh(&trie_lock); 975 | l = fib_find_node(key); 976 | if (!l) { 977 | goto out_from_lock; 978 | } 979 | li = find_leaf_info(l, plen); 980 | if (!li) 981 | goto out_from_lock; 982 | 983 | /* Here we need to check whether 'li' matches the provided 'rule' 984 | * since no check against *prefix6* is performed before. 985 | */ 986 | if (ipv6_addr_cmp(&li->prefix6, &rule->prefix6) || li->prefix6_len != rule->plen6 987 | || li->format != rule->format || li->ratio != rule->ratio || li->adjacent != rule->adjacent || li->transport != rule->transport) 988 | goto out_from_lock; 989 | 990 | hlist_del(&li->node); 991 | tleaf_info_free(li); 992 | #ifdef IVI_DEBUG_RULE 993 | printk(KERN_DEBUG "ivi_rule_delete: " NIP4_FMT "/%d -> " NIP6_FMT "/%d, ratio = %d, adjacent = %d, addr-format %d, transport %d\n", 994 | NIP4(rule->prefix4), rule->plen4, NIP6(rule->prefix6), rule->plen6, rule->ratio, rule->adjacent, rule->format, rule->transport); 995 | #endif 996 | 997 | if (hlist_empty(&l->head)) 998 | trie_leaf_remove(l); 999 | 1000 | ret = 0; 1001 | out_from_lock: 1002 | spin_unlock_bh(&trie_lock); 1003 | out: 1004 | return ret; 1005 | } 1006 | 1007 | /* 1008 | * Scan for the next right_leaf starting at node c 1009 | */ 1010 | static struct tleaf *leaf_walk(struct tnode *p, struct tentry *c) 1011 | { 1012 | do { 1013 | t_key idx; 1014 | 1015 | if (c) 1016 | idx = tkey_extract_bits(c->key, p->pos, p->bits) + 1; 1017 | else 1018 | idx = 0; 1019 | 1020 | while (idx < 1u << p->bits) { 1021 | c = tnode_get_child(p, idx++); 1022 | if (!c) 1023 | continue; 1024 | 1025 | if (IS_LEAF(c)) { 1026 | return (struct tleaf *)c; 1027 | } 1028 | 1029 | /* Descend and start scanning in new node */ 1030 | p = (struct tnode *)c; 1031 | idx = 0; 1032 | } 1033 | 1034 | /* Node empty, walk back up to parent */ 1035 | c = (struct tentry *)p; 1036 | } while ((p = node_parent(c)) != NULL); 1037 | 1038 | return NULL; /* Root of trie */ 1039 | } 1040 | 1041 | static struct tleaf *trie_first_leaf(struct tentry *t) 1042 | { 1043 | 1044 | struct tnode *n = (struct tnode *)t; 1045 | 1046 | if (!n) 1047 | return NULL; 1048 | 1049 | if (IS_LEAF(n)) /* trie is just a leaf */ 1050 | return (struct tleaf *)n; 1051 | 1052 | return leaf_walk(n, NULL); 1053 | } 1054 | 1055 | static struct tleaf *trie_next_leaf(struct tleaf *l) 1056 | { 1057 | struct tentry *c = (struct tentry *)l; 1058 | struct tnode *p = node_parent(c); 1059 | 1060 | if (!p) 1061 | return NULL; /* trie with just one leaf as its root */ 1062 | 1063 | return leaf_walk(p, c); 1064 | } 1065 | 1066 | static void trie_flush_leaf(struct tleaf *l) 1067 | { 1068 | struct tleaf_info *li = NULL; 1069 | struct hlist_node *loop, *temp; 1070 | 1071 | if (!l) 1072 | return; 1073 | 1074 | hlist_for_each_entry_safe(li, loop, temp, &l->head, node) { 1075 | hlist_del(&li->node); 1076 | tleaf_info_free(li); 1077 | } 1078 | } 1079 | 1080 | void ivi_rule_flush(void) 1081 | { 1082 | struct tleaf *l, *ll = NULL; 1083 | 1084 | spin_lock_bh(&trie_lock); 1085 | 1086 | for (l = trie_first_leaf(trie); l; l = trie_next_leaf(l)) { 1087 | trie_flush_leaf(l); 1088 | 1089 | if (ll && hlist_empty(&ll->head)) 1090 | trie_leaf_remove(ll); 1091 | ll = l; 1092 | } 1093 | 1094 | if (ll && hlist_empty(&ll->head)) 1095 | trie_leaf_remove(ll); 1096 | 1097 | spin_unlock_bh(&trie_lock); 1098 | } 1099 | 1100 | int ivi_rule_init(void) { 1101 | trie = NULL; 1102 | spin_lock_init(&trie_lock); 1103 | #ifdef IVI_DEBUG 1104 | balance = 0; 1105 | printk(KERN_DEBUG "IVI: ivi_rule loaded.\n"); 1106 | #endif 1107 | return 0; 1108 | } 1109 | 1110 | void ivi_rule_exit(void) { 1111 | ivi_rule_flush(); 1112 | #ifdef IVI_DEBUG 1113 | printk(KERN_DEBUG "IVI: ivi_rule unloaded.\n"); 1114 | printk(KERN_DEBUG "IVI: ivi_rule memory balance = %d\n", balance); 1115 | #endif 1116 | } 1117 | -------------------------------------------------------------------------------- /modules/ivi_rule.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_rule.h : 4 | * 5 | * This file is the header file for the 'ivi_rule.c' file. 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Wentao Shang 14 | * Yuncheng Zhu 15 | * Guoliang Han 16 | * 17 | * Contributions: 18 | * 19 | * This file is part of MAP-T/MAP-E Kernel Module. 20 | * 21 | * Permission to use, copy, modify, and distribute this software for any 22 | * purpose with or without fee is hereby granted, provided that the above 23 | * copyright notice and this permission notice appear in all copies. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with MAP-T/MAP-E Kernel Module. If not, see 27 | * . 28 | * 29 | * For more versions, please send an email to to 30 | * obtain an password to access the svn server. 31 | * 32 | * LIC: GPLv2 33 | * 34 | ************************************************************************/ 35 | 36 | 37 | #ifndef IVI_RULE_H 38 | #define IVI_RULE_H 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "ivi_config.h" 49 | 50 | extern int ivi_rule_lookup(u32 key, struct in6_addr *prefix6, int *plen4, int *plen6, u16 *ratio, u16 *adjacent, u8 *fmt, u8 *transpt); 51 | extern int ivi_rule_insert(struct rule_info *rule); 52 | extern int ivi_rule_delete(struct rule_info *rule); 53 | extern void ivi_rule_flush(void); 54 | 55 | extern int ivi_rule_init(void); 56 | extern void ivi_rule_exit(void); 57 | 58 | #endif /* IVI_RULE_H */ 59 | -------------------------------------------------------------------------------- /modules/ivi_rule6.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_rule_v6.c : 4 | * 5 | * MAP-T/MAP-E 6to4 Prefix Mapping Kernel Module 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Wentao Shang 14 | * Yuncheng Zhu 15 | * Guoliang Han 16 | * 17 | * Contributions: 18 | * 19 | * This file is part of MAP-T/MAP-E Kernel Module. 20 | * 21 | * Permission to use, copy, modify, and distribute this software for any 22 | * purpose with or without fee is hereby granted, provided that the above 23 | * copyright notice and this permission notice appear in all copies. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with MAP-T/MAP-E Kernel Module. If not, see 27 | * . 28 | * 29 | * For more versions, please send an email to to 30 | * obtain an password to access the svn server. 31 | * 32 | * LIC: GPLv2 33 | * 34 | ************************************************************************/ 35 | 36 | #include "ivi_rule6.h" 37 | 38 | u8 u_byte = 1; // 0: no u-byte; 1: set u-byte in v6 addr 39 | 40 | struct rule6_node { 41 | struct rule6_node *parent; 42 | struct rule6_node *left; 43 | struct rule6_node *right; 44 | struct in6_addr key; 45 | u32 prefix4; 46 | int bit_pos; // plen6 + plen4 47 | int plen6; // actuall ipv6 prefix length 48 | int plen4; // actuall ipv4 prefix length 49 | u16 ratio; 50 | u16 adjacent; 51 | u8 format; 52 | u8 flag; 53 | }; 54 | 55 | #define RN_RINFO 0x0001 56 | 57 | static struct rule6_node *radix = NULL; 58 | static spinlock_t radix_lock; 59 | 60 | #ifdef IVI_DEBUG 61 | /* Memory counter */ 62 | static int balance = 0; 63 | #endif 64 | 65 | 66 | /* 67 | * test bit 68 | */ 69 | #if defined(__LITTLE_ENDIAN) 70 | # define BITOP_BE32_SWIZZLE (0x1F & ~7) 71 | #else 72 | # define BITOP_BE32_SWIZZLE 0 73 | #endif 74 | 75 | static __inline__ __be32 addr_bit_set(const void *token, int pos) 76 | { 77 | const __be32 *addr = token; 78 | /* 79 | * Here, 80 | * 1 << ((~pos ^ BITOP_BE32_SWIZZLE) & 0x1f) 81 | * is optimized version of 82 | * htonl(1 << ((~pos)&0x1F)) 83 | * See include/asm-generic/bitops/le.h. 84 | */ 85 | return (__force __be32)(1 << ((~pos ^ BITOP_BE32_SWIZZLE) & 0x1f)) & addr[pos >> 5]; 86 | } 87 | 88 | static __inline__ struct rule6_node * node_alloc(void) 89 | { 90 | struct rule6_node *n; 91 | n = kzalloc(sizeof(struct rule6_node), GFP_ATOMIC); 92 | #ifdef IVI_DEBUG 93 | balance++; 94 | #endif 95 | return n; 96 | } 97 | 98 | static __inline__ void node_free(struct rule6_node *n) 99 | { 100 | kfree(n); 101 | #ifdef IVI_DEBUG 102 | balance--; 103 | #endif 104 | } 105 | 106 | /* 107 | * Rule insertion 108 | */ 109 | 110 | static struct rule6_node* radix_insert_node(const struct in6_addr *addr, struct rule_info *rule) 111 | { 112 | struct rule6_node *fn, *in, *ln, *pn; 113 | int plen, bit; 114 | u32 dir; 115 | 116 | pn = NULL; 117 | dir = 0; 118 | if (rule->format == ADDR_FMT_MAPT) 119 | plen = ubyte_adjust_bit(rule->plen6); 120 | else 121 | plen = rule->plen6 + rule->plen4; 122 | 123 | if (!radix) 124 | goto root_empty; 125 | 126 | fn = radix; 127 | 128 | do { 129 | /* Prefix match */ 130 | if (plen < fn->bit_pos || !ipv6_prefix_equal(&fn->key, addr, fn->bit_pos)) 131 | goto insert_above; 132 | 133 | /* Exact match ? */ 134 | if (plen == fn->bit_pos) { 135 | fn->flag |= RN_RINFO; /* fn contains rule info now */ 136 | return fn; 137 | } 138 | 139 | /* 140 | * We have more bits to go 141 | */ 142 | 143 | /* Try to walk down on tree. */ 144 | dir = addr_bit_set(addr, fn->bit_pos); 145 | pn = fn; 146 | fn = dir ? fn->right: fn->left; 147 | } while (fn); 148 | 149 | root_empty: 150 | /* 151 | * We have walked to the bottom of tree. 152 | * Create new leaf node without children. 153 | */ 154 | ln = node_alloc(); 155 | if (ln == NULL) 156 | return NULL; 157 | 158 | /* set new leaf's key */ 159 | ln->key = *addr; 160 | ln->prefix4 = rule->prefix4; 161 | ln->bit_pos = plen; 162 | ln->plen6 = rule->plen6; 163 | ln->plen4 = rule->plen4; 164 | ln->ratio = rule->ratio; 165 | ln->adjacent = rule->adjacent; 166 | ln->format = rule->format; 167 | ln->parent = pn; 168 | ln->flag |= RN_RINFO; 169 | 170 | if (!pn) { 171 | /* we have empty root */ 172 | radix = ln; 173 | } else { 174 | if (dir) 175 | pn->right = ln; 176 | else 177 | pn->left = ln; 178 | } 179 | 180 | return ln; 181 | 182 | 183 | insert_above: 184 | /* 185 | * split since we don't have a common prefix anymore or 186 | * we have a less significant route. 187 | * we've to insert an intermediate node on the list 188 | * this new node will point to the one we need to create 189 | * and the current 190 | */ 191 | 192 | pn = fn->parent; 193 | 194 | /* find 1st bit in difference between the 2 addrs. 195 | 196 | See comment in __ipv6_addr_diff: bit may be an invalid value, 197 | but if it is >= plen, the value is ignored in any case. 198 | */ 199 | bit = ipv6_addr_diff(addr, &fn->key); 200 | 201 | /* 202 | * (intermediate)[in] 203 | * / \ 204 | * (new leaf node)[ln] (old node)[fn] 205 | */ 206 | if (plen > bit) { 207 | in = node_alloc(); 208 | ln = node_alloc(); 209 | 210 | if (in == NULL || ln == NULL) { 211 | if (in) 212 | node_free(in); 213 | if (ln) 214 | node_free(ln); 215 | return NULL; 216 | } 217 | 218 | /* use fn's key as in's key */ 219 | in->key = fn->key; 220 | in->bit_pos = bit; 221 | in->parent = pn; 222 | in->flag = 0; /* in's flag is cleared */ 223 | 224 | if (!pn) { 225 | /* in is root now */ 226 | radix = in; 227 | } else { 228 | /* update parent pointer */ 229 | if (dir) 230 | pn->right = in; 231 | else 232 | pn->left = in; 233 | } 234 | 235 | /* set new leaf's key */ 236 | ln->key = *addr; 237 | ln->prefix4 = rule->prefix4; 238 | ln->bit_pos = plen; 239 | ln->plen6 = rule->plen6; 240 | ln->plen4 = rule->plen4; 241 | ln->ratio = rule->ratio; 242 | ln->adjacent = rule->adjacent; 243 | ln->format = rule->format; 244 | ln->parent = in; 245 | ln->flag |= RN_RINFO; 246 | 247 | fn->parent = in; 248 | 249 | if (addr_bit_set(addr, bit)) { 250 | in->right = ln; 251 | in->left = fn; 252 | } else { 253 | in->left = ln; 254 | in->right = fn; 255 | } 256 | } else { /* plen <= bit */ 257 | 258 | /* 259 | * (new leaf node)[ln] 260 | * / \ 261 | * (old node)[fn] NULL 262 | */ 263 | ln = node_alloc(); 264 | 265 | if (ln == NULL) 266 | return NULL; 267 | 268 | /* set new leaf's key */ 269 | ln->key = *addr; 270 | ln->prefix4 = rule->prefix4; 271 | ln->bit_pos = plen; 272 | ln->plen6 = rule->plen6; 273 | ln->plen4 = rule->plen4; 274 | ln->ratio = rule->ratio; 275 | ln->adjacent = rule->adjacent; 276 | ln->format = rule->format; 277 | ln->parent = pn; 278 | ln->flag |= RN_RINFO; 279 | 280 | if (!pn) { 281 | /* ln is root now */ 282 | radix = ln; 283 | } else { 284 | if (dir) 285 | pn->right = ln; 286 | else 287 | pn->left = ln; 288 | } 289 | 290 | if (addr_bit_set(&fn->key, plen)) 291 | ln->right = fn; 292 | else 293 | ln->left = fn; 294 | 295 | fn->parent = ln; 296 | } 297 | return ln; 298 | } 299 | 300 | int ivi_rule6_insert(struct rule_info *rule) 301 | { 302 | int ret, plen6; 303 | 304 | if (rule->plen4 > 0) { 305 | /* concatenate ipv6 prefix and ipv4 prefix */ 306 | /* overwrite on 'rule' memory */ 307 | plen6 = rule->plen6 >> 3; 308 | if (rule->format == ADDR_FMT_MAPT) { 309 | // Special care for MAP-T format 310 | // Currently no IPv4 bits is copied, LPM is totally done on Rule IPv6 Prefix 311 | } else { 312 | rule->prefix6.s6_addr[plen6] = (unsigned char)(rule->prefix4 >> 24); 313 | rule->prefix6.s6_addr[plen6 + 1] = (unsigned char)((rule->prefix4 >> 16) & 0xff); 314 | rule->prefix6.s6_addr[plen6 + 2] = (unsigned char)((rule->prefix4 >> 8) & 0xff); 315 | rule->prefix6.s6_addr[plen6 + 3] = (unsigned char)(rule->prefix4 & 0xff); 316 | } 317 | } 318 | 319 | spin_lock_bh(&radix_lock); 320 | if (radix_insert_node(&rule->prefix6, rule) == NULL) { 321 | ret = -1; 322 | #ifdef IVI_DEBUG_RULE 323 | printk(KERN_DEBUG "ivi_rule6_insert: failed to insert entry " NIP6_FMT " plen6 = %d, plen4 = %d, ratio = %d, adjacent = %d, addr-format %d\n", 324 | NIP6(rule->prefix6), rule->plen6, rule->plen4, rule->ratio, rule->adjacent, rule->format); 325 | #endif 326 | } else { 327 | ret = 0; 328 | #ifdef IVI_DEBUG_RULE 329 | printk(KERN_DEBUG "ivi_rule6_insert: " NIP6_FMT " plen6 = %d, prefix4 = " NIP4_FMT ", plen4 = %d, ratio = %d, adjacent = %d, addr-format %d\n", 330 | NIP6(rule->prefix6), rule->plen6, NIP4(rule->prefix4), rule->plen4, rule->ratio, rule->adjacent, rule->format); 331 | #endif 332 | } 333 | spin_unlock_bh(&radix_lock); 334 | return ret; 335 | } 336 | 337 | 338 | /* 339 | * Rule lookup 340 | */ 341 | 342 | static struct rule6_node* radix_lookup(const struct in6_addr *addr) 343 | { 344 | struct rule6_node *fn, *next; 345 | u32 dir; 346 | 347 | if (unlikely(!radix)) /* empty radix tree */ 348 | return NULL; 349 | 350 | /* 351 | * Descend on a tree 352 | */ 353 | fn = radix; 354 | 355 | for (;;) { 356 | dir = addr_bit_set(addr, fn->bit_pos); 357 | 358 | next = dir ? fn->right : fn->left; 359 | 360 | if (!next) 361 | break; 362 | 363 | fn = next; 364 | } 365 | 366 | while (fn) { 367 | if ((fn->flag & RN_RINFO) && 368 | ipv6_prefix_equal(&fn->key, addr, fn->bit_pos)) { 369 | return fn; 370 | } 371 | 372 | /* backtrace */ 373 | fn = fn->parent; 374 | } 375 | 376 | return NULL; 377 | } 378 | 379 | int ivi_rule6_lookup(struct in6_addr *addr, int *plen, u32 *prefix4, int *plen4, u16 *ratio, u16 *adjacent, u8 *fmt) 380 | { 381 | struct rule6_node* n; 382 | int ret; 383 | 384 | if (!plen) 385 | return -1; 386 | 387 | ret = -1; 388 | *plen = 0; 389 | 390 | spin_lock_bh(&radix_lock); 391 | 392 | n = radix_lookup(addr); 393 | 394 | if (n) { 395 | #ifdef IVI_DEBUG_RULE 396 | printk(KERN_DEBUG "ivi_rule6_lookup: " NIP6_FMT " -> %d\n", NIP6(n->key), n->bit_pos); 397 | #endif 398 | if (plen) 399 | *plen = n->plen6; 400 | if (prefix4) 401 | *prefix4 = n->prefix4; 402 | if (plen4) 403 | *plen4 = n->plen4; 404 | if (ratio) 405 | *ratio = n->ratio; 406 | if (adjacent) 407 | *adjacent = n->adjacent; 408 | if (fmt) 409 | *fmt = n->format; 410 | ret = 0; 411 | } 412 | 413 | spin_unlock_bh(&radix_lock); 414 | 415 | return ret; 416 | 417 | } 418 | 419 | 420 | /* 421 | * Rule deletion 422 | */ 423 | 424 | static struct rule6_node* radix_delete_trim(struct rule6_node* fn) 425 | { 426 | u32 children; 427 | struct rule6_node *pn, *child; 428 | 429 | if (unlikely(!fn)) /* nothing to be done */ 430 | return NULL; 431 | 432 | /* 433 | * Delete 434 | */ 435 | 436 | pn = fn->parent; 437 | 438 | children = 0; 439 | child = NULL; 440 | if (fn->left) { 441 | child = fn->left; 442 | children++; 443 | } 444 | 445 | if (fn->right) { 446 | child = fn->right; 447 | children++; 448 | } 449 | 450 | if (children == 2) { 451 | /* clear flag and set 'fn' to be an intermediate node without rule info */ 452 | fn->flag &= ~RN_RINFO; 453 | fn = pn; /* backtrace */ 454 | } else if (children == 1) { 455 | /* move the single child up */ 456 | child->parent = pn; 457 | 458 | if (!pn) { 459 | /* child is root now */ 460 | radix = child; 461 | } else { 462 | /* update parent pointers */ 463 | if (pn->left == fn) 464 | pn->left = child; 465 | else 466 | pn->right = child; 467 | } 468 | 469 | node_free(fn); 470 | fn = pn; /* backtrace */ 471 | } else { 472 | /* 'fn' is leaf, simply free it */ 473 | if (!pn) { 474 | /* radix tree is empty now */ 475 | radix = NULL; 476 | } else { 477 | /* update parent pointers */ 478 | if (pn->left == fn) 479 | pn->left = NULL; 480 | else 481 | pn->right = NULL; 482 | } 483 | node_free(fn); 484 | fn = pn; /* backtrace */ 485 | } 486 | 487 | /* 488 | * Trim 489 | */ 490 | 491 | while(fn) { 492 | if (fn->flag & RN_RINFO) /* never trim a rule info node */ 493 | break; 494 | 495 | pn = fn->parent; 496 | 497 | children = 0; 498 | child = NULL; 499 | if (fn->left) { 500 | child = fn->left; 501 | children++; 502 | } 503 | 504 | if (fn->right) { 505 | child = fn->right; 506 | children++; 507 | } 508 | 509 | if (children == 2) { 510 | /* never trim a node with two children */ 511 | break; 512 | } else if (children == 1) { 513 | /* move the single child up */ 514 | child->parent = pn; 515 | 516 | if (!pn) { 517 | /* child is root now */ 518 | radix = child; 519 | } else { 520 | /* update parent pointers */ 521 | if (pn->left == fn) 522 | pn->left = child; 523 | else 524 | pn->right = child; 525 | } 526 | 527 | node_free(fn); 528 | fn = pn; /* backtrace */ 529 | } else { 530 | /* 'fn' is leaf, simply free it */ 531 | if (!pn) { 532 | /* radix tree is empty now */ 533 | radix = NULL; 534 | } else { 535 | /* update parent pointers */ 536 | if (pn->left == fn) 537 | pn->left = NULL; 538 | else 539 | pn->right = NULL; 540 | } 541 | node_free(fn); 542 | fn = pn; /* backtrace */ 543 | } 544 | } 545 | 546 | return fn; 547 | } 548 | 549 | int ivi_rule6_delete(struct rule_info *rule) 550 | { 551 | struct rule6_node *fn, *next; 552 | u32 dir; 553 | int ret, plen6; 554 | 555 | ret = -1; 556 | 557 | if (rule->plen4 > 0) { 558 | /* concatenate ipv6 prefix and ipv4 prefix */ 559 | /* overwrite on 'rule' memory */ 560 | plen6 = rule->plen6 >> 3; 561 | rule->prefix6.s6_addr[ubyte_adjust(plen6)] = (unsigned char)(rule->prefix4 >> 24); 562 | rule->prefix6.s6_addr[ubyte_adjust(plen6 + 1)] = (unsigned char)((rule->prefix4 >> 16) & 0xff); 563 | rule->prefix6.s6_addr[ubyte_adjust(plen6 + 2)] = (unsigned char)((rule->prefix4 >> 8) & 0xff); 564 | rule->prefix6.s6_addr[ubyte_adjust(plen6 + 3)] = (unsigned char)(rule->prefix4 & 0xff); 565 | } 566 | 567 | spin_lock_bh(&radix_lock); 568 | 569 | if (unlikely(!radix)) { 570 | /* empty radix tree */ 571 | spin_unlock_bh(&radix_lock); 572 | return -1; 573 | } 574 | 575 | /* 576 | * Descend on a tree 577 | */ 578 | fn = radix; 579 | 580 | for (;;) { 581 | dir = addr_bit_set(&rule->prefix6, fn->bit_pos); 582 | 583 | next = dir ? fn->right : fn->left; 584 | 585 | if (!next) 586 | break; 587 | 588 | fn = next; 589 | } 590 | 591 | /* Exact match? */ 592 | if ((fn->flag & RN_RINFO) 593 | && (fn->bit_pos == ubyte_adjust_bit(rule->plen6 + rule->plen4)) 594 | && (fn->plen6 == rule->plen6) 595 | && (fn->ratio == rule->ratio) 596 | && (fn->adjacent == rule->adjacent) 597 | && (fn->format == rule->format) 598 | && ipv6_prefix_equal(&fn->key, &rule->prefix6, fn->bit_pos)) { 599 | if (radix_delete_trim(fn) != NULL) { 600 | ret = 0; 601 | #ifdef IVI_DEBUG_RULE 602 | printk(KERN_DEBUG "ivi_rule6_delete: " NIP6_FMT "/%d\n", NIP6(rule->prefix6), rule->plen6); 603 | #endif 604 | } 605 | } 606 | 607 | spin_unlock_bh(&radix_lock); 608 | 609 | return ret; 610 | } 611 | 612 | 613 | /* 614 | * Traversal (root first) 615 | */ 616 | 617 | static __inline int child_dir(struct rule6_node *p, struct rule6_node *c) 618 | { 619 | return (c == p->left) ? 0 : 1; 620 | } 621 | 622 | static struct rule6_node* next_rule6_info(struct rule6_node *p) 623 | { 624 | struct rule6_node *c; 625 | int dir; 626 | 627 | c = NULL; 628 | 629 | do { 630 | if (c) 631 | dir = child_dir(p, c) + 1; 632 | else 633 | dir = 0; 634 | 635 | while (dir < 2) { 636 | c = (dir++ == 0) ? p->left : p->right; 637 | if (!c) 638 | continue; 639 | 640 | if (c->flag & RN_RINFO) { 641 | return c; 642 | } 643 | 644 | /* Descend and start scanning in new node */ 645 | p = c; 646 | dir = 0; 647 | } 648 | 649 | /* Node empty, walk back up to parent */ 650 | c = p; 651 | } while ((p = c->parent) != NULL); 652 | 653 | return NULL; /* Root of trie */ 654 | } 655 | 656 | static struct rule6_node* first_rule6_info(void) 657 | { 658 | if (unlikely(!radix)) /* empty radix tree */ 659 | return NULL; 660 | 661 | if (radix->flag & RN_RINFO) /* root has rule info */ 662 | return radix; 663 | 664 | return next_rule6_info(radix); 665 | } 666 | 667 | void ivi_rule6_flush(void) 668 | { 669 | struct rule6_node *r, *rr = NULL; 670 | 671 | spin_lock_bh(&radix_lock); 672 | 673 | for (r = first_rule6_info(); r; r = next_rule6_info(r)) { 674 | #ifdef IVI_DEBUG_RULE 675 | printk(KERN_DEBUG "ivi_rule6_flush: " NIP6_FMT "/%d\n", NIP6(r->key), r->bit_pos); 676 | #endif 677 | if (rr) 678 | radix_delete_trim(rr); 679 | rr = r; 680 | } 681 | 682 | if (rr) 683 | radix_delete_trim(rr); 684 | 685 | spin_unlock_bh(&radix_lock); 686 | } 687 | 688 | 689 | int ivi_rule6_init(void) { 690 | radix = NULL; 691 | spin_lock_init(&radix_lock); 692 | #ifdef IVI_DEBUG 693 | balance = 0; 694 | printk(KERN_DEBUG "IVI: ivi_rule6 loaded.\n"); 695 | #endif 696 | return 0; 697 | } 698 | 699 | void ivi_rule6_exit(void) { 700 | ivi_rule6_flush(); 701 | #ifdef IVI_DEBUG 702 | printk(KERN_DEBUG "IVI: ivi_rule6 unloaded.\n"); 703 | printk(KERN_DEBUG "IVI: ivi_rule6 memory balance = %d\n", balance); 704 | #endif 705 | } 706 | -------------------------------------------------------------------------------- /modules/ivi_rule6.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_rule6.h : 4 | * 5 | * This file is the header file for the 'ivi_rule6.c' file. 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Wentao Shang 14 | * Yuncheng Zhu 15 | * Guoliang Han 16 | * 17 | * Contributions: 18 | * 19 | * This file is part of MAP-T/MAP-E Kernel Module. 20 | * 21 | * Permission to use, copy, modify, and distribute this software for any 22 | * purpose with or without fee is hereby granted, provided that the above 23 | * copyright notice and this permission notice appear in all copies. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with MAP-T/MAP-E Kernel Module. If not, see 27 | * . 28 | * 29 | * For more versions, please send an email to to 30 | * obtain an password to access the svn server. 31 | * 32 | * LIC: GPLv2 33 | * 34 | ************************************************************************/ 35 | 36 | 37 | #ifndef IVI_RULE6_H 38 | #define IVI_RULE6_H 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "ivi_config.h" 48 | #include "ivi_rule.h" 49 | 50 | extern u8 u_byte; 51 | 52 | static inline int ubyte_adjust(int pos) { 53 | if (!u_byte) 54 | return pos; 55 | 56 | if (pos < 8) 57 | return pos; 58 | else 59 | return pos + 1; 60 | } 61 | 62 | static inline int ubyte_adjust_bit(int pos) { 63 | if (!u_byte) 64 | return pos; 65 | 66 | if (pos < 64) 67 | return pos; 68 | else 69 | return pos + 8; 70 | } 71 | 72 | extern int ivi_rule6_insert(struct rule_info *rule); 73 | extern int ivi_rule6_lookup(struct in6_addr *addr, int *plen, u32 *prefix4, int *plen4, u16 *ratio, u16 *adjacent, u8 *fmt); 74 | extern int ivi_rule6_delete(struct rule_info *rule); 75 | extern void ivi_rule6_flush(void); 76 | 77 | extern int ivi_rule6_init(void); 78 | extern void ivi_rule6_exit(void); 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /modules/ivi_xmit.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_xmit.c : 4 | * 5 | * MAP-T/MAP-E Packet Transmission Kernel Module 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Guoliang Han 14 | * Yuncheng Zhu 15 | * Wentao Shang 16 | * 17 | * 18 | * Contributions: 19 | * 20 | * This file is part of MAP-T/MAP-E Kernel Module. 21 | * 22 | * Permission to use, copy, modify, and distribute this software for any 23 | * purpose with or without fee is hereby granted, provided that the above 24 | * copyright notice and this permission notice appear in all copies. 25 | * 26 | * You should have received a copy of the GNU General Public License 27 | * along with MAP-T/MAP-E Kernel Module. If not, see 28 | * . 29 | * 30 | * For more versions, please send an email to to 31 | * obtain an password to access the svn server. 32 | * 33 | * LIC: GPLv2 34 | * 35 | ************************************************************************/ 36 | 37 | #include "ivi_xmit.h" 38 | 39 | 40 | static inline int link_local_addr(const struct in6_addr *addr) { 41 | return ((addr->s6_addr32[0] & htonl(0xffc00000)) == htonl(0xfe800000)); 42 | } 43 | 44 | static inline int mc_v6_addr(const struct in6_addr *addr) { 45 | return (addr->s6_addr[0] == 0xff); 46 | } 47 | 48 | static inline int addr_in_v4network(const unsigned int *addr) { 49 | return ((ntohl(*addr) & v4mask) == (v4address & v4mask)); 50 | } 51 | 52 | u8 ivi_mode = 0; // working mode for IVI translation 53 | 54 | /* 55 | * Local parameter cache for fast path local address translation in hgw mode 56 | */ 57 | 58 | // IPv4 address of v4dev 59 | __be32 v4address = 0x01010101; // "1.1.1.1" in host byte order 60 | 61 | __be32 v4mask = 0xffffff00; // "/24" 62 | 63 | // NAT public address and mask for v4 network 64 | __be32 v4publicaddr = 0x03030303; // "3.3.3.3" in host byte order 65 | 66 | __be32 v4publicmask = 0xffffff00; // "/24" 67 | 68 | // v6 prefix where v4 network or public address is mapped into. 69 | __u8 v6prefix[16] = { 0x20, 0x01, 0x0d, 0xa8, 0x01, 0x23, 0x04, 0x56 }; // "2001:da8:123:456::" in network byte order 70 | 71 | __be32 v6prefixlen = 64; // "/64" prefix length 72 | 73 | u8 hgw_fmt = ADDR_FMT_MAPT; // default address format is MAP-T 74 | 75 | u8 hgw_transport = 0; // header manipulation manner 76 | 77 | u16 mss_limit = 1440; // max mss supported 78 | 79 | 80 | #define ADDR_DIR_SRC 0 81 | #define ADDR_DIR_DST 1 82 | 83 | static int ipaddr_4to6(unsigned int *v4addr, u16 port, u8 _dir, struct in6_addr *v6addr, u8 *transpt) { 84 | int prefixlen, plen4, ealen; 85 | u32 eabits; //FIXME: we assume 'ealen' won't be larger than 32 although max length of eabits is 48 86 | u32 addr, mask; 87 | u16 ratio, adjacent, offset, suffix; 88 | u8 fmt, remainder, i, o; 89 | 90 | addr = ntohl(*v4addr); 91 | eabits = 0; 92 | ealen = 0; 93 | ratio = adjacent = offset = suffix = fmt = 0; 94 | remainder= 0; 95 | 96 | memset(v6addr, 0, sizeof(struct in6_addr)); 97 | 98 | if (_dir == ADDR_DIR_DST) { 99 | if (ivi_rule_lookup(addr, v6addr, &plen4, &prefixlen, &ratio, &adjacent, &fmt, transpt) != 0) { 100 | printk(KERN_DEBUG "ipaddr_4to6: failed to map v4 addr " NIP4_FMT "\n", NIP4(addr)); 101 | return -1; 102 | } 103 | 104 | // when *transpt is set to MAP_E, an /128 IPv6 destination address is used in encapsulation header. 105 | if (*transpt == MAP_E) 106 | return 0; 107 | 108 | remainder = prefixlen - ((prefixlen >> 3) << 3); // in case IPv6 prefix isn't on a BYTE boundary 109 | prefixlen = prefixlen >> 3; // counted in bytes 110 | 111 | if (fmt != ADDR_FMT_NONE && ratio && adjacent) { // FMR matching rule found 112 | // Create EA bits for MAP format 113 | ratio = fls(ratio) - 1; // Length of PSID 114 | adjacent = fls(adjacent) - 1; // Length of M 115 | 116 | mask = ntohl(inet_make_mask(32 - ratio)); 117 | offset = (port >> adjacent) & ~mask & 0xffff; 118 | 119 | mask = ntohl(inet_make_mask(plen4)); 120 | eabits = (addr & ~mask) << plen4; 121 | ealen = 32 - plen4 + ratio; // IPv4 suffix length + length of PSID 122 | eabits += offset << (32 - ealen); 123 | 124 | if (fmt == ADDR_FMT_MAPT || fmt == ADDR_FMT_MAPX_CPE) 125 | suffix = offset; // left-padded 126 | } 127 | 128 | } else if (_dir == ADDR_DIR_SRC) { 129 | // Fast path for local address translation in hgw mode, use global parameters 130 | prefixlen = v6prefixlen >> 3; 131 | remainder = v6prefixlen - (prefixlen << 3); 132 | fmt = hgw_fmt; 133 | 134 | if (hgw_fmt == ADDR_FMT_MAPX_CPE && prefixlen != 8) { 135 | #ifdef IVI_DEBUG_RULE 136 | printk(KERN_DEBUG "ipaddr_4to6: MAP-X CPE prefix must be /64.\n"); 137 | #endif 138 | return -1; 139 | } 140 | 141 | // If prefix length isn't on a BYTE boundary, we have to copy (prefixlen + 1) bytes 142 | if(remainder) 143 | memcpy(v6addr, v6prefix, prefixlen + 1); 144 | else 145 | memcpy(v6addr, v6prefix, prefixlen); 146 | 147 | ratio = hgw_ratio; 148 | offset = hgw_offset; 149 | suffix = hgw_suffix; 150 | 151 | if (ivi_mode == IVI_MODE_HGW_NAT44) 152 | mask = v4publicmask; 153 | else 154 | mask = v4mask; 155 | 156 | // Create EA bits for MAP format 157 | ealen = ffs(mask) - 1; // Length of IPv4 subnet ID 158 | eabits = (addr & ~mask) << (32 - ealen); 159 | ealen += fls(ratio) - 1; // Length of PSID + Length of IPv4 subnet ID 160 | eabits += offset << (32 - ealen); 161 | 162 | } 163 | 164 | if (fmt == ADDR_FMT_MAPT) { 165 | if ((prefixlen << 3) + ealen <= 64) { 166 | o = 24 + remainder; // initial offset for the first uncompleted byte 167 | for (i = prefixlen; i < 8; i++) { // eabits outside /64 are cutted 168 | v6addr->s6_addr[i] += (unsigned char)((eabits >> o) & 0xff); 169 | o -= 8; 170 | } 171 | v6addr->s6_addr[8] = 0x00; 172 | v6addr->s6_addr[9] = (unsigned char)(addr >> 24); 173 | v6addr->s6_addr[10] = (unsigned char)((addr >> 16) & 0xff); 174 | v6addr->s6_addr[11] = (unsigned char)((addr >> 8) & 0xff); 175 | v6addr->s6_addr[12] = (unsigned char)(addr & 0xff); 176 | v6addr->s6_addr[13] = (suffix >> 8) & 0xff; 177 | v6addr->s6_addr[14] = suffix & 0xff; 178 | } else { 179 | #ifdef IVI_DEBUG_RULE 180 | printk(KERN_DEBUG "ipaddr_4to6: cannot map v4 addr " NIP4_FMT \ 181 | " because 'prefixlen + ealen' exceed 64\n", NIP4(addr)); 182 | #endif 183 | return -1; 184 | } 185 | } else if (fmt == ADDR_FMT_MAPX_CPE) { 186 | // this format has no eabits 187 | v6addr->s6_addr[9] = (unsigned char)(addr >> 24); 188 | v6addr->s6_addr[10] = (unsigned char)((addr >> 16) & 0xff); 189 | v6addr->s6_addr[11] = (unsigned char)((addr >> 8) & 0xff); 190 | v6addr->s6_addr[12] = (unsigned char)(addr & 0xff); 191 | v6addr->s6_addr[13] = (suffix >> 8) & 0xff; 192 | v6addr->s6_addr[14] = suffix & 0xff; 193 | } else { 194 | // DMR translation: just copy the addr 195 | v6addr->s6_addr[9] = (unsigned char)(addr >> 24); 196 | v6addr->s6_addr[10] = (unsigned char)((addr >> 16) & 0xff); 197 | v6addr->s6_addr[11] = (unsigned char)((addr >> 8) & 0xff); 198 | v6addr->s6_addr[12] = (unsigned char)(addr & 0xff); 199 | } 200 | 201 | return 0; 202 | } 203 | 204 | static int ipaddr_6to4(struct in6_addr *v6addr, u8 _dir, unsigned int *v4addr, u16 *ratio, u16 *adjacent, u16 *offset) { 205 | u32 addr; 206 | int prefixlen; 207 | u8 fmt; 208 | int retval; 209 | u32 prefix4, mask; 210 | int plen4; 211 | 212 | addr = prefix4 = mask = 0; 213 | fmt = 0; 214 | plen4 = 0; 215 | retval = 0; 216 | 217 | if ((ratio == NULL) || (adjacent == NULL) ||(offset == NULL)) { 218 | return -1; 219 | } 220 | 221 | // Do not translate ipv6 link local address. 222 | if (link_local_addr(v6addr)) { 223 | #ifdef IVI_DEBUG_RULE 224 | printk(KERN_DEBUG "ipaddr_6to4: ignore link local address.\n"); 225 | #endif 226 | return -1; 227 | } 228 | 229 | addr |= ((unsigned int)v6addr->s6_addr[9]) << 24; 230 | addr |= ((unsigned int)v6addr->s6_addr[10]) << 16; 231 | addr |= ((unsigned int)v6addr->s6_addr[11]) << 8; 232 | addr |= ((unsigned int)v6addr->s6_addr[12]); 233 | *v4addr = htonl(addr); 234 | 235 | if (_dir == ADDR_DIR_DST) { 236 | // Do not translate native IPv6 address 237 | if (ivi_mode == IVI_MODE_HGW && ((addr & v4mask) != (v4address & v4mask))) { 238 | //printk(KERN_DEBUG "ipaddr6to4: destination address not translated\n"); 239 | return -1; 240 | } 241 | else if (ivi_mode == IVI_MODE_HGW_NAT44 && ((addr & v4publicmask) != (v4publicaddr & v4publicmask))) { 242 | //printk(KERN_DEBUG "ipaddr6to4: destination address not translated\n"); 243 | return -1; 244 | } 245 | 246 | fmt = hgw_fmt; 247 | *ratio = hgw_ratio; 248 | *adjacent = hgw_adjacent; 249 | *offset = hgw_offset; 250 | } 251 | 252 | else if (_dir == ADDR_DIR_SRC) { 253 | if (ivi_rule6_lookup(v6addr, &prefixlen, &prefix4, &plen4, ratio, adjacent, &fmt) != 0) { 254 | // Solve the problem of "MAP-T packet's src address doesn't have a matching rule in MAP-E opposite end" 255 | *ratio = 1; 256 | *adjacent = 1; 257 | fmt = ADDR_FMT_NONE; 258 | retval = 1; 259 | } 260 | 261 | /* offset is obtained from Interface Identifier */ 262 | if (fmt == ADDR_FMT_MAPT) 263 | *offset = (v6addr->s6_addr[13] << 8) + v6addr->s6_addr[14]; 264 | else if (fmt == ADDR_FMT_NONE) 265 | *offset = 0; 266 | } 267 | 268 | return retval; 269 | } 270 | 271 | int ivi_v4v6_xmit(struct sk_buff *skb) { 272 | struct sk_buff *newskb; 273 | struct ethhdr *eth4, *eth6; 274 | struct iphdr *ip4h; 275 | struct ipv6hdr *ip6h; 276 | struct tcphdr *tcph; 277 | struct udphdr *udph; 278 | struct icmphdr *icmph; 279 | struct icmp6hdr *icmp6h; 280 | __u8 *payload; 281 | unsigned int hlen, plen; 282 | u16 newp, s_port, d_port; 283 | u8 transport; 284 | char flag_udp_nullcheck; 285 | 286 | eth4 = eth_hdr(skb); 287 | if (unlikely(eth4->h_proto != __constant_ntohs(ETH_P_IP))) { 288 | // This should not happen since we are hooked on PF_INET. 289 | #ifdef IVI_DEBUG 290 | printk(KERN_ERR "ivi_v4v6_xmit: non-IPv4 packet type %x received on IPv4 hook.\n", ntohs(eth4->h_proto)); 291 | #endif 292 | return -EINVAL; // Just accept. 293 | } 294 | 295 | ip4h = ip_hdr(skb); 296 | 297 | // By pass multicast packet 298 | if (ipv4_is_multicast(ip4h->daddr) || ipv4_is_lbcast(ip4h->daddr) || ipv4_is_loopback(ip4h->daddr)) { 299 | #ifdef IVI_DEBUG 300 | printk(KERN_DEBUG "ivi_v4v6_xmit: by pass ipv4 multicast/broadcast/loopback dest address.\n"); 301 | #endif 302 | return -EINVAL; // Just accept. 303 | } 304 | 305 | // Do not translate ipv4 packets (hair pin) that are toward v4network. 306 | if (addr_in_v4network(&(ip4h->daddr))) { 307 | #ifdef IVI_DEBUG 308 | printk(KERN_DEBUG "ivi_v4v6_xmit: IPv4 packet toward the v4 network bypassed in HGW mode.\n"); 309 | #endif 310 | return -EINVAL; // Just accept. 311 | } 312 | 313 | if (ip4h->ttl <= 1) { 314 | return -EINVAL; // Just accept. 315 | } 316 | 317 | plen = ntohs(ip4h->tot_len) - (ip4h->ihl * 4); 318 | payload = (__u8 *)(ip4h) + (ip4h->ihl << 2); 319 | s_port = d_port = newp = 0; 320 | transport = 0; 321 | flag_udp_nullcheck = 0; 322 | 323 | switch (ip4h->protocol) { 324 | case IPPROTO_TCP: 325 | tcph = (struct tcphdr *)payload; 326 | 327 | if (tcph->syn && (tcph->doff > 5)) { 328 | __u16 *option = (__u16*)tcph; 329 | if (option[10] == htons(0x0204)) { 330 | if (ntohs(option[11]) > mss_limit) { 331 | csum_replace2(&tcph->check, option[11], htons(mss_limit)); 332 | option[11] = htons(mss_limit); 333 | } 334 | } 335 | } 336 | 337 | if (ivi_mode == IVI_MODE_HGW && ntohs(tcph->source) < 1024) { 338 | newp = ntohs(tcph->source); 339 | } 340 | 341 | else if (get_outflow_tcp_map_port(ntohl(ip4h->saddr), ntohs(tcph->source), ntohl(ip4h->daddr), \ 342 | ntohs(tcph->dest), hgw_ratio, hgw_adjacent, hgw_offset, tcph, plen, &newp) == -1) { 343 | #ifdef IVI_DEBUG 344 | printk(KERN_ERR "ivi_v4v6_xmit: fail to perform nat44 mapping for " NIP4_FMT \ 345 | ":%d (TCP).\n", NIP4(ip4h->saddr), ntohs(tcph->source)); 346 | #endif 347 | return 0; // silently drop 348 | 349 | } 350 | 351 | if (ivi_mode == IVI_MODE_HGW_NAT44) { 352 | csum_replace4(&tcph->check, ip4h->saddr, htonl(v4publicaddr)); 353 | csum_replace4(&ip4h->check, ip4h->saddr, htonl(v4publicaddr)); 354 | ip4h->saddr = htonl(v4publicaddr); 355 | } 356 | csum_replace2(&tcph->check, tcph->source, htons(newp)); 357 | tcph->source = htons(newp); 358 | s_port = ntohs(tcph->source); 359 | d_port = ntohs(tcph->dest); 360 | 361 | break; 362 | 363 | case IPPROTO_UDP: 364 | udph = (struct udphdr *)payload; 365 | if (udph->check == 0) 366 | flag_udp_nullcheck = 1; 367 | 368 | if (ivi_mode == IVI_MODE_HGW && ntohs(udph->source) < 1024) { 369 | newp = ntohs(udph->source); 370 | } 371 | 372 | else if (get_outflow_map_port(&udp_list, ntohl(ip4h->saddr), ntohs(udph->source), \ 373 | ntohl(ip4h->daddr), hgw_ratio, hgw_adjacent, hgw_offset, &newp) == -1) { 374 | #ifdef IVI_DEBUG 375 | printk(KERN_ERR "ivi_v4v6_xmit: fail to perform nat44 mapping for " NIP4_FMT \ 376 | ":%d (UDP).\n", NIP4(ip4h->saddr), ntohs(udph->source)); 377 | #endif 378 | return 0; // silently drop 379 | 380 | } 381 | 382 | if (ivi_mode == IVI_MODE_HGW_NAT44) { 383 | if (!flag_udp_nullcheck) { 384 | csum_replace4(&udph->check, ip4h->saddr, htonl(v4publicaddr)); 385 | } 386 | csum_replace4(&ip4h->check, ip4h->saddr, htonl(v4publicaddr)); 387 | ip4h->saddr = htonl(v4publicaddr); 388 | } 389 | if (!flag_udp_nullcheck) { 390 | csum_replace2(&udph->check, udph->source, htons(newp)); 391 | } 392 | udph->source = htons(newp); 393 | s_port = ntohs(udph->source); 394 | d_port = ntohs(udph->dest); 395 | 396 | break; 397 | 398 | case IPPROTO_ICMP: 399 | icmph = (struct icmphdr *)payload; 400 | 401 | if (icmph->type == ICMP_ECHO) { 402 | if (get_outflow_map_port(&icmp_list, ntohl(ip4h->saddr), ntohs(icmph->un.echo.id), \ 403 | ntohl(ip4h->daddr), hgw_ratio, hgw_adjacent, hgw_offset, &newp) == -1) { 404 | #ifdef IVI_DEBUG 405 | printk(KERN_ERR "ivi_v4v6_xmit: fail to perform nat44 mapping for " NIP4_FMT \ 406 | ":%d (ICMP).\n", NIP4(ip4h->saddr), ntohs(icmph->un.echo.id)); 407 | #endif 408 | return 0; // silently drop 409 | 410 | } else { 411 | if (ivi_mode == IVI_MODE_HGW_NAT44) { 412 | csum_replace4(&ip4h->check, ip4h->saddr, htonl(v4publicaddr)); 413 | ip4h->saddr = htonl(v4publicaddr); 414 | } 415 | csum_replace2(&icmph->checksum, icmph->un.echo.id, htons(newp)); 416 | icmph->un.echo.id = htons(newp); 417 | } 418 | s_port = d_port = ntohs(icmph->un.echo.id); 419 | 420 | } else if (icmph->type == ICMP_ECHOREPLY) { 421 | if (ivi_mode == IVI_MODE_HGW_NAT44) { 422 | #ifdef IVI_DEBUG 423 | printk(KERN_ERR "ivi_v4v6_xmit: we currently doesn't send ECHO-REPLY " \ 424 | "when CPE is working in NAT44 mode\n"); 425 | #endif 426 | return 0; // silently drop 427 | } 428 | s_port = d_port = ntohs(icmph->un.echo.id); 429 | 430 | } else { 431 | printk(KERN_ERR "ivi_v4v6_xmit: unsupported ICMP type in NAT44. Drop packet now.\n"); 432 | return 0; 433 | } 434 | 435 | break; 436 | 437 | #ifdef IVI_DEBUG 438 | default: 439 | printk(KERN_ERR "ivi_v4v6_xmit: unsupported protocol %d in IPv4 packet.\n", ip4h->protocol); 440 | #endif 441 | } 442 | 443 | hlen = sizeof(struct ipv6hdr); 444 | if (!(newskb = dev_alloc_skb(2 + ETH_HLEN + hlen + htons(ip4h->tot_len)))) { 445 | // Allocation size is enough for both E and T; 446 | // Even in ICMP translation case, it's enough for two IP headers' translation. 447 | printk(KERN_ERR "ivi_v4v6_xmit: failed to allocate new socket buffer.\n"); 448 | return 0; // Drop packet on low memory 449 | } 450 | skb_reserve(newskb, 2); // Align IP header on 16 byte boundary (ETH_LEN + 2) 451 | 452 | eth6 = (struct ethhdr *)skb_put(newskb, ETH_HLEN); 453 | // Keep mac unchanged 454 | memcpy(eth6, eth4, 12); 455 | eth6->h_proto = __constant_ntohs(ETH_P_IPV6); 456 | 457 | ip6h = (struct ipv6hdr *)skb_put(newskb, hlen); 458 | 459 | if (ipaddr_4to6(&(ip4h->daddr), d_port, ADDR_DIR_DST, &(ip6h->daddr), &transport) != 0) { 460 | kfree_skb(newskb); 461 | return -EINVAL; 462 | } 463 | 464 | if (ipaddr_4to6(&(ip4h->saddr), s_port, ADDR_DIR_SRC, &(ip6h->saddr), NULL) != 0) { 465 | kfree_skb(newskb); 466 | return -EINVAL; 467 | } 468 | 469 | *(__u32 *)ip6h = __constant_htonl(0x60000000); 470 | 471 | if (transport == MAP_E) { 472 | // Encapsulation 473 | ip6h->payload_len = ip4h->tot_len; 474 | plen = ntohs(ip4h->tot_len); 475 | ip6h->nexthdr = IPPROTO_IPIP; 476 | ip6h->hop_limit = 64 + 1; // we have to put translated IPv6 packet into the protocol stack again 477 | payload = (__u8 *)skb_put(newskb, plen); 478 | skb_copy_bits(skb, 0, payload, plen); 479 | } 480 | 481 | else { 482 | // Translation 483 | ip6h->hop_limit = ip4h->ttl; 484 | ip6h->payload_len = htons(plen); 485 | ip6h->nexthdr = ip4h->protocol; /* Need to be xlated for ICMP protocol */ 486 | 487 | payload = (__u8 *)skb_put(newskb, plen); 488 | switch (ip6h->nexthdr) { 489 | case IPPROTO_TCP: 490 | skb_copy_bits(skb, ip4h->ihl * 4, payload, plen); 491 | tcph = (struct tcphdr *)payload; 492 | tcph->check = 0; 493 | tcph->check = csum_ipv6_magic(&(ip6h->saddr), &(ip6h->daddr), plen, IPPROTO_TCP, \ 494 | csum_partial(payload, plen, 0)); 495 | break; 496 | 497 | case IPPROTO_UDP: 498 | skb_copy_bits(skb, ip4h->ihl * 4, payload, plen); 499 | udph = (struct udphdr *)payload; 500 | udph->check = 0; 501 | udph->check = csum_ipv6_magic(&(ip6h->saddr), &(ip6h->daddr), plen, IPPROTO_UDP, \ 502 | csum_partial(payload, plen, 0)); 503 | break; 504 | 505 | case IPPROTO_ICMP: 506 | ip6h->nexthdr = IPPROTO_ICMPV6; 507 | skb_copy_bits(skb, ip4h->ihl * 4, payload, 4); // ICMPv6 header length 508 | icmp6h = (struct icmp6hdr *)payload; 509 | 510 | if (icmp6h->icmp6_type == ICMP_ECHO || icmp6h->icmp6_type == ICMP_ECHOREPLY) { 511 | skb_copy_bits(skb, ip4h->ihl * 4 + 4, payload + 4, plen - 4); 512 | if (icmp6h->icmp6_type == ICMP_ECHO) 513 | icmp6h->icmp6_type = ICMPV6_ECHO_REQUEST; 514 | else 515 | icmp6h->icmp6_type = ICMPV6_ECHO_REPLY; 516 | 517 | icmp6h->icmp6_cksum = 0; 518 | icmp6h->icmp6_cksum = csum_ipv6_magic(&(ip6h->saddr), &(ip6h->daddr), plen, \ 519 | IPPROTO_ICMPV6, csum_partial(payload, plen, 0)); 520 | 521 | } else { 522 | //printk(KERN_ERR "ivi_v4v6_xmit: unsupported ICMP type in xlate. Drop packet.\n"); 523 | kfree_skb(newskb); 524 | return 0; 525 | } 526 | break; 527 | 528 | default: 529 | kfree_skb(newskb); 530 | return 0; 531 | } 532 | } 533 | 534 | // Prepare to re-enter the protocol stack 535 | newskb->protocol = eth_type_trans(newskb, skb->dev); 536 | newskb->ip_summed = CHECKSUM_NONE; 537 | 538 | netif_rx(newskb); 539 | return 0; 540 | } 541 | 542 | 543 | static inline bool port_in_range(u16 _port, u16 _ratio, u16 _adjacent, u16 _offset) 544 | { 545 | if (_ratio == 1) 546 | return true; 547 | else { 548 | // (_port / _adjacent) % _ratio 549 | u16 temp; 550 | _ratio = fls(_ratio) - 1; 551 | _adjacent = fls(_adjacent) - 1; 552 | temp = (_port >> _adjacent); 553 | return (temp - ((temp >> _ratio) << _ratio) == _offset); 554 | } 555 | } 556 | 557 | int ivi_v6v4_xmit(struct sk_buff *skb) { 558 | struct sk_buff *newskb; 559 | struct ethhdr *eth6, *eth4; 560 | struct iphdr *ip4h, *icmp_ip4h; 561 | struct ipv6hdr *ip6h, *icmp_ip6h; 562 | struct tcphdr *tcph, *icmp_tcph; 563 | struct udphdr *udph, *icmp_udph; 564 | struct icmphdr *icmph, *icmp_icmp4h; 565 | struct frag_hdr *fragh; 566 | __u8 *payload; 567 | int hlen, plen; 568 | __u8 poffset; 569 | __u8 flag4; 570 | __u16 off4; 571 | __be32 oldaddr; 572 | __be16 oldp; 573 | u16 s_ratio, s_adj, s_offset, d_ratio, d_adj, d_offset; 574 | u8 next_hdr, *ext_hdr; 575 | u32 tempaddr; 576 | 577 | fragh = NULL; 578 | 579 | eth6 = eth_hdr(skb); 580 | ip6h = ipv6_hdr(skb); 581 | hlen = sizeof(struct iphdr); 582 | plen = ntohs(ip6h->payload_len); 583 | poffset = sizeof(struct ipv6hdr); // Payload Offset 584 | 585 | // This should not happen since we are hooked on PF_INET6. 586 | if (unlikely(eth6->h_proto != __constant_ntohs(ETH_P_IPV6))) { 587 | return -EINVAL; // Just accept. 588 | } 589 | 590 | // By pass ipv6 multicast packet (for ND) 591 | if (mc_v6_addr(&(ip6h->daddr))) { 592 | return -EINVAL; 593 | } 594 | 595 | // leave the generation of ICMP packet to the protocol stack 596 | if (ip6h->hop_limit <= 1) { 597 | return -EINVAL; 598 | } 599 | 600 | // process extension headers 601 | next_hdr = ip6h->nexthdr; 602 | ext_hdr = (__u8 *)ip6h + sizeof(struct ipv6hdr); 603 | while (next_hdr != IPPROTO_IPIP && 604 | next_hdr != IPPROTO_TCP && 605 | next_hdr != IPPROTO_UDP && 606 | next_hdr != IPPROTO_ICMPV6) { 607 | 608 | if (next_hdr == IPPROTO_FRAGMENT) { 609 | printk(KERN_INFO "FRAGMENT header: frag_off is %x, identification is %x\n", \ 610 | ntohs(*((u16 *)ext_hdr + 1)), ntohl(*((u32 *)ext_hdr + 1))); 611 | fragh = (struct frag_hdr *)ext_hdr; 612 | plen -= sizeof(struct frag_hdr); 613 | poffset += sizeof(struct frag_hdr); 614 | next_hdr = fragh->nexthdr; 615 | ext_hdr += sizeof(struct frag_hdr); 616 | } 617 | else if (next_hdr == IPPROTO_AH) { 618 | printk(KERN_INFO "AH header, length is %d\n", *(ext_hdr + 1)); 619 | plen -= (*(ext_hdr + 1) << 2) + 8; 620 | poffset += (*(ext_hdr + 1) << 2) + 8; 621 | next_hdr = *ext_hdr; 622 | ext_hdr += (*(ext_hdr + 1) << 2) + 8; 623 | } 624 | else { 625 | printk(KERN_INFO "other header type is %d, length is %d\n", next_hdr, *(ext_hdr + 1)); 626 | plen -= (*(ext_hdr + 1) << 3) + 8; 627 | poffset += (*(ext_hdr + 1) << 3) + 8; 628 | next_hdr = *ext_hdr; 629 | ext_hdr += (*(ext_hdr + 1) << 3) + 8; 630 | } 631 | } 632 | 633 | if (!(newskb = dev_alloc_skb(2 + ETH_HLEN + max(hlen + plen, 184) + 20))) { 634 | printk(KERN_ERR "ivi_v6v4_xmit: failed to allocate new socket buffer.\n"); 635 | return 0; // Drop packet on low memory 636 | } 637 | skb_reserve(newskb, 2); // Align IP header on 16 byte boundary (ETH_LEN + 2) 638 | 639 | eth4 = (struct ethhdr *)skb_put(newskb, ETH_HLEN); 640 | memcpy(eth4, eth6, 12); // Keep mac unchanged 641 | eth4->h_proto = __constant_ntohs(ETH_P_IP); 642 | 643 | if (next_hdr == IPPROTO_IPIP) { // Decapsulation 644 | payload = (__u8 *)skb_put(newskb, plen); 645 | skb_copy_bits(skb, poffset, payload, plen); 646 | ip4h = (struct iphdr *)payload; 647 | payload += ip4h->ihl << 2; 648 | 649 | switch (ip4h->protocol) { 650 | case IPPROTO_TCP: 651 | tcph = (struct tcphdr *)payload; 652 | 653 | if (!port_in_range(ntohs(tcph->dest), hgw_ratio, hgw_adjacent, hgw_offset)) { 654 | //printk(KERN_INFO "ivi_v6v4_xmit: TCP dest port %d is not in range (r=%d, m=%d, o=%d)." 655 | // "Drop packet.\n", ntohs(tcph->dest), hgw_ratio, hgw_adjacent, hgw_offset); 656 | kfree_skb(newskb); 657 | return 0; 658 | } 659 | 660 | if (ivi_mode == IVI_MODE_HGW && ntohs(tcph->dest) < 1024) { 661 | oldaddr = ntohl(ip4h->daddr); 662 | oldp = ntohs(tcph->dest); 663 | } 664 | 665 | else if (get_inflow_tcp_map_port(ntohs(tcph->dest), ntohl(ip4h->saddr), ntohs(tcph->source), \ 666 | tcph, plen, &oldaddr, &oldp) == -1) { 667 | //printk(KERN_ERR "ivi_v6v4_xmit: fail to perform nat44 mapping for %d (TCP).\n", 668 | // ntohs(tcph->dest)); 669 | kfree_skb(newskb); 670 | return 0; 671 | } 672 | 673 | csum_replace4(&tcph->check, ip4h->daddr, htonl(oldaddr)); 674 | csum_replace4(&ip4h->check, ip4h->daddr, htonl(oldaddr)); 675 | ip4h->daddr = htonl(oldaddr); 676 | 677 | csum_replace2(&tcph->check, tcph->dest, htons(oldp)); 678 | tcph->dest = htons(oldp); 679 | 680 | if (tcph->syn && (tcph->doff > 5)) { 681 | __u16 *option = (__u16*)tcph; 682 | if (option[10] == htons(0x0204)) { 683 | if (ntohs(option[11]) > mss_limit) { 684 | csum_replace2(&tcph->check, option[11], htons(mss_limit)); 685 | option[11] = htons(mss_limit); 686 | } 687 | } 688 | } 689 | 690 | break; 691 | 692 | case IPPROTO_UDP: 693 | udph = (struct udphdr *)payload; 694 | 695 | if (!port_in_range(ntohs(udph->dest), hgw_ratio, hgw_adjacent, hgw_offset)) { 696 | //printk(KERN_INFO "ivi_v6v4_xmit: UDP dest port %d is not in range (r=%d, m=%d, o=%d)." 697 | // "Drop packet.\n", ntohs(udph->dest), hgw_ratio, hgw_adjacent, hgw_offset); 698 | kfree_skb(newskb); 699 | return 0; 700 | } 701 | 702 | if (ivi_mode == IVI_MODE_HGW && ntohs(udph->dest) < 1024) { 703 | oldaddr = ntohl(ip4h->daddr); 704 | oldp = ntohs(udph->dest); 705 | } 706 | 707 | else if (get_inflow_map_port(&udp_list, ntohs(udph->dest), ntohl(ip4h->saddr), \ 708 | &oldaddr, &oldp) == -1) { 709 | //printk(KERN_ERR "ivi_v6v4_xmit: fail to perform nat44 mapping for %d (UDP).\n", 710 | // ntohs(udph->dest)); 711 | kfree_skb(newskb); 712 | return 0; 713 | } 714 | 715 | // If checksum of UDP inside IPv4 packet is 0, we MUST NOT update the checksum value. 716 | if (udph->check != 0) { 717 | csum_replace4(&udph->check, ip4h->daddr, htonl(oldaddr)); 718 | csum_replace2(&udph->check, udph->dest, htons(oldp)); 719 | } 720 | 721 | csum_replace4(&ip4h->check, ip4h->daddr, htonl(oldaddr)); 722 | ip4h->daddr = htonl(oldaddr); 723 | udph->dest = htons(oldp); 724 | 725 | break; 726 | 727 | case IPPROTO_ICMP: 728 | icmph = (struct icmphdr *)payload; 729 | if (icmph->type == ICMP_ECHOREPLY) { 730 | if (get_inflow_map_port(&icmp_list, ntohs(icmph->un.echo.id), ntohl(ip4h->saddr), \ 731 | &oldaddr, &oldp) == -1) { 732 | tempaddr = ntohl(ip4h->saddr); 733 | printk(KERN_ERR "ivi_v6v4_xmit: fail to perform nat44 mapping for ( " NIP4_FMT \ 734 | ", %d) (ICMP).\n", NIP4(tempaddr), ntohs(icmph->un.echo.id)); 735 | kfree_skb(newskb); 736 | return 0; 737 | } else { 738 | csum_replace4(&ip4h->check, ip4h->daddr, htonl(oldaddr)); 739 | ip4h->daddr = htonl(oldaddr); 740 | 741 | csum_replace2(&icmph->checksum, icmph->un.echo.id, htons(oldp)); 742 | icmph->un.echo.id = htons(oldp); 743 | } 744 | } 745 | else if (icmph->type == ICMP_ECHO) { 746 | if (ivi_mode == IVI_MODE_HGW_NAT44) { 747 | #ifdef IVI_DEBUG 748 | printk(KERN_INFO "ivi_v6v4_xmit: you can't ping private address when CPE is working in NAT44 mode\n"); 749 | #endif 750 | return 0; // silently drop 751 | } 752 | } 753 | else if (icmph->type == ICMP_TIME_EXCEEDED) { 754 | icmp_ip4h = (struct iphdr *)((__u8 *)icmph + 8); 755 | if (icmp_ip4h->protocol == IPPROTO_ICMP) { 756 | icmp_icmp4h = (struct icmphdr *)((__u8 *)icmp_ip4h + (icmp_ip4h->ihl << 2)); 757 | if (icmp_icmp4h->type == ICMP_ECHO) { 758 | if (get_inflow_map_port(&icmp_list, ntohs(icmp_icmp4h->un.echo.id), \ 759 | ntohl(icmp_ip4h->daddr), &oldaddr, &oldp) == -1) { 760 | printk(KERN_ERR "ivi_v6v4_xmit: fail to perform nat44 mapping for %d (ICMP) "\ 761 | "in IP packet.\n", ntohs(icmph->un.echo.id)); 762 | kfree_skb(newskb); 763 | return 0; 764 | } else { 765 | csum_replace4(&icmp_ip4h->check, icmp_ip4h->saddr, htonl(oldaddr)); 766 | icmp_ip4h->saddr = htonl(oldaddr); 767 | csum_replace2(&icmp_icmp4h->checksum, icmp_icmp4h->un.echo.id, htons(oldp)); 768 | icmp_icmp4h->un.echo.id = htons(oldp); 769 | } 770 | } 771 | } 772 | } 773 | break; 774 | 775 | default: 776 | kfree_skb(newskb); 777 | return 0; 778 | } 779 | } 780 | 781 | else { // Translation 782 | ip4h = (struct iphdr *)skb_put(newskb, hlen); 783 | if (ipaddr_6to4(&(ip6h->saddr), ADDR_DIR_SRC, &(ip4h->saddr), &s_ratio, &s_adj, &s_offset) < 0) { 784 | kfree_skb(newskb); 785 | return -EINVAL; // Just accept. 786 | } 787 | if (ipaddr_6to4(&(ip6h->daddr), ADDR_DIR_DST, &(ip4h->daddr), &d_ratio, &d_adj, &d_offset) < 0) { 788 | kfree_skb(newskb); 789 | return -EINVAL; // Just accept. 790 | } 791 | 792 | *(__u16 *)ip4h = __constant_htons(0x4500); 793 | ip4h->tot_len = htons(hlen + plen); 794 | 795 | if (fragh) { // Containing Fragment Header 796 | ip4h->id = htons(ntohl(fragh->identification) & 0xffff); 797 | flag4 = ntohs(fragh->frag_off) & 0x0001; // DF=0, MF is copied without change 798 | off4 = (ntohs(fragh->frag_off)>>3) & 0x1fff; 799 | ip4h->frag_off = htons((flag4 << 13) + off4); 800 | ip4h->ttl = ip6h->hop_limit; 801 | ip4h->protocol = next_hdr; // ICMPv6 is translated below 802 | } 803 | else { 804 | ip4h->id = 0; 805 | ip4h->frag_off = htons(0x4000); // DF=1 806 | ip4h->ttl = ip6h->hop_limit; 807 | ip4h->protocol = next_hdr; // ICMPv6 is translated below 808 | } 809 | 810 | payload = (__u8 *)skb_put(newskb, plen); 811 | switch (next_hdr) { 812 | case IPPROTO_TCP: 813 | skb_copy_bits(skb, poffset, payload, plen); 814 | tcph = (struct tcphdr *)payload; 815 | 816 | if (!port_in_range(ntohs(tcph->dest), hgw_ratio, hgw_adjacent, hgw_offset)) { 817 | //printk(KERN_INFO "ivi_v6v4_xmit: TCP dest port %d is not in range (r=%d, m=%d, o=%d). " 818 | // "Drop packet.\n", ntohs(tcph->dest), hgw_ratio, hgw_adjacent, hgw_offset); 819 | kfree_skb(newskb); 820 | return 0; 821 | } 822 | 823 | if (ivi_mode == IVI_MODE_HGW && ntohs(tcph->dest) < 1024) { 824 | oldaddr = ntohl(ip4h->daddr); 825 | oldp = ntohs(tcph->dest); 826 | } 827 | 828 | else if (get_inflow_tcp_map_port(ntohs(tcph->dest), ntohl(ip4h->saddr), ntohs(tcph->source), \ 829 | tcph, plen, &oldaddr, &oldp) == -1) { 830 | //printk(KERN_ERR "ivi_v6v4_xmit: fail to perform nat44 mapping for %d (TCP).\n", 831 | // ntohs(tcph->dest)); 832 | kfree_skb(newskb); 833 | return 0; 834 | } 835 | 836 | ip4h->daddr = htonl(oldaddr); 837 | tcph->dest = htons(oldp); 838 | 839 | if (tcph->syn && (tcph->doff > 5)) { 840 | __u16 *option = (__u16*)tcph; 841 | if (option[10] == htons(0x0204)) { 842 | if (ntohs(option[11]) > mss_limit) { 843 | option[11] = htons(mss_limit); 844 | } 845 | } 846 | } 847 | 848 | tcph->check = 0; 849 | tcph->check = csum_tcpudp_magic(ip4h->saddr, ip4h->daddr, plen, IPPROTO_TCP, \ 850 | csum_partial(payload, plen, 0)); 851 | break; 852 | 853 | case IPPROTO_UDP: 854 | skb_copy_bits(skb, poffset, payload, plen); 855 | udph = (struct udphdr *)payload; 856 | 857 | if (!port_in_range(ntohs(udph->dest), hgw_ratio, hgw_adjacent, hgw_offset)) { 858 | //printk(KERN_INFO "ivi_v6v4_xmit: UDP dest port %d is not in range (r=%d, m=%d, o=%d)." 859 | // " Drop packet.\n", ntohs(udph->dest), hgw_ratio, hgw_adjacent, hgw_offset); 860 | kfree_skb(newskb); 861 | return 0; 862 | } 863 | 864 | if (ivi_mode == IVI_MODE_HGW && ntohs(udph->dest) < 1024) { 865 | oldaddr = ntohl(ip4h->daddr); 866 | oldp = ntohs(udph->dest); 867 | } 868 | 869 | else if (get_inflow_map_port(&udp_list, ntohs(udph->dest), ntohl(ip4h->saddr), \ 870 | &oldaddr, &oldp) == -1) { 871 | //printk(KERN_ERR "ivi_v6v4_xmit: fail to perform nat44 mapping for %d (UDP).\n", ntohs(udph->dest)); 872 | kfree_skb(newskb); 873 | return 0; 874 | } 875 | 876 | ip4h->daddr = htonl(oldaddr); 877 | udph->dest = htons(oldp); 878 | 879 | udph->check = 0; 880 | udph->check = csum_tcpudp_magic(ip4h->saddr, ip4h->daddr, plen, IPPROTO_UDP, \ 881 | csum_partial(payload, plen, 0)); 882 | break; 883 | 884 | case IPPROTO_ICMPV6: // indicating ICMPv4 packet 885 | ip4h->protocol = IPPROTO_ICMP; 886 | skb_copy_bits(skb, poffset, payload, 8); 887 | icmph = (struct icmphdr *)payload; 888 | 889 | if (icmph->type == ICMPV6_ECHO_REQUEST || icmph->type == ICMPV6_ECHO_REPLY) { 890 | skb_copy_bits(skb, poffset + 8, payload + 8, plen - 8); 891 | icmph->type = (icmph->type == ICMPV6_ECHO_REQUEST) ? ICMP_ECHO : ICMP_ECHOREPLY; 892 | 893 | if (icmph->type == ICMP_ECHOREPLY) { 894 | if (get_inflow_map_port(&icmp_list, ntohs(icmph->un.echo.id), ntohl(ip4h->saddr),\ 895 | &oldaddr, &oldp) == -1) { 896 | //printk(KERN_INFO "ivi_v6v4_xmit: fail to perform nat44 mapping for %d (ICMP).\n", 897 | // ntohs(icmph->un.echo.id)); 898 | } else { 899 | ip4h->daddr = htonl(oldaddr); 900 | icmph->un.echo.id = htons(oldp); 901 | } 902 | } 903 | 904 | icmph->checksum = 0; 905 | icmph->checksum = ip_compute_csum(icmph, plen); 906 | 907 | } else { 908 | if (icmph->type == ICMPV6_TIME_EXCEED) { 909 | icmph->type = ICMP_TIME_EXCEEDED; 910 | } 911 | else if (icmph->type == ICMPV6_DEST_UNREACH) { 912 | icmph->type = ICMP_DEST_UNREACH; 913 | if (icmph->code == ICMPV6_NOROUTE) 914 | icmph->code = ICMP_HOST_UNREACH; 915 | else if (icmph->code == ICMPV6_PORT_UNREACH) 916 | icmph->code = ICMP_PORT_UNREACH; 917 | } 918 | else { 919 | //printk(KERN_ERR "ivi_v6v4_xmit: unsupported ICMP type. Drop Packet now.\n"); 920 | return 0; 921 | } 922 | 923 | icmph->checksum = 0; 924 | memset((__u8 *)icmph + 4, 0, 4); 925 | 926 | // translation of ipv6 header embeded in icmpv6 927 | icmp_ip4h = (struct iphdr *)((__u8 *)icmph + 8); 928 | icmp_ip6h = (struct ipv6hdr *)((__u8 *)ip6h + poffset + sizeof(struct icmp6hdr)); 929 | *(__u16 *)icmp_ip4h = __constant_htons(0x4500); 930 | 931 | icmp_ip4h->id = 0; 932 | icmp_ip4h->frag_off = htons(0x4000); 933 | icmp_ip4h->ttl = icmp_ip6h->hop_limit; 934 | icmp_ip4h->protocol = icmp_ip6h->nexthdr; 935 | icmp_ip4h->check = 0; 936 | ipaddr_6to4(&(icmp_ip6h->saddr), ADDR_DIR_SRC, &(icmp_ip4h->saddr), &s_ratio, &s_adj, &s_offset); 937 | ipaddr_6to4(&(icmp_ip6h->daddr), ADDR_DIR_DST, &(icmp_ip4h->daddr), &d_ratio, &d_adj, &d_offset); 938 | payload = (__u8 *)icmp_ip4h + sizeof(struct iphdr); 939 | 940 | ip4h->tot_len = htons(ntohs(ip4h->tot_len)-20); 941 | icmp_ip4h->tot_len = htons(sizeof(struct iphdr) + ntohs(icmp_ip6h->payload_len)); 942 | skb_copy_bits(skb, poffset + sizeof(struct icmp6hdr) + sizeof(struct ipv6hdr), payload,\ 943 | ntohs(icmp_ip6h->payload_len)); 944 | 945 | switch (icmp_ip4h->protocol) { 946 | case IPPROTO_TCP: 947 | icmp_tcph = (struct tcphdr *)((__u8 *)icmp_ip4h + 20); 948 | oldaddr = oldp = 0; 949 | get_inflow_tcp_map_port(ntohs(icmp_tcph->source), ntohl(icmp_ip4h->daddr), 950 | ntohs(icmp_tcph->dest), icmp_tcph, ntohs(icmp_ip4h->tot_len) - 20,&oldaddr, &oldp); 951 | 952 | if (oldaddr == 0 && oldp == 0) // Many ICMP packets have an uncomplete inside TCP structure: 953 | // return value is -1 alone cannot imply a fail lookup. 954 | printk(KERN_ERR "ivi_v6v4_xmit: tcp-in-icmp reverse lookup failure.\n"); 955 | 956 | else { 957 | icmp_ip4h->saddr = ip4h->daddr = htonl(oldaddr); 958 | icmp_tcph->source = htons(oldp); 959 | } 960 | icmp_tcph->check = 0; 961 | icmp_tcph->check = csum_tcpudp_magic(icmp_ip4h->saddr, icmp_ip4h->daddr, \ 962 | ntohs(icmp_ip4h->tot_len) - 20, IPPROTO_TCP, \ 963 | csum_partial(payload, ntohs(icmp_ip4h->tot_len-20), 0)); 964 | break; 965 | case IPPROTO_UDP: 966 | icmp_udph = (struct udphdr *)((__u8 *)icmp_ip4h + 20); 967 | if (get_inflow_map_port(&udp_list, ntohs(icmp_udph->source), ntohl(icmp_ip4h->daddr), \ 968 | &oldaddr, &oldp) == -1) { 969 | printk(KERN_ERR "ivi_v6v4_xmit: udp-in-icmp reverse lookup failure.\n"); 970 | 971 | } else { 972 | icmp_ip4h->saddr = ip4h->daddr = htonl(oldaddr); 973 | icmp_udph->source = htons(oldp); 974 | } 975 | icmp_udph->len = htons(ntohs(icmp_ip4h->tot_len) - 20); 976 | icmp_udph->check = 0; 977 | icmp_udph->check = csum_tcpudp_magic(icmp_ip4h->saddr, icmp_ip4h->daddr, \ 978 | ntohs(icmp_ip4h->tot_len) - 20, IPPROTO_UDP, \ 979 | csum_partial(payload, ntohs(icmp_ip4h->tot_len)-20, 0)); 980 | break; 981 | case IPPROTO_ICMPV6: 982 | icmp_ip4h->protocol = IPPROTO_ICMP; 983 | icmp_icmp4h = (struct icmphdr *)((__u8 *)icmp_ip4h + 20); 984 | if (icmp_icmp4h->type == ICMPV6_ECHO_REQUEST || icmp_icmp4h->type == ICMPV6_ECHO_REPLY) { 985 | icmp_icmp4h->type=(icmp_icmp4h->type==ICMPV6_ECHO_REQUEST)?ICMP_ECHO:ICMPV6_ECHO_REPLY; 986 | if (get_inflow_map_port(&icmp_list, ntohs(icmp_icmp4h->un.echo.id), \ 987 | ntohl(icmp_ip4h->daddr), &oldaddr, &oldp) == -1) 988 | printk(KERN_ERR "ivi_v6v4_xmit: echo-in-icmp reverse lookup failure.\n"); 989 | else { 990 | icmp_ip4h->saddr = ip4h->daddr = htonl(oldaddr); 991 | icmp_icmp4h->un.echo.id = htons(oldp); 992 | } 993 | icmp_icmp4h->checksum = 0; 994 | icmp_icmp4h->checksum = ip_compute_csum(icmp_icmp4h, ntohs(icmp_ip4h->tot_len)-20); 995 | } 996 | break; 997 | default: 998 | break; 999 | } 1000 | 1001 | icmp_ip4h->check = ip_fast_csum((__u8 *)icmp_ip4h, icmp_ip4h->ihl); 1002 | icmph->checksum = ip_compute_csum(icmph, ntohs(icmp_ip4h->tot_len) + 8); 1003 | } 1004 | break; 1005 | 1006 | default: 1007 | kfree_skb(newskb); 1008 | return 0; 1009 | } 1010 | ip4h->check = 0; 1011 | ip4h->check = ip_fast_csum((__u8 *)ip4h, ip4h->ihl); 1012 | } 1013 | 1014 | // Prepare to re-enter the protocol stack 1015 | newskb->protocol = eth_type_trans(newskb, skb->dev); 1016 | newskb->ip_summed = CHECKSUM_NONE; 1017 | 1018 | netif_rx(newskb); 1019 | return 0; 1020 | } 1021 | -------------------------------------------------------------------------------- /modules/ivi_xmit.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivi_xmit.h : 4 | * 5 | * This file is the header file for the 'ivi_xmit.c' file. 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Guoliang Han 14 | * Yuncheng Zhu 15 | * Wentao Shang 16 | * 17 | * 18 | * Contributions: 19 | * 20 | * This file is part of MAP-T/MAP-E Kernel Module. 21 | * 22 | * Permission to use, copy, modify, and distribute this software for any 23 | * purpose with or without fee is hereby granted, provided that the above 24 | * copyright notice and this permission notice appear in all copies. 25 | * 26 | * You should have received a copy of the GNU General Public License 27 | * along with MAP-T/MAP-E Kernel Module. If not, see 28 | * . 29 | * 30 | * For more versions, please send an email to to 31 | * obtain an password to access the svn server. 32 | * 33 | * LIC: GPLv2 34 | * 35 | ************************************************************************/ 36 | 37 | 38 | #ifndef IVI_XMIT_H 39 | #define IVI_XMIT_H 40 | 41 | #ifdef __KERNEL__ 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | 59 | #include "ivi_config.h" 60 | #include "ivi_rule.h" 61 | #include "ivi_rule6.h" 62 | #include "ivi_map.h" 63 | #include "ivi_map_tcp.h" 64 | #include "ivi_nf.h" 65 | 66 | extern __be32 v4address; 67 | extern __be32 v4mask; 68 | extern __be32 v4publicaddr; 69 | extern __be32 v4publicmask; 70 | extern __u8 v6prefix[16]; 71 | extern __be32 v6prefixlen; 72 | 73 | extern u8 ivi_mode; 74 | 75 | extern u8 hgw_fmt; 76 | extern u8 hgw_transport; 77 | 78 | extern u16 mss_limit; 79 | 80 | extern int ivi_v4v6_xmit(struct sk_buff *skb); 81 | extern int ivi_v6v4_xmit(struct sk_buff *skb); 82 | extern int ivi_v4_dev(struct net_device *dev); 83 | extern int ivi_v6_dev(struct net_device *dev); 84 | 85 | 86 | #endif /* __KERNEL__ */ 87 | #endif /* IVI_XMIT_H */ 88 | -------------------------------------------------------------------------------- /radvd.conf: -------------------------------------------------------------------------------- 1 | # NOTE: there is no such thing as a working "by-default" configuration file. 2 | # At least the prefix needs to be specified. Please consult the radvd.conf(5) 3 | # man page and/or /usr/share/doc/radvd-*/radvd.conf.example for help. 4 | # 5 | # 6 | interface eth1 7 | { 8 | AdvSendAdvert on; 9 | MinRtrAdvInterval 30; 10 | MaxRtrAdvInterval 100; 11 | prefix 2001:da8:b001:2000::/64 12 | { 13 | AdvOnLink on; 14 | AdvAutonomous on; 15 | AdvRouterAddr off; 16 | }; 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /readme: -------------------------------------------------------------------------------- 1 | MAP-T/MAP-E Module Installation And Usage Manual 2 | 3 | Notice: This code package currently supports the translation 4 | of TCP, UDP and ICMP Query packets with two working modes: CE, 5 | CE with NAT44. Anyone may contribute to add more 6 | functionalities to this code under the license of GPL. 7 | 8 | Part I: building binaries from source 9 | 10 | To build the source codes, follow the steps below: 11 | 12 | 1) Enter './modules/' directory; 13 | 2) Run 'make' command to build kernel modules; 14 | 3) Switch to './utils/' directory; 15 | 4) Run 'make' command to build 'ivictl' command line utility; 16 | 17 | Part II: install & remove the module 18 | 19 | Currently the MAP-T/MAP-E module does not need special installation steps. It 20 | is suggested that you directly start the module using shell scripts located in 21 | './scripts/' directory. Those scripts will install and start the module 22 | automatically. You may copy or move those scripts to other locations but pay 23 | attention to the relative directory references in the scripts. 24 | 25 | The module installation is actually performed by the script command 'control 26 | start', which will call 'insmod' to insert the kernel module 'ivi.ko' and then 27 | call 'mknod' to create a charactor device interface in '/dev' directory for 28 | IOCTL purpose. 29 | 30 | The module is removed by the script command 'control stop', which will call 31 | 'rmmod' to remove the kernel module 'ivi.ko' and then call 'rm' to remove the 32 | charactor device interface from the '/dev' directory. 33 | 34 | The module start and stop is performed by calling 'ivictl' command. See Part 35 | III for the usage of 'ivictl' tool. 36 | 37 | 38 | Part III: 'ivictl' usage 39 | 40 | The MAP-T/MAP-E functionality is controlled via 'ivictl' utility. This command 41 | line tool allows you to configure mapping rules (through 'ivictl -r ...' 42 | command), start (through 'ivictl -s ...' command) or stop (through 'ivictl -q' 43 | command) packet translation. You can also view the usage instructions through 44 | 'ivictl -h' command. 45 | 46 | 1) Configure mapping rule 47 | 48 | To configure a mapping rule, the following options are used: 49 | 50 | -p: specify the IPv4 rule prefix and prefix length in the form of 'a.b.c.d/l' 51 | -d: specify the default mapping rule, either '-p' or '-d' must be specified 52 | -P: specify the corresponding IPv6 rule prefix and prefix length in the form of 53 | 'a:b:c:d::/l', must be specified 54 | -z: specify the psid offset, default value is 6. 55 | -R: specify the associated IPv4 address sharing ratio R used in GMA, default 56 | value is 1 57 | -T translation(MAP-T) 58 | -E encapsulation(MAP-E) 59 | 60 | For example, a mapping rule '1.1.1.0/24 -> 2001:da8:abc::/48, R = 16, PSID offset = 4' is 61 | configured via: 62 | 63 | ivictl -r -p 1.1.1.0/24 -P 2001:da8:abc::/48 -z 4 -R 16 -T 64 | 65 | 66 | 2) Start packet translation 67 | 68 | The MAP module support two working mode: CE mode and CE 69 | with NAT44 mode, both for translation and encpasulation 70 | 71 | To start the module in BR mode, the following options are used: 72 | 73 | -i: specify the name of the Ethernet device connected to IPv4 world 74 | -I: specify the name of the Ethernet device connected to IPv6 world 75 | 76 | Remember that you MUST configure correct mapping rules before starting BR mode. 77 | At least two mapping rules (the DMR and the BMR) are necessary. 78 | 79 | 80 | To start the module in CE mode, the following options are required: 81 | 82 | -i: specify the name of the Ethernet device connected to IPv4 world 83 | -I: specify the name of the Ethernet device connected to IPv6 world 84 | -H: specify that we are in HGW mode 85 | -a: specify the IPv4 address and mask of the host behind the CE device, in the 86 | form of 'a.b.c.d/l' 87 | -P: specify the IPv6 rule prefix and prefix length of the host behind the CE 88 | device, in the form of 'a:b:c:d::/l' 89 | -R: specify the associated IPv4 address sharing ratio R of the host behind the 90 | CE device 91 | -z: specify the psid offset 92 | -o: specify the PSID of the host behind the CE device 93 | -T: translation (MAP-T) 94 | -E: encapsulation (MAP-E) 95 | -c: MSS clamping to avoid the MTU problem along the path. 96 | 97 | 98 | Remember that you MUST configure the DMR before starting CE mode. 99 | 100 | 101 | To start the module in CE with NAT44 mode, the additional necessary options are 102 | as follows: 103 | 104 | -A: specify the public IPv4 address and mask which the host behind the CE 105 | device is mapped into. In this case, the '-a' option will specify the 106 | private IPv4 network and prefix length 107 | -N: specify that we are in NAT44 mode 108 | 109 | 110 | './scripts/' directory contains real configuration examples for these working 111 | modes. 112 | 113 | 3) Stop packet translation 114 | 115 | This is easy. Simply run 'ivictl -q' command. 116 | 117 | 118 | If you have any question regarding the usage of the source code and the MAP-T/MAP-E 119 | module, feel free to contact the authors via email. 120 | 121 | -------------------------------------------------------------------------------- /stopall: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | utils/ivictl -q 4 | 5 | ./control stop 6 | -------------------------------------------------------------------------------- /utils/Makefile: -------------------------------------------------------------------------------- 1 | all: ivictl.c ../modules/ivi_ioctl.h 2 | $(CC) -o ivictl ivictl.c 3 | 4 | clean: 5 | rm -rf ivictl 6 | -------------------------------------------------------------------------------- /utils/ivictl.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * 3 | * ivictl.c : 4 | * 5 | * MAP-T/MAP-E CPE Userspace Controller Utility 6 | * 7 | * Copyright (C) 2013 CERNET Network Center 8 | * All rights reserved. 9 | * 10 | * Design and coding: 11 | * Xing Li 12 | * Congxiao Bao 13 | * Yuncheng Zhu 14 | * Wentao Shang 15 | * Guoliang Han 16 | * 17 | * Contributions: 18 | * 19 | * Permission to use, copy, modify, and distribute this software for any 20 | * purpose with or without fee is hereby granted, provided that the above 21 | * copyright notice and this permission notice appear in all copies. 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with MAP-T/MAP-E Kernel Module. If not, see 25 | * . 26 | * 27 | * For more versions, please send an email to to 28 | * obtain an password to access the svn server. 29 | * 30 | * LIC: GPLv2 31 | * 32 | ************************************************************************/ 33 | 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "../modules/ivi_ioctl.h" 44 | 45 | static const struct option longopts[] = 46 | { 47 | {"rule", no_argument, NULL, 'r'}, 48 | {"start", no_argument, NULL, 's'}, 49 | {"stop", required_argument, NULL, 'q'}, 50 | {"help", no_argument, NULL, 'h'}, 51 | {"hgw", no_argument, NULL, 'H'}, 52 | {"nat44", no_argument, NULL, 'N'}, 53 | {"noeabits", no_argument, NULL, 'X'}, 54 | {"default", no_argument, NULL, 'd'}, 55 | {"prefix4", required_argument, NULL, 'p'}, 56 | {"prefix6", required_argument, NULL, 'P'}, 57 | {"ratio", required_argument, NULL, 'R'}, 58 | {"psidoffset", required_argument, NULL, 'z'}, 59 | {"encapsulate", required_argument, NULL, 'E'}, 60 | {"translate", required_argument, NULL, 'T'}, 61 | {"psid", required_argument, NULL, 'o'}, 62 | {"address", required_argument, NULL, 'a'}, 63 | {"publicaddr", required_argument, NULL, 'A'}, 64 | {"dev4", required_argument, NULL, 'i'}, 65 | {"dev6", required_argument, NULL, 'I'}, 66 | {"mssclamping", required_argument, NULL, 'c'}, 67 | {NULL, no_argument, NULL, 0} 68 | }; 69 | 70 | 71 | static char hgw; 72 | static char nat44; 73 | static char xeabits; 74 | static char transpt; 75 | static char psidoff; 76 | static char dev[IVI_IOCTL_LEN]; 77 | static __u16 gma[2]; // Store R and PSID, M is stored in 'rule.adjacent' 78 | static __u16 mss_val; 79 | static struct in_addr v4addr; 80 | static struct rule_info rule; 81 | 82 | int ffs(int x) 83 | { 84 | int r = 1; 85 | 86 | if (!x) 87 | return 0; 88 | if (!(x & 0xffff)) { 89 | x >>= 16; 90 | r += 16; 91 | } 92 | if (!(x & 0xff)) { 93 | x >>= 8; 94 | r += 8; 95 | } 96 | if (!(x & 0xf)) { 97 | x >>= 4; 98 | r += 4; 99 | } 100 | if (!(x & 3)) { 101 | x >>= 2; 102 | r += 2; 103 | } 104 | if (!(x & 1)) { 105 | x >>= 1; 106 | r += 1; 107 | } 108 | return r; 109 | } 110 | 111 | int fls(int x) 112 | { 113 | int r = 32; 114 | 115 | if (!x) 116 | return 0; 117 | if (!(x & 0xffff0000u)) { 118 | x <<= 16; 119 | r -= 16; 120 | } 121 | if (!(x & 0xff000000u)) { 122 | x <<= 8; 123 | r -= 8; 124 | } 125 | if (!(x & 0xf0000000u)) { 126 | x <<= 4; 127 | r -= 4; 128 | } 129 | if (!(x & 0xc0000000u)) { 130 | x <<= 2; 131 | r -= 2; 132 | } 133 | if (!(x & 0x80000000u)) { 134 | x <<= 1; 135 | r -= 1; 136 | } 137 | return r; 138 | } 139 | 140 | void usage(int status) { 141 | if (status != EXIT_SUCCESS) 142 | printf("Try `ivictl --help' for more information.\n"); 143 | else { 144 | printf("\ 145 | Usage: ivictl -r [rule_options]\n\ 146 | (used to insert a mapping rule)\n\ 147 | ivictl -s [start_options]\n\ 148 | (used to start MAP module)\n\ 149 | ivictl -q\n\ 150 | (used to stop MAP module)\n\ 151 | ivictl -h\n\ 152 | (used to display this help information)\n\ 153 | \n\ 154 | rule_options:\n\ 155 | -p --prefix4 [PREFIX4/PLEN4]\n\ 156 | specify the ipv4 prefix and length\n\ 157 | -P --prefix6 [PREFIX6/PLEN6]\n\ 158 | specify the ipv6 prefix and length\n\ 159 | -z --psidoffset PSIDOFFSET\n\ 160 | specify the psid offset parameter in GMA\n\ 161 | -R --ratio RATIO\n\ 162 | specify the address sharing ratio in GMA\n\ 163 | -d --default\n\ 164 | specify the ipv4 prefix is '0.0.0.0/0' instead of using '-p 0.0.0.0 -l 0'\n\ 165 | -E --encapsulate\n\ 166 | specify the mapping rule is used for MAP-E\n\ 167 | -T --translate\n\ 168 | specify the mapping rule is used for MAP-T\n\ 169 | \n\ 170 | start_options:\n\ 171 | -i --dev4 DEV4\n\ 172 | specify the name of ipv4 device\n\ 173 | -I --dev6 DEV6\n\ 174 | specify the name of ipv6 device\n\ 175 | -c --mssclamping MSS\n\ 176 | specify the reduced tcp mss value\n\ 177 | \n\ 178 | HGW mode:\n\ 179 | -H --hgw\n\ 180 | specify that IVI is working as home gateway\n\ 181 | -N --nat44\n\ 182 | specify that IVI HGW is performing NAT44\n\ 183 | -o --psid PSID\n\ 184 | specify the local PSID of the HGW, default is 0\n\ 185 | -a --address [ADDRRESS/PREFIXLENGTH]\n\ 186 | specify the ipv4 address and mask used by the HGW\n\ 187 | -A --publicaddr [PUBLICADDR/PUBLICPREFIXLENGTH]\n\ 188 | specify the public ipv4 address and mask used by the HGW in NAT44 mode\n\ 189 | always used with -N (--nat44)\n\ 190 | -P --prefix6 [PREFIX6/PLEN6]\n\ 191 | specify the local IVI prefix and length used by the HGW\n\ 192 | -z --psidoffset PSIDOFFSET\n\ 193 | specify the local psid offset parameter in GMA\n\ 194 | -R --ratio RATIO\n\ 195 | specify the local address sharing ratio in GMA\n\ 196 | -X --noeabits\n\ 197 | specify that the HGW doesn't use eabits to constitute the IPv6 address\n\ 198 | -E --encapsulate\n\ 199 | specify that the HGW supports MAP-E mode\n\ 200 | -T --translate\n\ 201 | specify that the HGW supports MAP-T\n\ 202 | \n"); 203 | } 204 | exit(status); 205 | } 206 | 207 | static inline void param_init(void) { 208 | hgw = 0; 209 | nat44 = 0; 210 | xeabits = 0; 211 | psidoff = 6; // default PSID offset value 212 | transpt = MAP_T; 213 | gma[0] = gma[1] = 0; 214 | memset(&rule, 0, sizeof(rule)); 215 | rule.ratio = 1; 216 | rule.adjacent = 1; 217 | rule.format = ADDR_FMT_MAPT; 218 | rule.transport = MAP_T; 219 | } 220 | 221 | int main(int argc, char *argv[]) { 222 | int retval, fd, temp, optc; 223 | char *token = NULL; 224 | 225 | printf("MAP netfilter device controller utility v1.0\n"); 226 | 227 | if ((fd = open("/dev/ivi", 0)) < 0) { 228 | printf("\nError*****: cannot open virtual device for ioctl, code %d.\n\n", fd); 229 | exit(-1); 230 | } 231 | 232 | param_init(); 233 | 234 | optc = getopt_long(argc, argv, "rsqh", longopts, NULL); 235 | switch (optc) 236 | { 237 | case 'r': 238 | goto rule_opt; 239 | break; 240 | case 's': 241 | goto start_opt; 242 | break; 243 | case 'q': 244 | if ((retval = ioctl(fd, IVI_IOC_STOP, 0)) != 0) { 245 | printf("\nError*****: failed to stop MAP module, code %d.\n\n", retval); 246 | } 247 | else { 248 | printf("Info: successfully stopped MAP module.\n"); 249 | } 250 | goto out; 251 | break; 252 | case 'h': 253 | close(fd); 254 | usage(EXIT_SUCCESS); 255 | break; 256 | default: 257 | close(fd); 258 | usage(EXIT_FAILURE); 259 | break; 260 | } 261 | 262 | rule_opt: 263 | while ((optc = getopt_long(argc, argv, "p:P:R:z:fdET", longopts, NULL)) != -1) 264 | { 265 | switch(optc) 266 | { 267 | case 'd': 268 | rule.prefix4 = 0; 269 | rule.plen4 = 0; 270 | rule.format = ADDR_FMT_NONE; 271 | break; 272 | 273 | case 'p': 274 | // Extract IPv4 address 275 | token = strtok(optarg, "/"); 276 | if (token == NULL) { 277 | retval = -1; 278 | goto out; 279 | } 280 | if ((retval = inet_pton(AF_INET, token, (void*)(&(rule.prefix4)))) != 1) { 281 | printf("\nError*****: failed to parse IPv4 address, code %d.\n\n", retval); 282 | retval = -1; 283 | goto out; 284 | } 285 | rule.prefix4 = ntohl(rule.prefix4); // Convert to host byte order 286 | 287 | // Extract address prefix length 288 | token = strtok(NULL, "/"); 289 | if (token == NULL) { 290 | retval = -1; 291 | goto out; 292 | } 293 | rule.plen4 = atoi(token); 294 | if (rule.plen4 > 32 || rule.plen4 < 0) { 295 | printf("\nError*****: IPv4 prefix length is out of scope.\n\n"); 296 | usage(EXIT_FAILURE); 297 | retval = -1; 298 | goto out; 299 | } 300 | break; 301 | case 'P': 302 | // Extract IPv6 address 303 | token = strtok(optarg, "/"); 304 | if (token == NULL) { 305 | retval = -1; 306 | goto out; 307 | } 308 | if ((retval = inet_pton(AF_INET6, token, (void*)(&(rule.prefix6)))) != 1) { 309 | printf("\nError*****: failed to parse IPv6 prefix, code %d.\n\n", retval); 310 | retval = -1; 311 | goto out; 312 | } 313 | 314 | // Extract address prefix length 315 | token = strtok(NULL, "/"); 316 | if (token == NULL) { 317 | retval = -1; 318 | goto out; 319 | } 320 | rule.plen6 = atoi(token); 321 | if (rule.plen6 > 128 || rule.plen6 < 0) { 322 | printf("\nError*****: IPv6 prefix length is out of scope.\n\n"); 323 | usage(EXIT_FAILURE); 324 | retval = -1; 325 | goto out; 326 | } 327 | break; 328 | case 'R': 329 | rule.ratio = atoi(optarg); 330 | if (fls(rule.ratio) != ffs(rule.ratio)) { 331 | printf("\nError*****: Ratio must be a power of two.\n\n"); 332 | usage(EXIT_FAILURE); 333 | retval = -1; 334 | goto out; 335 | } 336 | break; 337 | case 'z': 338 | psidoff = atoi(optarg); 339 | if (psidoff > 16 || psidoff < 0) { 340 | printf("\nError*****: psid offset is out of scope.\n\n"); 341 | usage(EXIT_FAILURE); 342 | retval = -1; 343 | goto out; 344 | } 345 | break; 346 | case 'E': 347 | rule.transport = MAP_E; 348 | break; 349 | case 'T': 350 | rule.transport = MAP_T; 351 | break; 352 | default: 353 | close(fd); 354 | usage(EXIT_FAILURE); 355 | break; 356 | } 357 | } 358 | 359 | if (rule.prefix4 > 0) { 360 | if (psidoff + fls(rule.ratio) - 1 > 16) { 361 | printf("\nError*****: PSID offset + PSID length must be no more than 16 bits.\n\n"); 362 | usage(EXIT_FAILURE); 363 | retval = -1; 364 | goto out; 365 | } 366 | 367 | rule.adjacent = 1 << (16 - psidoff - (fls(rule.ratio) - 1)); 368 | 369 | // Finalize 370 | temp = (rule.plen4 == 0) ? 0 : 0xffffffff << (32 - rule.plen4); // Generate network mask 371 | rule.prefix4 = rule.prefix4 & temp; 372 | } 373 | 374 | // Insert rule 375 | if ((retval = ioctl(fd, IVI_IOC_ADD_RULE, &rule)) < 0) { 376 | printf("\nError*****: failed to add mapping rule, code %d.\n\n", retval); 377 | usage(EXIT_FAILURE); 378 | } else { 379 | printf("Info: successfully add mapping rule.\n"); 380 | } 381 | 382 | goto out; 383 | 384 | start_opt: 385 | while ((optc = getopt_long(argc, argv, "i:I:A:a:P:R:z:o:fc:HNXET", longopts, NULL)) != -1) 386 | { 387 | switch(optc) 388 | { 389 | case 'i': 390 | strncpy(dev, optarg, IVI_IOCTL_LEN); 391 | if ((retval = ioctl(fd, IVI_IOC_V4DEV, dev)) < 0) { 392 | printf("\nError*****: failed to assign IPv4 device, code %d.\n\n", retval); 393 | goto out; 394 | } 395 | break; 396 | case 'I': 397 | strncpy(dev, optarg, IVI_IOCTL_LEN); 398 | if ((retval = ioctl(fd, IVI_IOC_V6DEV, dev)) < 0) { 399 | printf("\nError*****: failed to assign IPv6 device, code %d.\n\n", retval); 400 | goto out; 401 | } 402 | break; 403 | case 'c': 404 | mss_val = atoi(optarg); 405 | if ((retval = ioctl(fd, IVI_IOC_MSS_LIMIT, (void*)(&mss_val))) < 0) { 406 | printf("\nError*****: failed to set mssclamping, code %d.\n\n", retval); 407 | goto out; 408 | } 409 | break; 410 | case 'H': 411 | hgw = 1; 412 | break; 413 | case 'a': 414 | // Extract IPv4 address 415 | token = strtok(optarg, "/"); 416 | if (token == NULL) { 417 | retval = -1; 418 | goto out; 419 | } 420 | if ((retval = inet_pton(AF_INET, token, (void*)(&(rule.prefix4)))) != 1) { 421 | printf("\nError*****: failed to parse IPv4 address, code %d.\n\n", retval); 422 | retval = -1; 423 | goto out; 424 | } 425 | rule.prefix4 = ntohl(rule.prefix4); // Convert to host byte order 426 | if ((retval = ioctl(fd, IVI_IOC_V4NET, &(rule.prefix4))) < 0) { 427 | printf("\nError*****: failed to assign IPv4 address, code %d.\n\n", retval); 428 | goto out; 429 | } 430 | 431 | // Extract address prefix length 432 | token = strtok(NULL, "/"); 433 | if (token == NULL) { 434 | retval = -1; 435 | goto out; 436 | } 437 | rule.plen4 = atoi(token); 438 | if (rule.plen4 > 32 || rule.plen4 < 0) { 439 | printf("\nError*****: IPv4 prefix length is out of scope.\n\n"); 440 | usage(EXIT_FAILURE); 441 | retval = -1; 442 | goto out; 443 | } 444 | temp = (rule.plen4 == 0) ? 0 : 0xffffffff << (32 - rule.plen4); // Generate network mask 445 | if ((retval = ioctl(fd, IVI_IOC_V4MASK, &(temp))) < 0) { 446 | printf("\nError*****: failed to assign IPv4 address prefix length, code %d.\n\n", retval); 447 | goto out; 448 | } 449 | 450 | break; 451 | case 'N': 452 | nat44 = 1; 453 | break; 454 | case 'A': 455 | // Extract IPv4 address 456 | token = strtok(optarg, "/"); 457 | if (token == NULL) { 458 | retval = -1; 459 | goto out; 460 | } 461 | if ((retval = inet_pton(AF_INET, token, (void*)(&v4addr))) != 1) { 462 | printf("\nError*****: failed to parse IPv4 public address, code %d.\n\n", retval); 463 | retval = -1; 464 | goto out; 465 | } 466 | v4addr.s_addr = ntohl(v4addr.s_addr); 467 | if ((retval = ioctl(fd, IVI_IOC_V4PUB, &(v4addr.s_addr))) < 0) { 468 | printf("\nError*****: failed to assign IPv4 public address, code %d.\n\n", retval); 469 | goto out; 470 | } 471 | 472 | // Extract address prefix length 473 | token = strtok(NULL, "/"); 474 | if (token == NULL) { 475 | retval = -1; 476 | goto out; 477 | } 478 | rule.plen4 = atoi(token); 479 | if (rule.plen4 > 32 || rule.plen4 < 0) { 480 | printf("\nError*****: IPv4 prefix length is out of scope.\n\n"); 481 | usage(EXIT_FAILURE); 482 | retval = -1; 483 | goto out; 484 | } 485 | temp = (rule.plen4 == 0) ? 0 : 0xffffffff << (32 - rule.plen4); // Generate network mask 486 | if ((retval = ioctl(fd, IVI_IOC_V4PUBMASK, &(temp))) < 0) { 487 | printf("\nError*****: failed to assign IPv4 public address prefix length, code %d.\n\n", retval); 488 | goto out; 489 | } 490 | 491 | nat44 = 1; // Done.:) 492 | break; 493 | case 'P': 494 | // Extract IPv6 address 495 | token = strtok(optarg, "/"); 496 | if (token == NULL) { 497 | retval = -1; 498 | goto out; 499 | } 500 | if ((retval = inet_pton(AF_INET6, token, (void*)(&(rule.prefix6)))) != 1) { 501 | printf("\nError*****: failed to parse IPv6 prefix, code %d.\n\n", retval); 502 | retval = -1; 503 | goto out; 504 | } 505 | if ((retval = ioctl(fd, IVI_IOC_V6NET, &(rule.prefix6))) < 0) { 506 | printf("\nError*****: failed to assign IPv6 prefix, code %d.\n\n", retval); 507 | goto out; 508 | } 509 | 510 | // Extract address prefix length 511 | token = strtok(NULL, "/"); 512 | if (token == NULL) { 513 | retval = -1; 514 | goto out; 515 | } 516 | rule.plen6 = atoi(token); 517 | if (rule.plen6 > 128 || rule.plen6 < 0) { 518 | printf("\nError*****: IPv6 prefix length is out of scope.\n\n"); 519 | usage(EXIT_FAILURE); 520 | retval = -1; 521 | goto out; 522 | } 523 | temp = rule.plen6; // counted in bits 524 | if ((retval = ioctl(fd, IVI_IOC_V6MASK, &(temp))) < 0) { 525 | printf("\nError*****: failed to assign IPv6 prefix length, code %d.\n\n", retval); 526 | goto out; 527 | } 528 | break; 529 | 530 | case 'X': 531 | xeabits = 1; 532 | break; 533 | case 'R': 534 | gma[0] = rule.ratio = atoi(optarg); 535 | if (fls(rule.ratio) != ffs(rule.ratio)) { 536 | printf("\nError*****: Ratio must be a power of two.\n\n"); 537 | usage(EXIT_FAILURE); 538 | retval = -1; 539 | goto out; 540 | } 541 | break; 542 | case 'z': 543 | psidoff = atoi(optarg); 544 | if (psidoff > 16 || psidoff < 0) { 545 | printf("\nError*****: psid offset is out of scope.\n\n"); 546 | usage(EXIT_FAILURE); 547 | retval = -1; 548 | goto out; 549 | } 550 | break; 551 | case 'o': 552 | gma[1] = atoi(optarg); 553 | break; 554 | case 'E': 555 | transpt = MAP_E; 556 | break; 557 | case 'T': 558 | transpt = MAP_T; 559 | break; 560 | default: 561 | close(fd); 562 | usage(EXIT_FAILURE); 563 | break; 564 | } 565 | } 566 | 567 | if (psidoff + fls(rule.ratio) - 1 > 16) { 568 | printf("\nError*****: PSID offset + PSID length must be no more than 16 bits.\n\n"); 569 | usage(EXIT_FAILURE); 570 | retval = -1; 571 | goto out; 572 | } 573 | 574 | rule.adjacent = 1 << (16 - psidoff - (fls(rule.ratio) - 1)); 575 | 576 | if (gma[1] >= rule.ratio || gma[1] < 0) { 577 | printf("\nError*****: PSID must be less than ratio.\n\n"); 578 | usage(EXIT_FAILURE); 579 | retval = -1; 580 | goto out; 581 | } 582 | 583 | // Set local addr format for HGW mode 584 | if (hgw) { 585 | if (rule.format == ADDR_FMT_MAPT) { 586 | if ((retval = ioctl(fd, IVI_IOC_MAPT, gma)) < 0) { 587 | printf("\nError*****: failed to set addr format, code %d.\n\n", retval); 588 | goto out; 589 | } 590 | if ((retval = ioctl(fd, IVI_IOC_ADJACENT, (void*)(&rule.adjacent))) < 0) { 591 | printf("\nError*****: failed to set adjacent parameter, code %d.\n\n", retval); 592 | goto out; 593 | } 594 | } 595 | 596 | if ((retval = ioctl(fd, IVI_IOC_TRANSPT, &transpt)) < 0) { 597 | printf("\nError*****: failed to set MAP transport, code %d.\n\n", retval); 598 | goto out; 599 | } 600 | 601 | printf("Info: successfully set HGW parameters.\n"); 602 | } 603 | 604 | // Start IVI 605 | if (hgw && !nat44 && !xeabits) { 606 | if ((retval = ioctl(fd, IVI_IOC_NONAT, 0)) < 0) { 607 | printf("\nError*****: failed to disable nat44, code %d.\n\n", retval); 608 | goto out; 609 | } 610 | if ((retval = ioctl(fd, IVI_IOC_START, 0)) < 0) { 611 | printf("\nError*****: failed to start MAP module, code %d.\n\n", retval); 612 | goto out; 613 | } 614 | } else if (hgw && nat44 && !xeabits) { 615 | if ((retval = ioctl(fd, IVI_IOC_NAT, 0)) < 0) { 616 | printf("\nError*****: failed to enable nat44, code %d.\n\n", retval); 617 | goto out; 618 | } 619 | if ((retval = ioctl(fd, IVI_IOC_START, 0)) < 0) { 620 | printf("\nError*****: failed to start MAP module, code %d.\n\n", retval); 621 | goto out; 622 | } 623 | } else if (hgw && nat44 && xeabits) { // no eabits 624 | if ((retval = ioctl(fd, IVI_IOC_NAT, 0)) < 0) { 625 | printf("\nError*****: failed to enable nat44, code %d.\n\n", retval); 626 | goto out; 627 | } 628 | if ((retval = ioctl(fd, IVI_IOC_HGW_MAPX, 0)) < 0) { 629 | printf("\nError*****: failed to enable no eabits format, code %d.\n\n", retval); 630 | goto out; 631 | } 632 | if ((retval = ioctl(fd, IVI_IOC_START, 0)) < 0) { 633 | printf("\nError*****: failed to start MAP module, code %d.\n\n", retval); 634 | goto out; 635 | } 636 | } else if (hgw && !nat44 && xeabits) { // no eabits 637 | if ((retval = ioctl(fd, IVI_IOC_NONAT, 0)) < 0) { 638 | printf("\nError*****: failed to enable nat44, code %d.\n\n", retval); 639 | goto out; 640 | } 641 | if ((retval = ioctl(fd, IVI_IOC_HGW_MAPX, 0)) < 0) { 642 | printf("\nError*****: failed to enable no eabits format, code %d.\n\n", retval); 643 | goto out; 644 | } 645 | if ((retval = ioctl(fd, IVI_IOC_START, 0)) < 0) { 646 | printf("\nError*****: failed to start MAP module, code %d.\n\n", retval); 647 | goto out; 648 | } 649 | } 650 | else { 651 | close(fd); 652 | usage(EXIT_FAILURE); 653 | } 654 | 655 | printf("Info: successfully started MAP module.\n"); 656 | 657 | out: 658 | close(fd); 659 | return retval; 660 | } 661 | -------------------------------------------------------------------------------- /zxhgw-addr: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # configure system profile 4 | echo 1 > /proc/sys/net/ipv4/ip_forward 5 | echo 1 > /proc/sys/net/ipv6/conf/all/forwarding 6 | echo 0 > /proc/sys/net/ipv6/conf/eth0/autoconf 7 | echo 0 > /proc/sys/net/ipv6/conf/eth1/autoconf 8 | echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter 9 | echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter 10 | 11 | # configure eth0 -- IPv6 interface 12 | #ifconfig eth0 down 13 | #ifconfig eth0 up 14 | ip -6 addr add 2001:da8:aaaf:1000::2/64 dev eth0 15 | ip -6 route add default via 2001:da8:aaaf:1000::1 dev eth0 16 | 17 | # configure eth1 -- IPv4 interface 18 | #ifconfig eth1 down 19 | #ifconfig eth1 up 20 | #ifconfig eth1 192.168.1.1/24 21 | ip route add default dev eth1 22 | ifconfig eth1 202.38.102.129/30 23 | ip -6 addr add 2001:da8:b001:2000::1/64 dev eth1 24 | 25 | dhcpd -cf /etc/dhcpd.conf 26 | radvd 27 | /etc/init.d/dnsmasq start 28 | 29 | service iptables stop 30 | service ip6tables stop 31 | -------------------------------------------------------------------------------- /zyhgw-E: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./control start 4 | utils/ivictl -r -d -P 2001:da8:b001:ffff::/64 -E 5 | utils/ivictl -s -i eth1 -I eth0 -H -a 202.38.102.130/28 -P 2001:da8:b001::/48 -z 4 -R 16 -o 0 -c 1400 -E 6 | 7 | -------------------------------------------------------------------------------- /zyhgw-E44: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./control start 4 | utils/ivictl -r -d -P 2001:da8:b001:ffff::/64 -E 5 | utils/ivictl -r -p 166.111.132.0/24 -P 2001:da8:5678::/48 -z 4 -R 16 -E 6 | utils/ivictl -s -i eth1 -I eth0 -H -a 192.168.1.1/24 -A 202.38.102.130/28 -P 2001:da8:b001::/48 -z 4 -R 16 -o 1 -c 1400 -E 7 | -------------------------------------------------------------------------------- /zyhgw-T: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./control start 4 | utils/ivictl -r -d -P 2001:da8:b001:ffff::/64 -T 5 | utils/ivictl -s -i eth1 -I eth0 -H -a 202.38.102.130/28 -P 2001:da8:b001::/48 -z 4 -R 16 -o 0 -c 1400 -T 6 | 7 | -------------------------------------------------------------------------------- /zyhgw-T44: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./control start 4 | utils/ivictl -r -d -P 2001:da8:b001:ffff::/64 -T 5 | utils/ivictl -r -p 166.111.132.0/24 -P 2001:da8:5678::/48 -z 4 -R 16 -T 6 | utils/ivictl -s -i eth1 -I eth0 -H -a 192.168.1.1/24 -A 202.38.102.130/28 -P 2001:da8:b001::/48 -z 4 -R 16 -o 1 -c 1400 -T 7 | --------------------------------------------------------------------------------