This commit is contained in:
hathach 2014-03-26 16:06:46 +07:00
parent 7320d22041
commit abc6b58063
159 changed files with 209 additions and 67562 deletions

View File

@ -111,28 +111,6 @@ void board_init(void)
//------------- NAND Flash (K9FXX) Size = 128M, Page Size = 2K, Block Size = 128K, Number of Block = 1024 -------------//
// nand_init();
#if 0
//------------- Ethernet -------------//
LPC_CREG->CREG6 &= ~0x7;
/* RMII mode setup only */
LPC_CREG->CREG6 |= 0x4;
scu_pinmux(0x1, 18, (MD_EHS | MD_PLN | MD_ZI) , FUNC3); // ENET TXD0
scu_pinmux(0x1, 20, (MD_EHS | MD_PLN | MD_ZI) , FUNC3); // ENET TXD1
scu_pinmux(0x0, 1 , (MD_EHS | MD_PLN | MD_ZI) , FUNC6); // ENET TX Enable
scu_pinmux(0x1, 15, (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET RXD0
scu_pinmux(0x0, 0 , (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC2); // ENET RXD1
scu_pinmux(0x1, 16, (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC7); // ENET RX Data Valid
scu_pinmux(0x1, 19, (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC0); // ENET REF CLK
scu_pinmux(0x1, 17, (MD_EHS | MD_PLN | MD_EZI | MD_ZI), FUNC3); // ENET MDIO
scu_pinmux(0xC, 1 , (MD_EHS | MD_PLN | MD_ZI) , FUNC3); // ENET MDC
#endif
}
//--------------------------------------------------------------------+

View File

@ -75,7 +75,7 @@
</option>
<option id="gnu.c.link.option.libs.1088600788" name="Libraries (-l)" superClass="gnu.c.link.option.libs"/>
<option id="gnu.c.link.option.paths.1352371726" name="Library search path (-L)" superClass="gnu.c.link.option.paths"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1912639139" name="Use C library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1912639139" name="Library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<option id="com.crt.advproject.link.fpu.1071054814" name="Floating point" superClass="com.crt.advproject.link.fpu" value="com.crt.advproject.link.fpu.fpv4" valueType="enumerated"/>
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.1768732506" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
@ -175,7 +175,7 @@
<option id="gnu.c.link.option.paths.916077707" name="Library search path (-L)" superClass="gnu.c.link.option.paths" valueType="libPaths">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/cmsis_rtos_rtx/LIB/GCC}&quot;"/>
</option>
<option id="com.crt.advproject.link.gcc.hdrlib.1015545513" name="Use C library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.nohost" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1015545513" name="Library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.nohost" valueType="enumerated"/>
<option id="com.crt.advproject.link.fpu.834301167" name="Floating point" superClass="com.crt.advproject.link.fpu" value="com.crt.advproject.link.fpu.fpv4.hard" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.multicore.slave.1674664189" name="Multicore slave" superClass="com.crt.advproject.link.gcc.multicore.slave"/>
<option id="com.crt.advproject.link.gcc.multicore.master.413285924" name="Multicore" superClass="com.crt.advproject.link.gcc.multicore.master"/>
@ -277,7 +277,7 @@
<option id="gnu.c.link.option.paths.1185436199" name="Library search path (-L)" superClass="gnu.c.link.option.paths" valueType="libPaths">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/cmsis_rtos_rtx/LIB/GCC}&quot;"/>
</option>
<option id="com.crt.advproject.link.gcc.hdrlib.1376822718" name="Use C library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.nohost" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1376822718" name="Library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.nohost" valueType="enumerated"/>
<option id="com.crt.advproject.link.fpu.1096421602" name="Floating point" superClass="com.crt.advproject.link.fpu" value="com.crt.advproject.link.fpu.none" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.multicore.slave.1605384275" name="Multicore slave" superClass="com.crt.advproject.link.gcc.multicore.slave"/>
<option id="com.crt.advproject.link.gcc.multicore.master.122348860" name="Multicore" superClass="com.crt.advproject.link.gcc.multicore.master"/>
@ -366,7 +366,7 @@
<tool command="arm-none-eabi-gcc" commandLinePattern="${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}" errorParsers="org.eclipse.cdt.core.GLDErrorParser" id="com.crt.advproject.link.exe.debug.1504055209" name="MCU Linker" superClass="com.crt.advproject.link.exe.debug">
<option id="com.crt.advproject.link.arch.1071981976" name="Architecture" superClass="com.crt.advproject.link.arch" value="com.crt.advproject.link.target.cm4" valueType="enumerated"/>
<option id="com.crt.advproject.link.thumb.1280965025" name="Thumb mode" superClass="com.crt.advproject.link.thumb" value="true" valueType="boolean"/>
<option id="com.crt.advproject.link.script.1619199675" name="Linker script" superClass="com.crt.advproject.link.script" value="&quot;host_cmsis_rtx_Board_EA4357.ld&quot;" valueType="string"/>
<option id="com.crt.advproject.link.script.1619199675" name="Linker script" superClass="com.crt.advproject.link.script" value="&quot;host_cmsis_rtx_Board_MCB4300.ld&quot;" valueType="string"/>
<option id="com.crt.advproject.link.manage.1840945088" name="Manage linker script" superClass="com.crt.advproject.link.manage" value="true" valueType="boolean"/>
<option id="gnu.c.link.option.nostdlibs.745328522" name="No startup or default libs (-nostdlib)" superClass="gnu.c.link.option.nostdlibs" value="true" valueType="boolean"/>
<option id="gnu.c.link.option.other.1659973052" name="Other options (-Xlinker [option])" superClass="gnu.c.link.option.other" valueType="stringList">
@ -379,7 +379,7 @@
<option id="gnu.c.link.option.paths.715959224" name="Library search path (-L)" superClass="gnu.c.link.option.paths" valueType="libPaths">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/cmsis_rtos_rtx/LIB/GCC}&quot;"/>
</option>
<option id="com.crt.advproject.link.gcc.hdrlib.411801202" name="Use C library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.nohost" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.hdrlib.411801202" name="Library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.nohost" valueType="enumerated"/>
<option id="com.crt.advproject.link.fpu.1713572194" name="Floating point" superClass="com.crt.advproject.link.fpu" value="com.crt.advproject.link.fpu.fpv4.hard" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.multicore.slave.1674664189.1636251285" name="Multicore slave" superClass="com.crt.advproject.link.gcc.multicore.slave"/>
<option id="com.crt.advproject.link.gcc.multicore.master.413285924.1459162754" name="Multicore" superClass="com.crt.advproject.link.gcc.multicore.master"/>
@ -408,10 +408,7 @@
<projectStorage>&lt;?xml version="1.0" encoding="UTF-8"?&gt;&#13;
&lt;TargetConfig&gt;&#13;
&lt;Properties property_0="" property_2="LPC18x7_43x7_2x512_BootA.cfx" property_3="NXP" property_4="LPC4357" property_count="5" version="60100"/&gt;&#13;
&lt;infoList vendor="NXP"&gt;&#13;
&lt;info chip="LPC4357" flash_driver="LPC18x7_43x7_2x512_BootA.cfx" match_id="0x0" name="LPC4357" resetscript="LPC18LPC43InternalFLASHBootResetscript.scp" stub="crt_emu_lpc18_43_nxp"&gt;&#13;
&lt;chip&gt;&#13;
&lt;name&gt;LPC4357&lt;/name&gt;&#13;
&lt;infoList vendor="NXP"&gt;&lt;info chip="LPC4357" flash_driver="LPC18x7_43x7_2x512_BootA.cfx" match_id="0x0" name="LPC4357" resetscript="LPC18LPC43InternalFLASHBootResetscript.scp" stub="crt_emu_lpc18_43_nxp"&gt;&lt;chip&gt;&lt;name&gt;LPC4357&lt;/name&gt;&#13;
&lt;family&gt;LPC43xx&lt;/family&gt;&#13;
&lt;vendor&gt;NXP (formerly Philips)&lt;/vendor&gt;&#13;
&lt;reset board="None" core="Real" sys="Real"/&gt;&#13;
@ -486,8 +483,7 @@
&lt;peripheralInstance derived_from="SPI" determined="infoFile" id="SPI" location="0x40100000"/&gt;&#13;
&lt;peripheralInstance derived_from="SGPIO" determined="infoFile" id="SGPIO" location="0x40101000"/&gt;&#13;
&lt;/chip&gt;&#13;
&lt;processor&gt;&#13;
&lt;name gcc_name="cortex-m4"&gt;Cortex-M4&lt;/name&gt;&#13;
&lt;processor&gt;&lt;name gcc_name="cortex-m4"&gt;Cortex-M4&lt;/name&gt;&#13;
&lt;family&gt;Cortex-M&lt;/family&gt;&#13;
&lt;/processor&gt;&#13;
&lt;link href="nxp_lpc43xx_peripheral.xme" show="embed" type="simple"/&gt;&#13;

View File

@ -2780,9 +2780,6 @@
<file>
<name>$PROJ_DIR$\..\src\cdc_serial_host_app.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\src\msc_cli.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\src\keyboard_host_app.c</name>
</file>
@ -2792,6 +2789,9 @@
<file>
<name>$PROJ_DIR$\..\src\mouse_host_app.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\src\msc_cli.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\src\msc_host_app.c</name>
</file>
@ -2913,9 +2913,6 @@
<file>
<name>$PROJ_DIR$\..\..\..\tinyusb\class\cdc_host.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\..\tinyusb\class\cdc_rndis_host.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\..\tinyusb\class\hid_host.c</name>
</file>

View File

@ -458,7 +458,7 @@
<OPTFL>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<IsCurrentTarget>0</IsCurrentTarget>
<IsCurrentTarget>1</IsCurrentTarget>
</OPTFL>
<CpuCode>8</CpuCode>
<Books>
@ -673,7 +673,7 @@
<OPTFL>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<IsCurrentTarget>1</IsCurrentTarget>
<IsCurrentTarget>0</IsCurrentTarget>
</OPTFL>
<CpuCode>8</CpuCode>
<Books>
@ -906,22 +906,6 @@
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2>
<PathWithFileName>..\src\rndis_host_app.c</PathWithFileName>
<FilenameWithoutPath>rndis_host_app.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>1</GroupNumber>
<FileNumber>6</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2>
<PathWithFileName>..\src\msc_host_app.c</PathWithFileName>
<FilenameWithoutPath>msc_host_app.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
@ -929,7 +913,7 @@
</File>
<File>
<GroupNumber>1</GroupNumber>
<FileNumber>7</FileNumber>
<FileNumber>6</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -953,7 +937,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>8</FileNumber>
<FileNumber>7</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -969,7 +953,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>9</FileNumber>
<FileNumber>8</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -985,7 +969,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>10</FileNumber>
<FileNumber>9</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1001,7 +985,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>11</FileNumber>
<FileNumber>10</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1017,7 +1001,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>12</FileNumber>
<FileNumber>11</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1033,7 +1017,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>13</FileNumber>
<FileNumber>12</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1049,7 +1033,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>14</FileNumber>
<FileNumber>13</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1065,7 +1049,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>15</FileNumber>
<FileNumber>14</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1081,7 +1065,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>16</FileNumber>
<FileNumber>15</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1097,7 +1081,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>17</FileNumber>
<FileNumber>16</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1115,13 +1099,13 @@
<Group>
<GroupName>tinyusb</GroupName>
<tvExp>0</tvExp>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>0</RteFlg>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>18</FileNumber>
<FileNumber>17</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1137,7 +1121,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>19</FileNumber>
<FileNumber>18</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1153,7 +1137,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>20</FileNumber>
<FileNumber>19</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1169,7 +1153,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>21</FileNumber>
<FileNumber>20</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1185,7 +1169,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>22</FileNumber>
<FileNumber>21</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1201,7 +1185,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>23</FileNumber>
<FileNumber>22</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1217,7 +1201,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>24</FileNumber>
<FileNumber>23</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1233,7 +1217,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>25</FileNumber>
<FileNumber>24</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1249,7 +1233,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>26</FileNumber>
<FileNumber>25</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1265,7 +1249,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>27</FileNumber>
<FileNumber>26</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1281,7 +1265,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>28</FileNumber>
<FileNumber>27</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1297,7 +1281,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>29</FileNumber>
<FileNumber>28</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1313,7 +1297,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>30</FileNumber>
<FileNumber>29</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1329,23 +1313,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>31</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
<ColumnNumber>39</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\tinyusb\class\cdc_rndis_host.c</PathWithFileName>
<FilenameWithoutPath>cdc_rndis_host.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>32</FileNumber>
<FileNumber>30</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1361,7 +1329,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>33</FileNumber>
<FileNumber>31</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1377,7 +1345,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>34</FileNumber>
<FileNumber>32</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1393,7 +1361,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>35</FileNumber>
<FileNumber>33</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1409,7 +1377,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>36</FileNumber>
<FileNumber>34</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1425,7 +1393,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>37</FileNumber>
<FileNumber>35</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1441,7 +1409,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>38</FileNumber>
<FileNumber>36</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1457,7 +1425,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>39</FileNumber>
<FileNumber>37</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1473,7 +1441,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>40</FileNumber>
<FileNumber>38</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1489,7 +1457,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>41</FileNumber>
<FileNumber>39</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1505,7 +1473,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>42</FileNumber>
<FileNumber>40</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1521,7 +1489,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>43</FileNumber>
<FileNumber>41</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1545,7 +1513,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>44</FileNumber>
<FileNumber>42</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1561,7 +1529,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>45</FileNumber>
<FileNumber>43</FileNumber>
<FileType>4</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1577,7 +1545,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>46</FileNumber>
<FileNumber>44</FileNumber>
<FileType>4</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1601,7 +1569,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>47</FileNumber>
<FileNumber>45</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1617,7 +1585,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>48</FileNumber>
<FileNumber>46</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1633,7 +1601,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>49</FileNumber>
<FileNumber>47</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1657,7 +1625,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>50</FileNumber>
<FileNumber>48</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1673,7 +1641,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>51</FileNumber>
<FileNumber>49</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1689,7 +1657,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>52</FileNumber>
<FileNumber>50</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1705,7 +1673,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>53</FileNumber>
<FileNumber>51</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1721,7 +1689,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>54</FileNumber>
<FileNumber>52</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1737,7 +1705,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>55</FileNumber>
<FileNumber>53</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1753,7 +1721,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>56</FileNumber>
<FileNumber>54</FileNumber>
<FileType>2</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1777,7 +1745,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>57</FileNumber>
<FileNumber>55</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1793,7 +1761,7 @@
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>58</FileNumber>
<FileNumber>56</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1809,7 +1777,7 @@
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>59</FileNumber>
<FileNumber>57</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1825,7 +1793,7 @@
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>60</FileNumber>
<FileNumber>58</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1841,7 +1809,7 @@
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>61</FileNumber>
<FileNumber>59</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1857,7 +1825,7 @@
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>62</FileNumber>
<FileNumber>60</FileNumber>
<FileType>2</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>

View File

@ -411,11 +411,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -551,11 +546,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>
@ -1214,11 +1204,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -1394,11 +1379,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>
@ -1983,11 +1963,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -2123,11 +2098,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>
@ -2786,11 +2756,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -2926,11 +2891,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>

View File

@ -3879,9 +3879,6 @@
<file>
<name>$PROJ_DIR$\..\..\..\tinyusb\class\cdc_host.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\..\tinyusb\class\cdc_rndis_host.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\..\tinyusb\class\hid_host.c</name>
</file>

View File

@ -73,7 +73,7 @@
<OPTFL>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<IsCurrentTarget>1</IsCurrentTarget>
<IsCurrentTarget>0</IsCurrentTarget>
</OPTFL>
<CpuCode>8</CpuCode>
<DllOpt>
@ -370,7 +370,7 @@
<OPTFL>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<IsCurrentTarget>0</IsCurrentTarget>
<IsCurrentTarget>1</IsCurrentTarget>
</OPTFL>
<CpuCode>8</CpuCode>
<Books>
@ -857,7 +857,7 @@
<Group>
<GroupName>app</GroupName>
<tvExp>0</tvExp>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>0</RteFlg>
@ -936,22 +936,6 @@
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2>
<PathWithFileName>..\src\rndis_host_app.c</PathWithFileName>
<FilenameWithoutPath>rndis_host_app.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>1</GroupNumber>
<FileNumber>6</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2>
<PathWithFileName>..\src\msc_host_app.c</PathWithFileName>
<FilenameWithoutPath>msc_host_app.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
@ -959,7 +943,7 @@
</File>
<File>
<GroupNumber>1</GroupNumber>
<FileNumber>7</FileNumber>
<FileNumber>6</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -983,7 +967,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>8</FileNumber>
<FileNumber>7</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -999,7 +983,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>9</FileNumber>
<FileNumber>8</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1015,7 +999,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>10</FileNumber>
<FileNumber>9</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1031,7 +1015,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>11</FileNumber>
<FileNumber>10</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1047,7 +1031,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>12</FileNumber>
<FileNumber>11</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1063,7 +1047,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>13</FileNumber>
<FileNumber>12</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1079,7 +1063,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>14</FileNumber>
<FileNumber>13</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1095,7 +1079,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>15</FileNumber>
<FileNumber>14</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1111,7 +1095,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>16</FileNumber>
<FileNumber>15</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1127,7 +1111,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>17</FileNumber>
<FileNumber>16</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1143,7 +1127,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>18</FileNumber>
<FileNumber>17</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1159,7 +1143,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>19</FileNumber>
<FileNumber>18</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1175,7 +1159,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>20</FileNumber>
<FileNumber>19</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1191,23 +1175,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>21</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\tinyusb\class\cdc_rndis_host.c</PathWithFileName>
<FilenameWithoutPath>cdc_rndis_host.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>22</FileNumber>
<FileNumber>20</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1223,7 +1191,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>23</FileNumber>
<FileNumber>21</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1239,7 +1207,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>24</FileNumber>
<FileNumber>22</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1255,7 +1223,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>25</FileNumber>
<FileNumber>23</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1271,7 +1239,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>26</FileNumber>
<FileNumber>24</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1287,7 +1255,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>27</FileNumber>
<FileNumber>25</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1303,7 +1271,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>28</FileNumber>
<FileNumber>26</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1327,7 +1295,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>29</FileNumber>
<FileNumber>27</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1343,7 +1311,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>30</FileNumber>
<FileNumber>28</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1359,7 +1327,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>31</FileNumber>
<FileNumber>29</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1375,7 +1343,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>32</FileNumber>
<FileNumber>30</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1391,7 +1359,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>33</FileNumber>
<FileNumber>31</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1407,7 +1375,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>34</FileNumber>
<FileNumber>32</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1423,7 +1391,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>35</FileNumber>
<FileNumber>33</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1439,7 +1407,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>36</FileNumber>
<FileNumber>34</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1455,7 +1423,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>37</FileNumber>
<FileNumber>35</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1479,7 +1447,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>38</FileNumber>
<FileNumber>36</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1495,7 +1463,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>39</FileNumber>
<FileNumber>37</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1511,7 +1479,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>40</FileNumber>
<FileNumber>38</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1535,14 +1503,14 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>41</FileNumber>
<FileNumber>39</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
<ColumnNumber>0</ColumnNumber>
<ColumnNumber>1</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg>
<TopLine>66</TopLine>
<CurrentLine>81</CurrentLine>
<TopLine>74</TopLine>
<CurrentLine>75</CurrentLine>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\boards\board.c</PathWithFileName>
<FilenameWithoutPath>board.c</FilenameWithoutPath>
@ -1551,7 +1519,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>42</FileNumber>
<FileNumber>40</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1567,7 +1535,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>43</FileNumber>
<FileNumber>41</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1583,7 +1551,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>44</FileNumber>
<FileNumber>42</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1599,7 +1567,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>45</FileNumber>
<FileNumber>43</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1615,7 +1583,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>46</FileNumber>
<FileNumber>44</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1631,7 +1599,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>47</FileNumber>
<FileNumber>45</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1647,7 +1615,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>48</FileNumber>
<FileNumber>46</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1663,7 +1631,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>49</FileNumber>
<FileNumber>47</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1679,7 +1647,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>50</FileNumber>
<FileNumber>48</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1703,7 +1671,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>51</FileNumber>
<FileNumber>49</FileNumber>
<FileType>2</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1719,7 +1687,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>52</FileNumber>
<FileNumber>50</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1735,7 +1703,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>53</FileNumber>
<FileNumber>51</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1751,7 +1719,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>54</FileNumber>
<FileNumber>52</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1767,7 +1735,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>55</FileNumber>
<FileNumber>53</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1783,7 +1751,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>56</FileNumber>
<FileNumber>54</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1799,7 +1767,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>57</FileNumber>
<FileNumber>55</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1823,7 +1791,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>58</FileNumber>
<FileNumber>56</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1839,7 +1807,7 @@
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>59</FileNumber>
<FileNumber>57</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1855,7 +1823,7 @@
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>60</FileNumber>
<FileNumber>58</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1871,7 +1839,7 @@
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>61</FileNumber>
<FileNumber>59</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1887,7 +1855,7 @@
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>62</FileNumber>
<FileNumber>60</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1903,7 +1871,7 @@
</File>
<File>
<GroupNumber>7</GroupNumber>
<FileNumber>63</FileNumber>
<FileNumber>61</FileNumber>
<FileType>2</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>

View File

@ -411,11 +411,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -496,11 +491,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>
@ -1241,11 +1231,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -1326,11 +1311,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>
@ -2071,11 +2051,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -2156,11 +2131,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>
@ -2901,11 +2871,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -2986,11 +2951,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>
@ -3731,11 +3691,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -3816,11 +3771,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>

View File

@ -1,25 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?>
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="com.crt.advproject.config.exe.debug.1239969983">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.crt.advproject.config.exe.debug.1239969983" moduleId="org.eclipse.cdt.core.settings" name="Board NGX4330">
<macros>
<stringMacro name="CFLAGS_OFF" type="VALUE_TEXT" value=""/>
<stringMacro name="CFLAGS" type="VALUE_TEXT" value="${CFLAGS_OFF}"/>
<stringMacro name="CFLAGS_ON" type="VALUE_TEXT" value="-Wextra -Wswitch-default -Wunsafe-loop-optimizations -Wcast-align -Wlogical-op -Wpacked-bitfield-compat -Wnested-externs -Wredundant-decls -Winline"/>
<stringMacro name="CFLAGS" type="VALUE_TEXT" value="${CFLAGS_OFF}"/>
</macros>
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@ -75,7 +73,7 @@
</option>
<option id="gnu.c.link.option.libs.1088600788" name="Libraries (-l)" superClass="gnu.c.link.option.libs"/>
<option id="gnu.c.link.option.paths.1352371726" name="Library search path (-L)" superClass="gnu.c.link.option.paths"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1912639139" name="Use C library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1912639139" name="Library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<option id="com.crt.advproject.link.fpu.1467962306" name="Floating point" superClass="com.crt.advproject.link.fpu" value="com.crt.advproject.link.fpu.fpv4" valueType="enumerated"/>
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.1768732506" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
@ -93,25 +91,24 @@
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
<storageModule moduleId="scannerConfiguration"/>
</cconfiguration>
<cconfiguration id="com.crt.advproject.config.exe.debug.1239969983.636406670">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.crt.advproject.config.exe.debug.1239969983.636406670" moduleId="org.eclipse.cdt.core.settings" name="Board EA4357">
<macros>
<stringMacro name="CFLAGS_OFF" type="VALUE_TEXT" value=""/>
<stringMacro name="CFLAGS" type="VALUE_TEXT" value="${CFLAGS_OFF}"/>
<stringMacro name="CFLAGS_ON" type="VALUE_TEXT" value="-Wextra -Wswitch-default -Wunsafe-loop-optimizations -Wcast-align -Wlogical-op -Wpacked-bitfield-compat -Wnested-externs -Wredundant-decls -Winline"/>
<stringMacro name="CFLAGS" type="VALUE_TEXT" value="${CFLAGS_OFF}"/>
</macros>
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@ -167,7 +164,7 @@
</option>
<option id="gnu.c.link.option.libs.1825587478" name="Libraries (-l)" superClass="gnu.c.link.option.libs"/>
<option id="gnu.c.link.option.paths.916077707" name="Library search path (-L)" superClass="gnu.c.link.option.paths"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1015545513" name="Use C library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1015545513" name="Library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<option id="com.crt.advproject.link.fpu.409118044" name="Floating point" superClass="com.crt.advproject.link.fpu" value="com.crt.advproject.link.fpu.fpv4" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.multicore.slave.807948498" name="Multicore slave" superClass="com.crt.advproject.link.gcc.multicore.slave"/>
<option id="com.crt.advproject.link.gcc.multicore.master.1340978016" name="Multicore" superClass="com.crt.advproject.link.gcc.multicore.master"/>
@ -187,25 +184,24 @@
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
<storageModule moduleId="scannerConfiguration"/>
</cconfiguration>
<cconfiguration id="com.crt.advproject.config.exe.debug.1239969983.636406670.2112314850">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.crt.advproject.config.exe.debug.1239969983.636406670.2112314850" moduleId="org.eclipse.cdt.core.settings" name="Board MCB4300">
<macros>
<stringMacro name="CFLAGS_OFF" type="VALUE_TEXT" value=""/>
<stringMacro name="CFLAGS" type="VALUE_TEXT" value="${CFLAGS_OFF}"/>
<stringMacro name="CFLAGS_ON" type="VALUE_TEXT" value="-Wextra -Wswitch-default -Wunsafe-loop-optimizations -Wcast-align -Wlogical-op -Wpacked-bitfield-compat -Wnested-externs -Wredundant-decls -Winline"/>
<stringMacro name="CFLAGS" type="VALUE_TEXT" value="${CFLAGS_OFF}"/>
</macros>
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@ -261,7 +257,7 @@
</option>
<option id="gnu.c.link.option.libs.495921515" name="Libraries (-l)" superClass="gnu.c.link.option.libs"/>
<option id="gnu.c.link.option.paths.692268551" name="Library search path (-L)" superClass="gnu.c.link.option.paths"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1209404346" name="Use C library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1209404346" name="Library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<option id="com.crt.advproject.link.fpu.1664439954" name="Floating point" superClass="com.crt.advproject.link.fpu" value="com.crt.advproject.link.fpu.fpv4" valueType="enumerated"/>
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.1521825863" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
@ -279,25 +275,24 @@
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
<storageModule moduleId="scannerConfiguration"/>
</cconfiguration>
<cconfiguration id="com.crt.advproject.config.exe.debug.1239969983.131108573">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.crt.advproject.config.exe.debug.1239969983.131108573" moduleId="org.eclipse.cdt.core.settings" name="Board LPC4357USB">
<macros>
<stringMacro name="CFLAGS_OFF" type="VALUE_TEXT" value=""/>
<stringMacro name="CFLAGS" type="VALUE_TEXT" value="${CFLAGS_OFF}"/>
<stringMacro name="CFLAGS_ON" type="VALUE_TEXT" value="-Wextra -Wswitch-default -Wunsafe-loop-optimizations -Wcast-align -Wlogical-op -Wpacked-bitfield-compat -Wnested-externs -Wredundant-decls -Winline"/>
<stringMacro name="CFLAGS" type="VALUE_TEXT" value="${CFLAGS_OFF}"/>
</macros>
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@ -351,7 +346,7 @@
</option>
<option id="gnu.c.link.option.libs.1973103706" name="Libraries (-l)" superClass="gnu.c.link.option.libs"/>
<option id="gnu.c.link.option.paths.909013832" name="Library search path (-L)" superClass="gnu.c.link.option.paths"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1101482430" name="Use C library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.hdrlib.1101482430" name="Library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.1196932037" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
@ -368,25 +363,24 @@
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
<storageModule moduleId="scannerConfiguration"/>
</cconfiguration>
<cconfiguration id="com.crt.advproject.config.exe.debug.1239969983.636406670.872802562">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.crt.advproject.config.exe.debug.1239969983.636406670.872802562" moduleId="org.eclipse.cdt.core.settings" name="Board LPCXpresso1769">
<macros>
<stringMacro name="CFLAGS_OFF" type="VALUE_TEXT" value=""/>
<stringMacro name="CFLAGS" type="VALUE_TEXT" value="${CFLAGS_OFF}"/>
<stringMacro name="CFLAGS_ON" type="VALUE_TEXT" value="-Wextra -Wswitch-default -Wunsafe-loop-optimizations -Wcast-align -Wlogical-op -Wpacked-bitfield-compat -Wnested-externs -Wredundant-decls -Winline"/>
<stringMacro name="CFLAGS" type="VALUE_TEXT" value="${CFLAGS_OFF}"/>
</macros>
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@ -442,7 +436,7 @@
</option>
<option id="gnu.c.link.option.libs.1868402007" name="Libraries (-l)" superClass="gnu.c.link.option.libs"/>
<option id="gnu.c.link.option.paths.943091458" name="Library search path (-L)" superClass="gnu.c.link.option.paths"/>
<option id="com.crt.advproject.link.gcc.hdrlib.961930336" name="Use C library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.hdrlib.961930336" name="Library" superClass="com.crt.advproject.link.gcc.hdrlib" value="com.crt.advproject.gcc.link.hdrlib.codered.semihost" valueType="enumerated"/>
<option id="com.crt.advproject.link.fpu.837495348" name="Floating point" superClass="com.crt.advproject.link.fpu" value="com.crt.advproject.link.fpu.none" valueType="enumerated"/>
<option id="com.crt.advproject.link.gcc.multicore.slave.92784419" name="Multicore slave" superClass="com.crt.advproject.link.gcc.multicore.slave"/>
<inputType id="cdt.managedbuild.tool.gnu.c.linker.input.1609667925" superClass="cdt.managedbuild.tool.gnu.c.linker.input">
@ -461,7 +455,6 @@
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
<storageModule moduleId="scannerConfiguration"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">

View File

@ -3817,9 +3817,6 @@
<file>
<name>$PROJ_DIR$\..\..\..\tinyusb\class\cdc_host.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\..\tinyusb\class\cdc_rndis_host.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\..\..\tinyusb\class\hid_host.c</name>
</file>

View File

@ -465,7 +465,7 @@
<OPTFL>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<IsCurrentTarget>0</IsCurrentTarget>
<IsCurrentTarget>1</IsCurrentTarget>
</OPTFL>
<CpuCode>8</CpuCode>
<Books>
@ -889,7 +889,7 @@
<OPTFL>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<IsCurrentTarget>1</IsCurrentTarget>
<IsCurrentTarget>0</IsCurrentTarget>
</OPTFL>
<CpuCode>8</CpuCode>
<Books>
@ -1050,7 +1050,7 @@
<Group>
<GroupName>app</GroupName>
<tvExp>1</tvExp>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>0</RteFlg>
@ -1129,22 +1129,6 @@
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2>
<PathWithFileName>..\src\rndis_host_app.c</PathWithFileName>
<FilenameWithoutPath>rndis_host_app.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>1</GroupNumber>
<FileNumber>6</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2>
<PathWithFileName>..\src\msc_host_app.c</PathWithFileName>
<FilenameWithoutPath>msc_host_app.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
@ -1152,7 +1136,7 @@
</File>
<File>
<GroupNumber>1</GroupNumber>
<FileNumber>7</FileNumber>
<FileNumber>6</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1176,7 +1160,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>8</FileNumber>
<FileNumber>7</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1192,7 +1176,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>9</FileNumber>
<FileNumber>8</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1208,7 +1192,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>10</FileNumber>
<FileNumber>9</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1224,7 +1208,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>11</FileNumber>
<FileNumber>10</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1240,7 +1224,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>12</FileNumber>
<FileNumber>11</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1256,7 +1240,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>13</FileNumber>
<FileNumber>12</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1272,7 +1256,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>14</FileNumber>
<FileNumber>13</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1288,7 +1272,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>15</FileNumber>
<FileNumber>14</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1304,7 +1288,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>16</FileNumber>
<FileNumber>15</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1320,7 +1304,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>17</FileNumber>
<FileNumber>16</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1336,7 +1320,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>18</FileNumber>
<FileNumber>17</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1352,7 +1336,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>19</FileNumber>
<FileNumber>18</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1368,7 +1352,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>20</FileNumber>
<FileNumber>19</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1384,23 +1368,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>21</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
<ColumnNumber>0</ColumnNumber>
<tvExpOptDlg>0</tvExpOptDlg>
<TopLine>0</TopLine>
<CurrentLine>0</CurrentLine>
<bDave2>0</bDave2>
<PathWithFileName>..\..\..\tinyusb\class\cdc_rndis_host.c</PathWithFileName>
<FilenameWithoutPath>cdc_rndis_host.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>22</FileNumber>
<FileNumber>20</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1416,7 +1384,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>23</FileNumber>
<FileNumber>21</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1432,7 +1400,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>24</FileNumber>
<FileNumber>22</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1448,7 +1416,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>25</FileNumber>
<FileNumber>23</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1464,7 +1432,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>26</FileNumber>
<FileNumber>24</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1480,7 +1448,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>27</FileNumber>
<FileNumber>25</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1496,7 +1464,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>28</FileNumber>
<FileNumber>26</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1512,7 +1480,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>29</FileNumber>
<FileNumber>27</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1528,7 +1496,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>30</FileNumber>
<FileNumber>28</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1544,7 +1512,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>31</FileNumber>
<FileNumber>29</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1560,7 +1528,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>32</FileNumber>
<FileNumber>30</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1576,7 +1544,7 @@
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>33</FileNumber>
<FileNumber>31</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1600,7 +1568,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>34</FileNumber>
<FileNumber>32</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1616,7 +1584,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>35</FileNumber>
<FileNumber>33</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1632,7 +1600,7 @@
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>36</FileNumber>
<FileNumber>34</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1650,13 +1618,13 @@
<Group>
<GroupName>boards</GroupName>
<tvExp>1</tvExp>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>0</RteFlg>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>37</FileNumber>
<FileNumber>35</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1672,7 +1640,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>38</FileNumber>
<FileNumber>36</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1688,7 +1656,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>39</FileNumber>
<FileNumber>37</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1704,7 +1672,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>40</FileNumber>
<FileNumber>38</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1720,7 +1688,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>41</FileNumber>
<FileNumber>39</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1736,7 +1704,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>42</FileNumber>
<FileNumber>40</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1752,7 +1720,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>43</FileNumber>
<FileNumber>41</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1768,7 +1736,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>44</FileNumber>
<FileNumber>42</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1784,7 +1752,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>45</FileNumber>
<FileNumber>43</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1800,7 +1768,7 @@
</File>
<File>
<GroupNumber>4</GroupNumber>
<FileNumber>46</FileNumber>
<FileNumber>44</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1824,7 +1792,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>47</FileNumber>
<FileNumber>45</FileNumber>
<FileType>2</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1840,7 +1808,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>48</FileNumber>
<FileNumber>46</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1856,7 +1824,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>49</FileNumber>
<FileNumber>47</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1872,7 +1840,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>50</FileNumber>
<FileNumber>48</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1888,7 +1856,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>51</FileNumber>
<FileNumber>49</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1904,7 +1872,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>52</FileNumber>
<FileNumber>50</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1920,7 +1888,7 @@
</File>
<File>
<GroupNumber>5</GroupNumber>
<FileNumber>53</FileNumber>
<FileNumber>51</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1944,7 +1912,7 @@
<RteFlg>0</RteFlg>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>54</FileNumber>
<FileNumber>52</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1960,7 +1928,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>55</FileNumber>
<FileNumber>53</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1976,7 +1944,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>56</FileNumber>
<FileNumber>54</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -1992,7 +1960,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>57</FileNumber>
<FileNumber>55</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -2008,7 +1976,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>58</FileNumber>
<FileNumber>56</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>
@ -2024,7 +1992,7 @@
</File>
<File>
<GroupNumber>6</GroupNumber>
<FileNumber>59</FileNumber>
<FileNumber>57</FileNumber>
<FileType>2</FileType>
<tvExp>0</tvExp>
<Focus>0</Focus>

View File

@ -411,11 +411,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -496,11 +491,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>
@ -1176,11 +1166,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -1261,11 +1246,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>
@ -1941,11 +1921,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -2026,11 +2001,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>
@ -2706,11 +2676,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -2791,11 +2756,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>
@ -3471,11 +3431,6 @@
<FileType>1</FileType>
<FilePath>..\src\mouse_host_app.c</FilePath>
</File>
<File>
<FileName>rndis_host_app.c</FileName>
<FileType>1</FileType>
<FilePath>..\src\rndis_host_app.c</FilePath>
</File>
<File>
<FileName>msc_host_app.c</FileName>
<FileType>1</FileType>
@ -3556,11 +3511,6 @@
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_host.c</FilePath>
</File>
<File>
<FileName>cdc_rndis_host.c</FileName>
<FileType>1</FileType>
<FilePath>..\..\..\tinyusb\class\cdc_rndis_host.c</FilePath>
</File>
<File>
<FileName>hid_host.c</FileName>
<FileType>1</FileType>

View File

@ -50,7 +50,6 @@
#include "keyboard_host_app.h"
#include "msc_host_app.h"
#include "cdc_serial_host_app.h"
#include "rndis_host_app.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
@ -78,7 +77,6 @@ void os_none_start_scheduler(void)
mouse_host_app_task(NULL);
msc_host_app_task(NULL);
cdc_serial_host_app_task(NULL);
rndis_host_app_task(NULL);
}
}
#endif
@ -101,7 +99,6 @@ int main(void)
mouse_host_app_init();
msc_host_app_init();
cdc_serial_host_app_init();
rndis_host_app_init();
//------------- start OS scheduler (never return) -------------//
#if TUSB_CFG_OS == TUSB_OS_FREERTOS

View File

@ -1,76 +0,0 @@
/**************************************************************************/
/*!
@file rndis_host_app.c
@author hathach (tinyusb.org)
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2013, hathach (tinyusb.org)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This file is part of the tinyusb stack.
*/
/**************************************************************************/
#include "rndis_host_app.h"
#include "app_os_prio.h"
#if TUSB_CFG_HOST_CDC && TUSB_CFG_HOST_CDC_RNDIS
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
void tusbh_cdc_rndis_mounted_cb(uint8_t dev_addr)
{ // application set-up
uint8_t mac_address[6];
printf("\nan RNDIS device is mounted\n");
tusbh_cdc_rndis_get_mac_addr(dev_addr, mac_address);
printf("MAC Address ");
for(uint8_t i=0; i<6; i++) printf("%X ", mac_address[i]);
printf("\n");
}
void tusbh_cdc_rndis_unmounted_cb(uint8_t dev_addr)
{
// application tear-down
printf("\nan RNDIS device is unmounted\n");
}
void rndis_host_app_init(void)
{
}
OSAL_TASK_FUNCTION( rndis_host_app_task, p_task_para)
{
OSAL_TASK_LOOP_BEGIN
OSAL_TASK_LOOP_END
}
#endif

View File

@ -1,75 +0,0 @@
/**************************************************************************/
/*!
@file rndis_host_app.h
@author hathach (tinyusb.org)
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2013, hathach (tinyusb.org)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This file is part of the tinyusb stack.
*/
/**************************************************************************/
/** \ingroup TBD
* \defgroup TBD
* \brief TBD
*
* @{
*/
#ifndef _TUSB_RNDIS_HOST_APP_H_
#define _TUSB_RNDIS_HOST_APP_H_
#include "board.h"
#include "tusb.h"
#ifdef __cplusplus
extern "C" {
#endif
#if TUSB_CFG_HOST_CDC && TUSB_CFG_HOST_CDC_RNDIS
void rndis_host_app_init(void);
OSAL_TASK_FUNCTION( rndis_host_app_task, p_task_para);
#else
#define rndis_host_app_init()
#define rndis_host_app_task(x)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_RNDIS_HOST_APP_H_ */
/** @} */

View File

@ -61,7 +61,6 @@
#define TUSB_CFG_HOST_HID_GENERIC 0 // (not yet supported)
#define TUSB_CFG_HOST_MSC 1
#define TUSB_CFG_HOST_CDC 1
#define TUSB_CFG_HOST_CDC_RNDIS 0
//--------------------------------------------------------------------+
// COMMON CONFIGURATION

View File

@ -47,7 +47,6 @@
//--------------------------------------------------------------------+
#include "common/common.h"
#include "cdc_host.h"
#include "cdc_rndis_host.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
@ -115,11 +114,6 @@ bool tusbh_cdc_serial_is_mounted(uint8_t dev_addr)
(cdch_data[dev_addr-1].interface_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA);
}
bool tusbh_cdc_rndis_is_mounted(uint8_t dev_addr)
{
return tusbh_cdc_is_mounted(dev_addr) && cdch_data[dev_addr-1].is_rndis;
}
tusb_error_t tusbh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify)
{
ASSERT( tusbh_cdc_is_mounted(dev_addr), TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED);
@ -148,9 +142,6 @@ tusb_error_t tusbh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t lengt
void cdch_init(void)
{
memclr_(cdch_data, sizeof(cdch_data_t)*TUSB_CFG_HOST_DEVICE_MAX);
#if TUSB_CFG_HOST_CDC_RNDIS
rndish_init();
#endif
}
tusb_error_t cdch_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t const *p_interface_desc, uint16_t *p_length)
@ -224,24 +215,6 @@ tusb_error_t cdch_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t con
}
}
#if TUSB_CFG_HOST_CDC_RNDIS // TODO move to rndis_host.c
//------------- RNDIS -------------//
if ( 0xff == cdch_data[dev_addr-1].interface_protocol && pipehandle_is_valid(cdch_data[dev_addr-1].pipe_notification) )
{
tusb_error_t error;
cdch_data[dev_addr-1].is_rndis = true; // set as true at first
OSAL_SUBTASK_INVOKED_AND_WAIT( rndish_open_subtask(dev_addr, &cdch_data[dev_addr-1]), error );
if (TUSB_ERROR_NONE != error)
{
cdch_data[dev_addr-1].is_rndis = false;
}
}
if ( !cdch_data[dev_addr-1].is_rndis ) // device is not an rndis
#endif
{
// FIXME mounted class flag is not set yet
tusbh_cdc_mounted_cb(dev_addr);
@ -252,14 +225,6 @@ tusb_error_t cdch_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t con
void cdch_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes)
{
#if TUSB_CFG_HOST_CDC_RNDIS
cdch_data_t *p_cdc = &cdch_data[pipe_hdl.dev_addr - 1];
if ( p_cdc->is_rndis )
{
rndish_xfer_isr(p_cdc, pipe_hdl, event, xferred_bytes);
} else
#endif
tusbh_cdc_xfer_isr( pipe_hdl.dev_addr, event, get_app_pipeid(pipe_hdl), xferred_bytes );
}
@ -267,21 +232,10 @@ void cdch_close(uint8_t dev_addr)
{
cdch_data_t * p_cdc = &cdch_data[dev_addr-1];
#if TUSB_CFG_HOST_CDC_RNDIS
if (p_cdc->is_rndis)
{
rndish_close(dev_addr);
}
#endif
(void) hcd_pipe_close(p_cdc->pipe_notification);
(void) hcd_pipe_close(p_cdc->pipe_in);
(void) hcd_pipe_close(p_cdc->pipe_out);
#if TUSB_CFG_HOST_CDC_RNDIS
#endif
memclr_(p_cdc, sizeof(cdch_data_t));
tusbh_cdc_unmounted_cb(dev_addr);

View File

@ -71,7 +71,7 @@ bool tusbh_cdc_serial_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RE
* \retval false if the interface is not busy, meaning the stack successfully transferred data from/to device
* \note This function is used to check if previous transfer is complete (success or error), so that the next transfer
* can be scheduled. User needs to make sure the corresponding interface is mounted
* (by \ref tusbh_cdc_serial_is_mounted or \ref tusbh_cdc_rndis_is_mounted) before calling this function.
* (by \ref tusbh_cdc_serial_is_mounted) before calling this function.
*/
bool tusbh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid) ATTR_PURE ATTR_WARN_UNUSED_RESULT;
@ -132,34 +132,6 @@ void tusbh_cdc_xfer_isr(uint8_t dev_addr, tusb_event_t event, cdc_pipeid_t pipe_
/// @} // group CDC_Serial_Host
/// @}
//--------------------------------------------------------------------+
// RNDIS APPLICATION API
//--------------------------------------------------------------------+
/** \ingroup CDC_RNSID_Host
* @{ */
bool tusbh_cdc_rndis_is_mounted(uint8_t dev_addr) ATTR_PURE ATTR_WARN_UNUSED_RESULT;
tusb_error_t tusbh_cdc_rndis_get_mac_addr(uint8_t dev_addr, uint8_t mac_address[6]);
//--------------------------------------------------------------------+
// RNDIS Application Callback (overshadow CDC callbacks)
//--------------------------------------------------------------------+
/** \brief Callback function that will be invoked when a device with RNDIS interface is mounted
* \param[in] dev_addr Address of newly mounted device
* \note This callback should be used by Application to set-up interface-related data
*/
void tusbh_cdc_rndis_mounted_cb(uint8_t dev_addr);
/** \brief Callback function that will be invoked when a device with RNDIS interface is unmounted
* \param[in] dev_addr Address of newly unmounted device
* \note This callback should be used by Application to tear-down interface-related data
*/
void tusbh_cdc_rndis_unmounted_cb(uint8_t dev_addr);
void tusbh_cdc_rndis_xfer_isr(uint8_t dev_addr, tusb_event_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes);
/// @} // group CDC_RNSID_Host
//--------------------------------------------------------------------+
// USBH-CLASS API
//--------------------------------------------------------------------+
@ -168,7 +140,7 @@ void tusbh_cdc_rndis_xfer_isr(uint8_t dev_addr, tusb_event_t event, cdc_pipeid_t
typedef struct {
uint8_t interface_number;
uint8_t interface_protocol;
bool is_rndis;
cdc_acm_capability_t acm_capability;
pipe_handle_t pipe_notification, pipe_out, pipe_in;

View File

@ -1,309 +0,0 @@
/**************************************************************************/
/*!
@file cdc_rndis.h
@author hathach (tinyusb.org)
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2013, hathach (tinyusb.org)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This file is part of the tinyusb stack.
*/
/**************************************************************************/
/** \ingroup ClassDriver_CDC Communication Device Class (CDC)
* \defgroup CDC_RNDIS Remote Network Driver Interface Specification (RNDIS)
* @{
* \defgroup CDC_RNDIS_Common Common Definitions
* @{ */
#ifndef _TUSB_CDC_RNDIS_H_
#define _TUSB_CDC_RNDIS_H_
#include "cdc.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __CC_ARM
#pragma diag_suppress 66 // Suppress Keil warnings #66-D: enumeration value is out of "int" range
#endif
/// RNDIS Message Types
typedef enum {
RNDIS_MSG_PACKET = 0x00000001UL, ///< The host and device use this to send network data to one another.
RNDIS_MSG_INITIALIZE = 0x00000002UL, ///< Sent by the host to initialize the device.
RNDIS_MSG_INITIALIZE_CMPLT = 0x80000002UL, ///< Device response to an initialize message.
RNDIS_MSG_HALT = 0x00000003UL, ///< Sent by the host to halt the device. This does not have a response. It is optional for the device to send this message to the host.
RNDIS_MSG_QUERY = 0x00000004UL, ///< Sent by the host to send a query OID.
RNDIS_MSG_QUERY_CMPLT = 0x80000004UL, ///< Device response to a query OID.
RNDIS_MSG_SET = 0x00000005UL, ///< Sent by the host to send a set OID.
RNDIS_MSG_SET_CMPLT = 0x80000005UL, ///< Device response to a set OID.
RNDIS_MSG_RESET = 0x00000006UL, ///< Sent by the host to perform a soft reset on the device.
RNDIS_MSG_RESET_CMPLT = 0x80000006UL, ///< Device response to reset message.
RNDIS_MSG_INDICATE_STATUS = 0x00000007UL, ///< Sent by the device to indicate its status or an error when an unrecognized message is received.
RNDIS_MSG_KEEP_ALIVE = 0x00000008UL, ///< During idle periods, sent every few seconds by the host to check that the device is still responsive. It is optional for the device to send this message to check if the host is active.
RNDIS_MSG_KEEP_ALIVE_CMPLT = 0x80000008UL ///< The device response to a keepalivemessage. The host can respond with this message to a keepalive message from the device when the device implements the optional KeepAliveTimer.
}rndis_msg_type_t;
/// RNDIS Message Status Values
typedef enum {
RNDIS_STATUS_SUCCESS = 0x00000000UL, ///< Success
RNDIS_STATUS_FAILURE = 0xC0000001UL, ///< Unspecified error
RNDIS_STATUS_INVALID_DATA = 0xC0010015UL, ///< Invalid data error
RNDIS_STATUS_NOT_SUPPORTED = 0xC00000BBUL, ///< Unsupported request error
RNDIS_STATUS_MEDIA_CONNECT = 0x4001000BUL, ///< Device is connected to a network medium.
RNDIS_STATUS_MEDIA_DISCONNECT = 0x4001000CUL ///< Device is disconnected from the medium.
}rndis_msg_status_t;
#ifdef __CC_ARM
#pragma diag_default 66 // return Keil 66 to normal severity
#endif
//--------------------------------------------------------------------+
// MESSAGE STRUCTURE
//--------------------------------------------------------------------+
//------------- Initialize -------------//
/// \brief Initialize Message
/// \details This message MUST be sent by the host to initialize the device.
typedef struct {
uint32_t type ; ///< Message type, must be \ref RNDIS_MSG_INITIALIZE
uint32_t length ; ///< Message length in bytes, must be 0x18
uint32_t request_id ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device.
uint32_t major_version ; ///< The major version of the RNDIS Protocol implemented by the host.
uint32_t minor_version ; ///< The minor version of the RNDIS Protocol implemented by the host
uint32_t max_xfer_size ; ///< The maximum size, in bytes, of any single bus data transfer that the host expects to receive from the device.
}rndis_msg_initialize_t;
/// \brief Initialize Complete Message
/// \details This message MUST be sent by the device in response to an initialize message.
typedef struct {
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_INITIALIZE_CMPLT
uint32_t length ; ///< Message length in bytes, must be 0x30
uint32_t request_id ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_initialize_t to which this message is a response.
uint32_t status ; ///< The initialization status of the device, has value from \ref rndis_msg_status_t
uint32_t major_version ; ///< the highest-numbered RNDIS Protocol version supported by the device.
uint32_t minor_version ; ///< the highest-numbered RNDIS Protocol version supported by the device.
uint32_t device_flags ; ///< MUST be set to 0x000000010. Other values are reserved for future use.
uint32_t medium ; ///< is 0x00 for RNDIS_MEDIUM_802_3
uint32_t max_packet_per_xfer ; ///< The maximum number of concatenated \ref RNDIS_MSG_PACKET messages that the device can handle in a single bus transfer to it. This value MUST be at least 1.
uint32_t max_xfer_size ; ///< The maximum size, in bytes, of any single bus data transfer that the device expects to receive from the host.
uint32_t packet_alignment_factor ; ///< The byte alignment the device expects for each RNDIS message that is part of a multimessage transfer to it. The value is specified as an exponent of 2; for example, the host uses 2<SUP>{PacketAlignmentFactor}</SUP> as the alignment value.
uint32_t reserved[2] ;
} rndis_msg_initialize_cmplt_t;
//------------- Query -------------//
/// \brief Query Message
/// \details This message MUST be sent by the host to query an OID.
typedef struct {
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_QUERY
uint32_t length ; ///< Message length in bytes, including the header and the \a oid_buffer
uint32_t request_id ; ///< A 32-bit integer value, generated by the host, used to match the host's sent request to the response from the device.
uint32_t oid ; ///< The integer value of the host operating system-defined identifier, for the parameter of the device being queried for.
uint32_t buffer_length ; ///< The length, in bytes, of the input data required for the OID query. This MUST be set to 0 when there is no input data associated with the OID.
uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the input data for the query is located in the message. This value MUST be set to 0 when there is no input data associated with the OID.
uint32_t reserved ;
uint8_t oid_buffer[] ; ///< Flexible array contains the input data supplied by the host, required for the OID query request processing by the device, as per the host NDIS specification.
} rndis_msg_query_t, rndis_msg_set_t;
STATIC_ASSERT(sizeof(rndis_msg_query_t) == 28, "Make sure flexible array member does not affect layout");
/// \brief Query Complete Message
/// \details This message MUST be sent by the device in response to a query OID message.
typedef struct {
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_QUERY_CMPLT
uint32_t length ; ///< Message length in bytes, including the header and the \a oid_buffer
uint32_t request_id ; ///< A 32-bit integer value from \a request_id field of the \ref rndis_msg_query_t to which this message is a response.
uint32_t status ; ///< The status of processing for the query request, has value from \ref rndis_msg_status_t.
uint32_t buffer_length ; ///< The length, in bytes, of the data in the response to the query. This MUST be set to 0 when there is no OIDInputBuffer.
uint32_t buffer_offset ; ///< The offset, in bytes, from the beginning of \a request_id field where the response data for the query is located in the message. This MUST be set to 0 when there is no \ref oid_buffer.
uint8_t oid_buffer[] ; ///< Flexible array member contains the response data to the OID query request as specified by the host.
} rndis_msg_query_cmplt_t;
STATIC_ASSERT(sizeof(rndis_msg_query_cmplt_t) == 24, "Make sure flexible array member does not affect layout");
//------------- Reset -------------//
/// \brief Reset Message
/// \details This message MUST be sent by the host to perform a soft reset on the device.
typedef struct {
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_RESET
uint32_t length ; ///< Message length in bytes, MUST be 0x06
uint32_t reserved ;
} rndis_msg_reset_t;
/// \brief Reset Complete Message
/// \details This message MUST be sent by the device in response to a reset message.
typedef struct {
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_RESET_CMPLT
uint32_t length ; ///< Message length in bytes, MUST be 0x10
uint32_t status ; ///< The status of processing for the \ref rndis_msg_reset_t, has value from \ref rndis_msg_status_t.
uint32_t addressing_reset ; ///< This field indicates whether the addressing information, which is the multicast address list or packet filter, has been lost during the reset operation. This MUST be set to 0x00000001 if the device requires that the host to resend addressing information or MUST be set to zero otherwise.
} rndis_msg_reset_cmplt_t;
//typedef struct {
// uint32_t type;
// uint32_t length;
// uint32_t status;
// uint32_t buffer_length;
// uint32_t buffer_offset;
// uint32_t diagnostic_status; // optional
// uint32_t diagnostic_error_offset; // optional
// uint32_t status_buffer[0]; // optional
//} rndis_msg_indicate_status_t;
/// \brief Keep Alive Message
/// \details This message MUST be sent by the host to check that device is still responsive. It is optional for the device to send this message to check if the host is active
typedef struct {
uint32_t type ; ///< Message Type
uint32_t length ; ///< Message length in bytes, MUST be 0x10
uint32_t request_id ;
} rndis_msg_keep_alive_t, rndis_msg_halt_t;
/// \brief Set Complete Message
/// \brief This message MUST be sent in response to a the request message
typedef struct {
uint32_t type ; ///< Message Type
uint32_t length ; ///< Message length in bytes, MUST be 0x10
uint32_t request_id ; ///< must be the same as requesting message
uint32_t status ; ///< The status of processing for the request message request by the device to which this message is the response.
} rndis_msg_set_cmplt_t, rndis_msg_keep_alive_cmplt_t;
/// \brief Packet Data Message
/// \brief This message MUST be used by the host and the device to send network data to one another.
typedef struct {
uint32_t type ; ///< Message Type, must be \ref RNDIS_MSG_PACKET
uint32_t length ; ///< Message length in bytes, The total length of this RNDIS message including the header, payload, and padding.
uint32_t data_offset ; ///< Specifies the offset, in bytes, from the start of this \a data_offset field of this message to the start of the data. This MUST be an integer multiple of 4.
uint32_t data_length ; ///< Specifies the number of bytes in the payload of this message.
uint32_t out_of_band_data_offet ; ///< Specifies the offset, in bytes, of the first out-of-band data record from the start of the DataOffset field in this message. MUST be an integer multiple of 4 when out-of-band data is present or set to 0 otherwise. When there are multiple out-ofband data records, each subsequent record MUST immediately follow the previous out-of-band data record.
uint32_t out_of_band_data_length ; ///< Specifies, in bytes, the total length of the out-of-band data.
uint32_t num_out_of_band_data_elements ; ///< Specifies the number of out-of-band records in this message.
uint32_t per_packet_info_offset ; ///< Specifies the offset, in bytes, of the start of per-packet-info data record from the start of the \a data_offset field in this message. MUST be an integer multiple of 4 when per-packet-info data record is present or MUST be set to 0 otherwise. When there are multiple per-packet-info data records, each subsequent record MUST immediately follow the previous record.
uint32_t per_packet_info_length ; ///< Specifies, in bytes, the total length of per-packetinformation contained in this message.
uint32_t reserved[2] ;
uint32_t payload[0] ; ///< Network data contained in this message.
// uint8_t padding[0]
// Additional bytes of zeros added at the end of the message to comply with
// the internal and external padding requirements. Internal padding SHOULD be as per the
// specification of the out-of-band data record and per-packet-info data record. The external
//padding size SHOULD be determined based on the PacketAlignmentFactor field specification
//in REMOTE_NDIS_INITIALIZE_CMPLT message by the device, when multiple
//REMOTE_NDIS_PACKET_MSG messages are bundled together in a single bus-native message.
//In this case, all but the very last REMOTE_NDIS_PACKET_MSG MUST respect the
//PacketAlignmentFactor field.
// rndis_msg_packet_t [0] : (optional) more packet if multiple packet per bus transaction is supported
} rndis_msg_packet_t;
typedef struct {
uint32_t size ; ///< Length, in bytes, of this header and appended data and padding. This value MUST be an integer multiple of 4.
uint32_t type ; ///< MUST be as per host operating system specification.
uint32_t offset ; ///< The byte offset from the beginning of this record to the beginning of data.
uint32_t data[0] ; ///< Flexible array contains data
} rndis_msg_out_of_band_data_t, rndis_msg_per_packet_info_t;
//--------------------------------------------------------------------+
// NDIS Object ID
//--------------------------------------------------------------------+
/// NDIS Object ID
typedef enum {
//------------- General Required OIDs -------------//
RNDIS_OID_GEN_SUPPORTED_LIST = 0x00010101, ///< List of supported OIDs
RNDIS_OID_GEN_HARDWARE_STATUS = 0x00010102, ///< Hardware status
RNDIS_OID_GEN_MEDIA_SUPPORTED = 0x00010103, ///< Media types supported (encoded)
RNDIS_OID_GEN_MEDIA_IN_USE = 0x00010104, ///< Media types in use (encoded)
RNDIS_OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105, ///<
RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106, ///< Maximum frame size in bytes
RNDIS_OID_GEN_LINK_SPEED = 0x00010107, ///< Link speed in units of 100 bps
RNDIS_OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108, ///< Transmit buffer space
RNDIS_OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109, ///< Receive buffer space
RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010A, ///< Minimum amount of storage, in bytes, that a single packet occupies in the transmit buffer space of the NIC
RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010B, ///< Amount of storage, in bytes, that a single packet occupies in the receive buffer space of the NIC
RNDIS_OID_GEN_VENDOR_ID = 0x0001010C, ///< Vendor NIC code
RNDIS_OID_GEN_VENDOR_DESCRIPTION = 0x0001010D, ///< Vendor network card description
RNDIS_OID_GEN_CURRENT_PACKET_FILTER = 0x0001010E, ///< Current packet filter (encoded)
RNDIS_OID_GEN_CURRENT_LOOKAHEAD = 0x0001010F, ///< Current lookahead size in bytes
RNDIS_OID_GEN_DRIVER_VERSION = 0x00010110, ///< NDIS version number used by the driver
RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111, ///< Maximum total packet length in bytes
RNDIS_OID_GEN_PROTOCOL_OPTIONS = 0x00010112, ///< Optional protocol flags (encoded)
RNDIS_OID_GEN_MAC_OPTIONS = 0x00010113, ///< Optional NIC flags (encoded)
RNDIS_OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114, ///< Whether the NIC is connected to the network
RNDIS_OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115, ///< The maximum number of send packets the driver can accept per call to its MiniportSendPacketsfunction
//------------- General Optional OIDs -------------//
RNDIS_OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116, ///< Vendor-assigned version number of the driver
RNDIS_OID_GEN_SUPPORTED_GUIDS = 0x00010117, ///< The custom GUIDs (Globally Unique Identifier) supported by the miniport driver
RNDIS_OID_GEN_NETWORK_LAYER_ADDRESSES = 0x00010118, ///< List of network-layer addresses associated with the binding between a transport and the driver
RNDIS_OID_GEN_TRANSPORT_HEADER_OFFSET = 0x00010119, ///< Size of packets' additional headers
RNDIS_OID_GEN_MEDIA_CAPABILITIES = 0x00010201, ///<
RNDIS_OID_GEN_PHYSICAL_MEDIUM = 0x00010202, ///< Physical media supported by the miniport driver (encoded)
//------------- 802.3 Objects (Ethernet) -------------//
RNDIS_OID_802_3_PERMANENT_ADDRESS = 0x01010101, ///< Permanent station address
RNDIS_OID_802_3_CURRENT_ADDRESS = 0x01010102, ///< Current station address
RNDIS_OID_802_3_MULTICAST_LIST = 0x01010103, ///< Current multicast address list
RNDIS_OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104, ///< Maximum size of multicast address list
} rndis_oid_type_t;
/// RNDIS Packet Filter Bits \ref RNDIS_OID_GEN_CURRENT_PACKET_FILTER.
typedef enum {
RNDIS_PACKET_TYPE_DIRECTED = 0x00000001, ///< Directed packets. Directed packets contain a destination address equal to the station address of the NIC.
RNDIS_PACKET_TYPE_MULTICAST = 0x00000002, ///< Multicast address packets sent to addresses in the multicast address list.
RNDIS_PACKET_TYPE_ALL_MULTICAST = 0x00000004, ///< All multicast address packets, not just the ones enumerated in the multicast address list.
RNDIS_PACKET_TYPE_BROADCAST = 0x00000008, ///< Broadcast packets.
RNDIS_PACKET_TYPE_SOURCE_ROUTING = 0x00000010, ///< All source routing packets. If the protocol driver sets this bit, the NDIS library attempts to act as a source routing bridge.
RNDIS_PACKET_TYPE_PROMISCUOUS = 0x00000020, ///< Specifies all packets regardless of whether VLAN filtering is enabled or not and whether the VLAN identifier matches or not.
RNDIS_PACKET_TYPE_SMT = 0x00000040, ///< SMT packets that an FDDI NIC receives.
RNDIS_PACKET_TYPE_ALL_LOCAL = 0x00000080, ///< All packets sent by installed protocols and all packets indicated by the NIC that is identified by a given NdisBindingHandle.
RNDIS_PACKET_TYPE_GROUP = 0x00001000, ///< Packets sent to the current group address.
RNDIS_PACKET_TYPE_ALL_FUNCTIONAL = 0x00002000, ///< All functional address packets, not just the ones in the current functional address.
RNDIS_PACKET_TYPE_FUNCTIONAL = 0x00004000, ///< Functional address packets sent to addresses included in the current functional address.
RNDIS_PACKET_TYPE_MAC_FRAME = 0x00008000, ///< NIC driver frames that a Token Ring NIC receives.
RNDIS_PACKET_TYPE_NO_LOCAL = 0x00010000,
} rndis_packet_filter_type_t;
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CDC_RNDIS_H_ */
/** @} */
/** @} */

View File

@ -1,295 +0,0 @@
/**************************************************************************/
/*!
@file cdc_rndis_host.c
@author hathach (tinyusb.org)
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2013, hathach (tinyusb.org)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This file is part of the tinyusb stack.
*/
/**************************************************************************/
#include "tusb_option.h"
#if (MODE_HOST_SUPPORTED && TUSB_CFG_HOST_CDC && TUSB_CFG_HOST_CDC_RNDIS)
#define _TINY_USB_SOURCE_FILE_
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "common/common.h"
#include "cdc_host.h"
#include "cdc_rndis_host.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
#define RNDIS_MSG_PAYLOAD_MAX (1024*4)
TUSB_CFG_ATTR_USBRAM static uint8_t msg_notification[TUSB_CFG_HOST_DEVICE_MAX][8];
TUSB_CFG_ATTR_USBRAM ATTR_ALIGNED(4) static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX];
STATIC_VAR rndish_data_t rndish_data[TUSB_CFG_HOST_DEVICE_MAX];
// TODO Microsoft requires message length for any get command must be at least 4096 bytes
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
static tusb_error_t rndis_body_subtask(void);
static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc,
uint8_t * p_mess, uint32_t mess_length,
uint8_t *p_response );
//--------------------------------------------------------------------+
// APPLICATION API
//--------------------------------------------------------------------+
tusb_error_t tusbh_cdc_rndis_get_mac_addr(uint8_t dev_addr, uint8_t mac_address[6])
{
ASSERT( tusbh_cdc_rndis_is_mounted(dev_addr), TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED);
ASSERT_PTR( mac_address, TUSB_ERROR_INVALID_PARA);
memcpy(mac_address, rndish_data[dev_addr-1].mac_address, 6);
return TUSB_ERROR_NONE;
}
//--------------------------------------------------------------------+
// IMPLEMENTATION
//--------------------------------------------------------------------+
// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper
// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with
// forever loop cannot have any return at all.
OSAL_TASK_FUNCTION(cdch_rndis_task) (void* p_task_para)
{
OSAL_TASK_LOOP_BEGIN
rndis_body_subtask();
OSAL_TASK_LOOP_END
}
static tusb_error_t rndis_body_subtask(void)
{
static uint8_t relative_addr;
OSAL_SUBTASK_BEGIN
for (relative_addr = 0; relative_addr < TUSB_CFG_HOST_DEVICE_MAX; relative_addr++)
{
}
osal_task_delay(100);
OSAL_SUBTASK_END
}
//--------------------------------------------------------------------+
// RNDIS-CDC Driver API
//--------------------------------------------------------------------+
void rndish_init(void)
{
memclr_(rndish_data, sizeof(rndish_data_t)*TUSB_CFG_HOST_DEVICE_MAX);
//------------- Task creation -------------//
//------------- semaphore creation for notificaiton pipe -------------//
for(uint8_t i=0; i<TUSB_CFG_HOST_DEVICE_MAX; i++)
{
rndish_data[i].sem_notification_hdl = osal_semaphore_create( OSAL_SEM_REF(rndish_data[i].semaphore_notification) );
}
}
void rndish_close(uint8_t dev_addr)
{
osal_semaphore_reset( rndish_data[dev_addr-1].sem_notification_hdl );
// memclr_(&rndish_data[dev_addr-1], sizeof(rndish_data_t)); TODO need to move semaphore & its handle out before memclr
}
static rndis_msg_initialize_t const msg_init =
{
.type = RNDIS_MSG_INITIALIZE,
.length = sizeof(rndis_msg_initialize_t),
.request_id = 1, // TODO should use some magic number
.major_version = 1,
.minor_version = 0,
.max_xfer_size = 0x4000 // TODO mimic windows
};
static rndis_msg_query_t const msg_query_permanent_addr =
{
.type = RNDIS_MSG_QUERY,
.length = sizeof(rndis_msg_query_t)+6,
.request_id = 1,
.oid = RNDIS_OID_802_3_PERMANENT_ADDRESS,
.buffer_length = 6,
.buffer_offset = 20,
};
static rndis_msg_set_t const msg_set_packet_filter =
{
.type = RNDIS_MSG_SET,
.length = sizeof(rndis_msg_set_t)+4,
.request_id = 1,
.oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
.buffer_length = 4,
.buffer_offset = 20,
};
tusb_error_t rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc)
{
tusb_error_t error;
OSAL_SUBTASK_BEGIN
//------------- Message Initialize -------------//
memcpy(msg_payload, &msg_init, sizeof(rndis_msg_initialize_t));
OSAL_SUBTASK_INVOKED_AND_WAIT(
send_message_get_response_subtask( dev_addr, p_cdc,
msg_payload, sizeof(rndis_msg_initialize_t),
msg_payload),
error
);
if ( TUSB_ERROR_NONE != error ) SUBTASK_EXIT(error);
// TODO currently not support multiple data packets per xfer
rndis_msg_initialize_cmplt_t * const p_init_cmpt = (rndis_msg_initialize_cmplt_t *) msg_payload;
SUBTASK_ASSERT(p_init_cmpt->type == RNDIS_MSG_INITIALIZE_CMPLT && p_init_cmpt->status == RNDIS_STATUS_SUCCESS &&
p_init_cmpt->max_packet_per_xfer == 1 && p_init_cmpt->max_xfer_size <= RNDIS_MSG_PAYLOAD_MAX);
rndish_data[dev_addr-1].max_xfer_size = p_init_cmpt->max_xfer_size;
//------------- Message Query 802.3 Permanent Address -------------//
memcpy(msg_payload, &msg_query_permanent_addr, sizeof(rndis_msg_query_t));
memclr_(msg_payload + sizeof(rndis_msg_query_t), 6); // 6 bytes for MAC address
OSAL_SUBTASK_INVOKED_AND_WAIT(
send_message_get_response_subtask( dev_addr, p_cdc,
msg_payload, sizeof(rndis_msg_query_t) + 6,
msg_payload),
error
);
if ( TUSB_ERROR_NONE != error ) SUBTASK_EXIT(error);
rndis_msg_query_cmplt_t * const p_query_cmpt = (rndis_msg_query_cmplt_t *) msg_payload;
SUBTASK_ASSERT(p_query_cmpt->type == RNDIS_MSG_QUERY_CMPLT && p_query_cmpt->status == RNDIS_STATUS_SUCCESS);
memcpy(rndish_data[dev_addr-1].mac_address, msg_payload + 8 + p_query_cmpt->buffer_offset, 6);
//------------- Set OID_GEN_CURRENT_PACKET_FILTER to (DIRECTED | MULTICAST | BROADCAST) -------------//
memcpy(msg_payload, &msg_set_packet_filter, sizeof(rndis_msg_set_t));
memclr_(msg_payload + sizeof(rndis_msg_set_t), 4); // 4 bytes for filter flags
((rndis_msg_set_t*) msg_payload)->oid_buffer[0] = (RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_MULTICAST | RNDIS_PACKET_TYPE_BROADCAST);
OSAL_SUBTASK_INVOKED_AND_WAIT(
send_message_get_response_subtask( dev_addr, p_cdc,
msg_payload, sizeof(rndis_msg_set_t) + 4,
msg_payload),
error
);
if ( TUSB_ERROR_NONE != error ) SUBTASK_EXIT(error);
rndis_msg_set_cmplt_t * const p_set_cmpt = (rndis_msg_set_cmplt_t *) msg_payload;
SUBTASK_ASSERT(p_set_cmpt->type == RNDIS_MSG_SET_CMPLT && p_set_cmpt->status == RNDIS_STATUS_SUCCESS);
tusbh_cdc_rndis_mounted_cb(dev_addr);
OSAL_SUBTASK_END
}
void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes)
{
if ( pipehandle_is_equal(pipe_hdl, p_cdc->pipe_notification) )
{
osal_semaphore_post( rndish_data[pipe_hdl.dev_addr-1].sem_notification_hdl );
}
}
//--------------------------------------------------------------------+
// INTERNAL & HELPER
//--------------------------------------------------------------------+
static tusb_error_t send_message_get_response_subtask( uint8_t dev_addr, cdch_data_t *p_cdc,
uint8_t * p_mess, uint32_t mess_length,
uint8_t *p_response)
{
tusb_error_t error;
OSAL_SUBTASK_BEGIN
//------------- Send RNDIS Control Message -------------//
OSAL_SUBTASK_INVOKED_AND_WAIT(
usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_INTERFACE),
CDC_REQUEST_SEND_ENCAPSULATED_COMMAND, 0, p_cdc->interface_number,
mess_length, p_mess),
error
);
if ( TUSB_ERROR_NONE != error ) SUBTASK_EXIT(error);
//------------- waiting for Response Available notification -------------//
(void) hcd_pipe_xfer(p_cdc->pipe_notification, msg_notification[dev_addr-1], 8, true);
osal_semaphore_wait(rndish_data[dev_addr-1].sem_notification_hdl, OSAL_TIMEOUT_NORMAL, &error);
if ( TUSB_ERROR_NONE != error ) SUBTASK_EXIT(error);
SUBTASK_ASSERT(msg_notification[dev_addr-1][0] == 1);
//------------- Get RNDIS Message Initialize Complete -------------//
OSAL_SUBTASK_INVOKED_AND_WAIT(
usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_INTERFACE),
CDC_REQUEST_GET_ENCAPSULATED_RESPONSE, 0, p_cdc->interface_number,
RNDIS_MSG_PAYLOAD_MAX, p_response),
error
);
if ( TUSB_ERROR_NONE != error ) SUBTASK_EXIT(error);
OSAL_SUBTASK_END
}
//static tusb_error_t send_process_msg_initialize_subtask(uint8_t dev_addr, cdch_data_t *p_cdc)
//{
// tusb_error_t error;
//
// OSAL_SUBTASK_BEGIN
//
// *((rndis_msg_initialize_t*) msg_payload) = (rndis_msg_initialize_t)
// {
// .type = RNDIS_MSG_INITIALIZE,
// .length = sizeof(rndis_msg_initialize_t),
// .request_id = 1, // TODO should use some magic number
// .major_version = 1,
// .minor_version = 0,
// .max_xfer_size = 0x4000 // TODO mimic windows
// };
//
//
//
// OSAL_SUBTASK_END
//}
#endif

View File

@ -1,79 +0,0 @@
/**************************************************************************/
/*!
@file cdc_rndis_host.h
@author hathach (tinyusb.org)
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2013, hathach (tinyusb.org)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This file is part of the tinyusb stack.
*/
/**************************************************************************/
/** \ingroup CDC_RNDIS
* \defgroup CDC_RNSID_Host Host
* @{ */
#ifndef _TUSB_CDC_RNDIS_HOST_H_
#define _TUSB_CDC_RNDIS_HOST_H_
#include "common/common.h"
#include "host/usbh.h"
#include "cdc_rndis.h"
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// RNDIS-CDC Driver API
//--------------------------------------------------------------------+
#ifdef _TINY_USB_SOURCE_FILE_
typedef struct {
OSAL_SEM_DEF(semaphore_notification);
osal_semaphore_handle_t sem_notification_hdl; // used to wait on notification pipe
uint32_t max_xfer_size; // got from device's msg initialize complete
uint8_t mac_address[6];
}rndish_data_t;
void rndish_init(void);
tusb_error_t rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc) ATTR_WARN_UNUSED_RESULT;
void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes);
void rndish_close(uint8_t dev_addr);
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CDC_RNDIS_HOST_H_ */
/** @} */

View File

@ -1,13 +0,0 @@
This includes un-modified versions of LWIP v1.4.1 and the LWIP
contrib files v1.4.1. Note individual copies of the files in
the contrib area may also be located in the LWIP example folders.
The original files can be downloaded at:
http://savannah.nongnu.org/projects/lwip
lwIP is licenced under the BSD licence. See the individual files
or the website for licensing information.
Copyright (c) 2001-2004 Swedish Institute of Computer Science.
All rights reserved.

View File

@ -1,99 +0,0 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __CC_H__
#define __CC_H__
#include <stdint.h>
#include "common/assertion.h"
/* Types based on stdint.h */
typedef uint8_t u8_t;
typedef int8_t s8_t;
typedef uint16_t u16_t;
typedef int16_t s16_t;
typedef uint32_t u32_t;
typedef int32_t s32_t;
typedef uintptr_t mem_ptr_t;
/* Define (sn)printf formatters for these lwIP types */
#define U16_F "hu"
#define S16_F "hd"
#define X16_F "hx"
#define U32_F "lu"
#define S32_F "ld"
#define X32_F "lx"
#define SZT_F "uz"
/* ARM/LPC17xx is little endian only */
#define BYTE_ORDER LITTLE_ENDIAN
/* Use LWIP error codes */
#define LWIP_PROVIDE_ERRNO
#if defined(__arm__) && defined(__ARMCC_VERSION)
/* Keil uVision4 tools */
#define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(fld) fld
#define ALIGNED(n) __align(n)
#elif defined (__IAR_SYSTEMS_ICC__)
/* IAR Embedded Workbench tools */
#define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(fld) fld
// #define PACK_STRUCT_USE_INCLUDES
#error NEEDS ALIGNED // FIXME TBD
#else
/* GCC tools (CodeSourcery) */
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(fld) fld
#define ALIGNED(n) __attribute__((aligned (n)))
#endif
/* Used with IP headers only */
#define LWIP_CHKSUM_ALGORITHM 1
#ifdef LWIP_DEBUG
/* Plaform specific diagnostic output */
#define LWIP_PLATFORM_DIAG(vars) printf(vars)
#define LWIP_PLATFORM_ASSERT(flag) hal_debugger_breakpoint()
#else
#define LWIP_PLATFORM_DIAG(msg) { ; }
#define LWIP_PLATFORM_ASSERT(flag) hal_debugger_breakpoint()
#endif
#endif /* __CC_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,51 +0,0 @@
/**********************************************************************
* $Id$ lpc18xx_43xx_emac.h 2011-11-20
*//**
* @file lpc18xx_43xx_emac.h
* @brief LPC18xx/43xx ethernet driver header file for LWIP
* @version 1.0
* @date 20. Nov. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#ifndef __LPC18XX_43XX_EMAC_H
#define __LPC18XX_43XX_EMAC_H
#include "lwip/opt.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* These functions are only visible when not using an RTOS */
#if NO_SYS == 1
void lpc_enetif_input(struct netif *netif);
s32_t lpc_tx_ready(struct netif *netif);
s32_t lpc_rx_queue(struct netif *netif);
void lpc_tx_reclaim(struct netif *netif);
#endif
err_t lpc_enetif_init(struct netif *netif);
#ifdef __cplusplus
}
#endif
#endif /* __LPC18XX_43XX_EMAC_H */

View File

@ -1,359 +0,0 @@
/**********************************************************************
* $Id$ lpc43xx_mac.h 2011-06-02
*//**
* @file lpc43xx_mac.h
* @brief Contains all functions support for the MAC peripheral
* @version 1.0
* @date 02. June. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors<EFBFBD>
* relevant copyright in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
**********************************************************************/
#ifndef __lpc18xx_lpc43xx_mac_regs_H_
#define __lpc18xx_lpc43xx_mac_regs_H_
#include "lpc_types.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** @defgroup lwip18xx_43xx_emac_regs lpc18xx/43xx EMAC registers
* @ingroup lwip18xx_43xx_emac_DRIVER
*
* Variants of these constants and macros exist in the lpc18xx or
* lpc43xx files. These are signficantly shorter and make the code
* easier to read.
*
* @{
*/
/* MAC_CONFIG register bit defines */
#define MAC_CFG_RE (1 << 2) /*!< Receiver enable */
#define MAC_CFG_TE (1 << 3) /*!< Transmitter Enable */
#define MAC_CFG_DF (1 << 4) /*!< Deferral Check */
#define MAC_CFG_BL(n) ((n) << 5) /*!< Back-Off Limit */
#define MAC_CFG_ACS (1 << 7) /*!< Automatic Pad/CRC Stripping */
#define MAC_CFG_LUD (1 << 8) /*!< Link Up/Down, 1 = up */
#define MAC_CFG_DR (1 << 9) /*!< Disable Retry */
#define MAC_CFG_IPC (1 << 10) /*!< Checksum Offload */
#define MAC_CFG_DM (1 << 11) /*!< Duplex Mode, 1 = full, 0 = half */
#define MAC_CFG_LM (1 << 12) /*!< Loopback Mode */
#define MAC_CFG_DO (1 << 13) /*!< Disable Receive Own */
#define MAC_CFG_FES (1 << 14) /*!< Speed, 1 = 100Mbps, 0 = 10Mbos */
#define MAC_CFG_PS (1 << 15) /*!< Port select, must always be 1 */
#define MAC_CFG_DCRS (1 << 16) /*!< Disable carrier sense during transmission */
#define MAC_CFG_IFG(n) ((n) << 17) /*!< Inter-frame gap, 40..96, n incs by 8 */
#define MAC_CFG_JE (1 << 20) /*!< Jumbo Frame Enable */
#define MAC_CFG_JD (1 << 22) /*!< Jabber Disable */
#define MAC_CFG_WD (1 << 23) /*!< Watchdog Disable */
/* MAC_FRAME_FILTER register bit defines */
#define MAC_FF_PR (1 << 0) /*!< Promiscuous Mode */
#define MAC_FF_DAIF (1 << 3) /*!< DA Inverse Filtering */
#define MAC_FF_PM (1 << 4) /*!< Pass All Multicast */
#define MAC_FF_DBF (1 << 5) /*!< Disable Broadcast Frames */
#define MAC_FF_PCF(n) ((n) << 6) /*!< Pass Control Frames, n = see user manual */
#define MAC_FF_SAIF (1 << 8) /*!< SA Inverse Filtering */
#define MAC_FF_SAF (1 << 9) /*!< Source Address Filter Enable */
#define MAC_FF_RA (1UL << 31) /*!< Receive all */
/* MAC_MII_ADDR register bit defines */
#define MAC_MIIA_GB (1 << 0) /*!< MII busy */
#define MAC_MIIA_W (1 << 1) /*!< MII write */
#define MAC_MIIA_CR(n) ((n) << 2) /*!< CSR clock range, n = see manual */
#define MAC_MIIA_GR(n) ((n) << 6) /*!< MII register. n = 0..31 */
#define MAC_MIIA_PA(n) ((n) << 11) /*!< Physical layer address, n = 0..31 */
/* MAC_MII_DATA register bit defines */
#define MAC_MIID_GDMSK (0xFFFF) /*!< MII data mask */
/* MAC_FLOW_CONTROL register bit defines */
#define MAC_FC_FCB (1 << 0) /*!< Flow Control Busy/Backpressure Activate */
#define MAC_FC_TFE (1 << 1) /*!< Transmit Flow Control Enable */
#define MAC_FC_RFE (1 << 2) /*!< Receive Flow Control Enable */
#define MAC_FC_UP (1 << 3) /*!< Unicast Pause Frame Detect */
#define MAC_FC_PLT(n) ((n) << 4) /*!< Pause Low Threshold, n = see manual */
#define MAC_FC_DZPQ (1 << 7) /*!< Disable Zero-Quanta Pause */
#define MAC_FC_PT(n) ((n) << 16) /*!< Pause time */
/* MAC_VLAN_TAG register bit defines */
#define MAC_VT_VL(n) ((n) << 0) /*!< VLAN Tag Identifier for Receive Frames */
#define MAC_VT_ETC (1 << 7) /*!< Enable 12-Bit VLAN Tag Comparison */
/* MAC_DEBUG register bit defines */
/* MAC_PMT_CTRL_STAT register bit defines */
#define MAC_PMT_PD (1 << 0) /*!< Power-down */
#define MAC_PMT_MPE (1 << 1) /*!< Magic packet enable */
#define MAC_PMT_WFE (1 << 2) /*!< Wake-up frame enable */
#define MAC_PMT_MPR (1 << 5) /*!< Magic Packet Received */
#define MAC_PMT_WFR (1 << 6) /*!< Wake-up Frame Received */
#define MAC_PMT_GU (1 << 9) /*!< Global Unicast */
#define MAC_PMT_WFFRPR (1UL << 31) /*!< Wake-up Frame Filter Register Pointer Reset */
/* MAC_INTR_MASK register bit defines */
#define MAC_IM_PMT (1 << 3) /*!< PMT Interrupt Mask */
/* MAC_ADDR0_HIGH register bit defines */
#define MAC_ADRH_MO (1UL << 31) /*!< Always 1 when writing register */
/* MAC_ADDR0_HIGH register bit defines */
#define MAC_ADRH_MO (1UL << 31) /*!< Always 1 when writing register */
/* MAC_TIMESTAMP register bit defines */
#define MAC_TS_TSENA (1 << 0) /*!< Time Stamp Enable */
#define MAC_TS_TSCFUP (1 << 1) /*!< Time Stamp Fine or Coarse Update */
#define MAC_TS_TSINIT (1 << 2) /*!< Time Stamp Initialize */
#define MAC_TS_TSUPDT (1 << 3) /*!< Time Stamp Update */
#define MAC_TS_TSTRIG (1 << 4) /*!< Time Stamp Interrupt Trigger Enable */
#define MAC_TS_TSADDR (1 << 5) /*!< Addend Reg Update */
#define MAC_TS_TSENAL (1 << 8) /*!< Enable Time Stamp for All Frames */
#define MAC_TS_TSCTRL (1 << 9) /*!< Time Stamp Digital or Binary rollover control */
#define MAC_TS_TSVER2 (1 << 10) /*!< Enable PTP packet snooping for version 2 format */
#define MAC_TS_TSIPENA (1 << 11) /*!< Enable Time Stamp Snapshot for PTP over Ethernet frames */
#define MAC_TS_TSIPV6E (1 << 12) /*!< Enable Time Stamp Snapshot for IPv6 frames */
#define MAC_TS_TSIPV4E (1 << 13) /*!< Enable Time Stamp Snapshot for IPv4 frames */
#define MAC_TS_TSEVNT (1 << 14) /*!< Enable Time Stamp Snapshot for Event Messages */
#define MAC_TS_TSMSTR (1 << 15) /*!< Enable Snapshot for Messages Relevant to Master */
#define MAC_TS_TSCLKT(n) ((n) << 16) /*!< Select the type of clock node, n = see menual */
#define MAC_TS_TSENMA (1 << 18) /*!< Enable MAC address for PTP frame filtering */
/* DMA_BUS_MODE register bit defines */
#define DMA_BM_SWR (1 << 0) /*!< Software reset */
#define DMA_BM_DA (1 << 1) /*!< DMA arbitration scheme, 1 = TX has priority over TX */
#define DMA_BM_DSL(n) ((n) << 2) /*!< Descriptor skip length, n = see manual */
#define DMA_BM_ATDS (1 << 7) /*!< Alternate (Enhanced) descriptor size */
#define DMA_BM_PBL(n) ((n) << 8) /*!< Programmable burst length, n = see manual */
#define DMA_BM_PR(n) ((n) << 14) /*!< Rx-to-Tx priority ratio, n = see manual */
#define DMA_BM_FB (1 << 16) /*!< Fixed burst */
#define DMA_BM_RPBL(n) ((n) << 17) /*!< RxDMA PBL, n = see manual */
#define DMA_BM_USP (1 << 23) /*!< Use separate PBL */
#define DMA_BM_PBL8X (1 << 24) /*!< 8 x PBL mode */
#define DMA_BM_AAL (1 << 25) /*!< Address-aligned beats */
#define DMA_BM_MB (1 << 26) /*!< Mixed burst */
#define DMA_BM_TXPR (1 << 27) /*!< Transmit DMA has higher priority than receive DMA */
/* DMA_STAT register bit defines */
#define DMA_ST_TI (1 << 0) /*!< Transmit interrupt */
#define DMA_ST_TPS (1 << 1) /*!< Transmit process stopped */
#define DMA_ST_TU (1 << 2) /*!< Transmit buffer unavailable */
#define DMA_ST_TJT (1 << 3) /*!< Transmit jabber timeout */
#define DMA_ST_OVF (1 << 4) /*!< Receive overflow */
#define DMA_ST_UNF (1 << 5) /*!< Transmit underflow */
#define DMA_ST_RI (1 << 6) /*!< Receive interrupt */
#define DMA_ST_RU (1 << 7) /*!< Receive buffer unavailable */
#define DMA_ST_RPS (1 << 8) /*!< Received process stopped */
#define DMA_ST_RWT (1 << 9) /*!< Receive watchdog timeout */
#define DMA_ST_ETI (1 << 10) /*!< Early transmit interrupt */
#define DMA_ST_FBI (1 << 13) /*!< Fatal bus error interrupt */
#define DMA_ST_ERI (1 << 14) /*!< Early receive interrupt */
#define DMA_ST_AIE (1 << 15) /*!< Abnormal interrupt summary */
#define DMA_ST_NIS (1 << 16) /*!< Normal interrupt summary */
#define DMA_ST_ALL (0x1E7FF) /*!< All interrupts */
/* DMA_OP_MODE register bit defines */
#define DMA_OM_SR (1 << 1) /*!< Start/stop receive */
#define DMA_OM_OSF (1 << 2) /*!< Operate on second frame */
#define DMA_OM_RTC(n) ((n) << 3) /*!< Receive threshold control, n = see manual */
#define DMA_OM_FUF (1 << 6) /*!< Forward undersized good frames */
#define DMA_OM_FEF (1 << 7) /*!< Forward error frames */
#define DMA_OM_ST (1 << 13) /*!< Start/Stop Transmission Command */
#define DMA_OM_TTC(n) ((n) << 14) /*!< Transmit threshold control, n = see manual */
#define DMA_OM_FTF (1 << 20) /*!< Flush transmit FIFO */
#define DMA_OM_TSF (1 << 21) /*!< Transmit store and forward */
#define DMA_OM_DFF (1 << 24) /*!< Disable flushing of received frames */
#define DMA_OM_RSF (1 << 25) /*!< Receive store and forward */
#define DMA_OM_DT (1 << 26) /*!< Disable Dropping of TCP/IP Checksum Error Frames */
/* DMA_INT_EN register bit defines */
#define DMA_IE_TIE (1 << 0) /*!< Transmit interrupt enable */
#define DMA_IE_TSE (1 << 1) /*!< Transmit stopped enable */
#define DMA_IE_TUE (1 << 2) /*!< Transmit buffer unavailable enable */
#define DMA_IE_TJE (1 << 3) /*!< Transmit jabber timeout enable */
#define DMA_IE_OVE (1 << 4) /*!< Overflow interrupt enable */
#define DMA_IE_UNE (1 << 5) /*!< Underflow interrupt enable */
#define DMA_IE_RIE (1 << 6) /*!< Receive interrupt enable */
#define DMA_IE_RUE (1 << 7) /*!< Receive buffer unavailable enable */
#define DMA_IE_RSE (1 << 8) /*!< Received stopped enable */
#define DMA_IE_RWE (1 << 9) /*!< Receive watchdog timeout enable */
#define DMA_IE_ETE (1 << 10) /*!< Early transmit interrupt enable */
#define DMA_IE_FBE (1 << 13) /*!< Fatal bus error enable */
#define DMA_IE_ERE (1 << 14) /*!< Early receive interrupt enable */
#define DMA_IE_AIE (1 << 15) /*!< Abnormal interrupt summary enable */
#define DMA_IE_NIE (1 << 16) /*!< Normal interrupt summary enable */
/* DMA_MFRM_BUFOF register bit defines */
#define DMA_MFRM_FMCMSK (0xFFFF) /*!< Number of frames missed mask */
#define DMA_MFRM_OC (1 << 16) /*!< Overflow bit for missed frame counter */
#define DMA_MFRM_FMA(n) (((n) & 0x0FFE0000) >> 17) /*!< Number of frames missed by the application mask/shift */
#define DMA_MFRM_OF (1 << 28) /*!< Overflow bit for FIFO overflow counter */
/* Common TRAN_DESC_T and TRAN_DESC_ENH_T CTRLSTAT field bit defines */
#define TDES_DB (1 << 0) /*!< Deferred Bit */
#define TDES_UF (1 << 1) /*!< Underflow Error */
#define TDES_ED (1 << 2) /*!< Excessive Deferral */
#define TDES_CCMSK(n) (((n) & 0x000000F0) >> 3) /*!< CC: Collision Count (Status field) mask and shift */
#define TDES_VF (1 << 7) /*!< VLAN Frame */
#define TDES_EC (1 << 8) /*!< Excessive Collision */
#define TDES_LC (1 << 9) /*!< Late Collision */
#define TDES_NC (1 << 10) /*!< No Carrier */
#define TDES_LCAR (1 << 11) /*!< Loss of Carrier */
#define TDES_IPE (1 << 12) /*!< IP Payload Error */
#define TDES_FF (1 << 13) /*!< Frame Flushed */
#define TDES_JT (1 << 14) /*!< Jabber Timeout */
#define TDES_ES (1 << 15) /*!< Error Summary */
#define TDES_IHE (1 << 16) /*!< IP Header Error */
#define TDES_TTSS (1 << 17) /*!< Transmit Timestamp Status */
#define TDES_OWN (1UL << 31) /*!< Own Bit */
/* TRAN_DESC_ENH_T only CTRLSTAT field bit defines */
#define TDES_ENH_IC (1UL << 30) /*!< Interrupt on Completion, enhanced descriptor */
#define TDES_ENH_LS (1 << 29) /*!< Last Segment, enhanced descriptor */
#define TDES_ENH_FS (1 << 28) /*!< First Segment, enhanced descriptor */
#define TDES_ENH_DC (1 << 27) /*!< Disable CRC, enhanced descriptor */
#define TDES_ENH_DP (1 << 26) /*!< Disable Pad, enhanced descriptor */
#define TDES_ENH_TTSE (1 << 25) /*!< Transmit Timestamp Enable, enhanced descriptor */
#define TDES_ENH_CIC(n) ((n) << 22) /*!< Checksum Insertion Control, enhanced descriptor */
#define TDES_ENH_TER (1 << 21) /*!< Transmit End of Ring, enhanced descriptor */
#define TDES_ENH_TCH (1 << 20) /*!< Second Address Chained, enhanced descriptor */
/* TRAN_DESC_T only BSIZE field bit defines */
#define TDES_NORM_IC (1UL << 31) /*!< Interrupt on Completion, normal descriptor */
#define TDES_NORM_FS (1 << 30) /*!< First Segment, normal descriptor */
#define TDES_NORM_LS (1 << 29) /*!< Last Segment, normal descriptor */
#define TDES_NORM_CIC(n) ((n) << 27) /*!< Checksum Insertion Control, normal descriptor */
#define TDES_NORM_DC (1 << 26) /*!< Disable CRC, normal descriptor */
#define TDES_NORM_TER (1 << 25) /*!< Transmit End of Ring, normal descriptor */
#define TDES_NORM_TCH (1 << 24) /*!< Second Address Chained, normal descriptor */
#define TDES_NORM_DP (1 << 23) /*!< Disable Pad, normal descriptor */
#define TDES_NORM_TTSE (1 << 22) /*!< Transmit Timestamp Enable, normal descriptor */
#define TDES_NORM_BS2(n) (((n) & 0x3FF) << 11) /*!< Buffer 2 size, normal descriptor */
#define TDES_NORM_BS1(n) (((n) & 0x3FF) << 0) /*!< Buffer 1 size, normal descriptor */
/* TRAN_DESC_ENH_T only BSIZE field bit defines */
#define TDES_ENH_BS2(n) (((n) & 0xFFF) << 16) /*!< Buffer 2 size, enhanced descriptor */
#define TDES_ENH_BS1(n) (((n) & 0xFFF) << 0) /*!< Buffer 1 size, enhanced descriptor */
/* Common REC_DESC_T and REC_DESC_ENH_T STATUS field bit defines */
#define RDES_ESA (1 << 0) /*!< Extended Status Available/Rx MAC Address */
#define RDES_CE (1 << 1) /*!< CRC Error */
#define RDES_DRE (1 << 2) /*!< Dribble Bit Error */
#define RDES_RE (1 << 3) /*!< Receive Error */
#define RDES_RWT (1 << 4) /*!< Receive Watchdog Timeout */
#define RDES_FT (1 << 5) /*!< Frame Type */
#define RDES_LC (1 << 6) /*!< Late Collision */
#define RDES_TSA (1 << 7) /*!< Timestamp Available/IP Checksum Error (Type1) /Giant Frame */
#define RDES_LS (1 << 8) /*!< Last Descriptor */
#define RDES_FS (1 << 9) /*!< First Descriptor */
#define RDES_VLAN (1 << 10) /*!< VLAN Tag */
#define RDES_OE (1 << 11) /*!< Overflow Error */
#define RDES_LE (1 << 12) /*!< Length Error */
#define RDES_SAF (1 << 13) /*!< Source Address Filter Fail */
#define RDES_DE (1 << 14) /*!< Descriptor Error */
#define RDES_ES (1 << 15) /*!< ES: Error Summary */
#define RDES_FLMSK(n) (((n) & 0x3FFF0000) >> 16) /*!< Frame Length mask and shift */
#define RDES_AFM (1 << 30) /*!< Destination Address Filter Fail */
#define RDES_OWN (1UL << 31) /*!< Own Bit */
/* Common REC_DESC_T and REC_DESC_ENH_T CTRL field bit defines */
#define RDES_DINT (1UL << 31) /*!< Disable interrupt on completion */
/* REC_DESC_T pnly CTRL field bit defines */
#define RDES_NORM_RER (1 << 25) /*!< Receive End of Ring, normal descriptor */
#define RDES_NORM_RCH (1 << 24) /*!< Second Address Chained, normal descriptor */
#define RDES_NORM_BS2(n) (((n) & 0x3FF) << 11) /*!< Buffer 2 size, normal descriptor */
#define RDES_NORM_BS1(n) (((n) & 0x3FF) << 0) /*!< Buffer 1 size, normal descriptor */
/* REC_DESC_ENH_T only CTRL field bit defines */
#define RDES_ENH_RER (1 << 15) /*!< Receive End of Ring, enhanced descriptor */
#define RDES_ENH_RCH (1 << 14) /*!< Second Address Chained, enhanced descriptor */
#define RDES_ENH_BS2(n) (((n) & 0xFFF) << 16) /*!< Buffer 2 size, enhanced descriptor */
#define RDES_ENH_BS1(n) (((n) & 0xFFF) << 0) /*!< Buffer 1 size, enhanced descriptor */
/* REC_DESC_ENH_T only EXTSTAT field bit defines */
#define RDES_ENH_IPPL(n) (((n) & 0x7) >> 2) /*!< IP Payload Type mask and shift, enhanced descripto */
#define RDES_ENH_IPHE (1 << 3) /*!< IP Header Error, enhanced descripto */
#define RDES_ENH_IPPLE (1 << 4) /*!< IP Payload Error, enhanced descripto */
#define RDES_ENH_IPCSB (1 << 5) /*!< IP Checksum Bypassed, enhanced descripto */
#define RDES_ENH_IPV4 (1 << 6) /*!< IPv4 Packet Received, enhanced descripto */
#define RDES_ENH_IPV6 (1 << 7) /*!< IPv6 Packet Received, enhanced descripto */
#define RDES_ENH_MTMSK(n) (((n) & 0xF) >> 8) /*!< Message Type mask and shift, enhanced descripto */
/* Maximum size of an ethernet buffer */
#define EMAC_ETH_MAX_FLEN (1536)
/* Structure of a transmit descriptor (without timestamp) */
typedef struct
{
__IO uint32_t CTRLSTAT; /*!< TDES control and status word */
__IO uint32_t BSIZE; /*!< Buffer 1/2 byte counts */
__IO uint32_t B1ADD; /*!< Buffer 1 address */
__IO uint32_t B2ADD; /*!< Buffer 2 or next descriptor address */
} TRAN_DESC_T;
/* Structure of a enhanced transmit descriptor (with timestamp) */
typedef struct
{
__IO uint32_t CTRLSTAT; /*!< TDES control and status word */
__IO uint32_t BSIZE; /*!< Buffer 1/2 byte counts */
__IO uint32_t B1ADD; /*!< Buffer 1 address */
__IO uint32_t B2ADD; /*!< Buffer 2 or next descriptor address */
__IO uint32_t TDES4; /*!< Reserved */
__IO uint32_t TDES5; /*!< Reserved */
__IO uint32_t TTSL; /*!< Timestamp value low */
__IO uint32_t TTSH; /*!< Timestamp value high */
} TRAN_DESC_ENH_T;
/* Structure of a receive descriptor (without timestamp) */
typedef struct
{
__IO uint32_t STATUS; /*!< RDES status word */
__IO uint32_t CTRL; /*!< Buffer 1/2 byte counts and control */
__IO uint32_t B1ADD; /*!< Buffer 1 address */
__IO uint32_t B2ADD; /*!< Buffer 2 or next descriptor address */
} REC_DESC_T;
/* Structure of a enhanced receive descriptor (with timestamp) */
typedef struct
{
__IO uint32_t STATUS; /*!< RDES status word */
__IO uint32_t CTRL; /*!< Buffer 1/2 byte counts */
__IO uint32_t B1ADD; /*!< Buffer 1 address */
__IO uint32_t B2ADD; /*!< Buffer 2 or next descriptor address */
__IO uint32_t EXTSTAT; /*!< Extended Status */
__IO uint32_t RDES5; /*!< Reserved */
__IO uint32_t RTSL; /*!< Timestamp value low */
__IO uint32_t RTSH; /*!< Timestamp value high */
} REC_DESC_ENH_T;
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __lpc18xx_lpc43xx_mac_regs_H_ */

View File

@ -1,95 +0,0 @@
/**********************************************************************
* $Id$ lpc18xx_43xx_systick_arch.c 2011-11-20
*//**
* @file lpc18xx_43xx_systick_arch.c
* @brief Setups up the system tick to generate a reference timebase
* @version 1.0
* @date 20. Nov. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#include "lwip/opt.h"
#if NO_SYS == 1
#ifdef LPC43XX
#include "lpc43xx_cgu.h"
#else
#ifdef LPC43XX
#include "lpc18xx_cgu.h"
#else
#error LPC18XX or LPC43XX for target system not defined!
#endif
#endif
#include "lpc_arch.h"
/** @defgroup LPC18xx_43xx_systick LPC18xx_43xx LWIP (standalone) timer base
* @ingroup LPC18xx_43xx
* @{
*/
/* Saved reference period */
static uint32_t saved_period;
/* Saved total time in mS since timer was enabled */
static volatile u32_t systick_timems;
/* Enable systick rate and interrupt */
void SysTick_Enable(uint32_t period)
{
saved_period = period;
SysTick_Config(CGU_GetPCLKFrequency(CGU_PERIPHERAL_M4CORE) / (1000 / period));
}
/* Disable systick */
void SysTick_Disable(void)
{
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
/** \brief SysTick IRQ handler and timebase management
*
* This function keeps a timebase for the sysTick that can be
* used for other functions.
*/
void SysTick_Handler(void)
{
/* Increment tick count */
systick_timems += saved_period;
}
/* Get the current systick time in milliSeconds */
uint32_t SysTick_GetMS(void)
{
return systick_timems;
}
/* Delay for the specified number of milliSeconds */
void msDelay(uint32_t ms)
{
uint32_t to = ms + systick_timems;
while (to > systick_timems);
}
#endif
/**
* @}
*/
/* --------------------------------- End Of File ------------------------------ */

View File

@ -1,86 +0,0 @@
/**********************************************************************
* $Id$ lpc_arch.h 2011-11-20
*//**
* @file lpc_arch.h
* @brief Architecture specific functions used with the LWIP examples
* @version 1.0
* @date 20. Nov. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#ifndef __LPC_ARCH_H
#define __LPC_ARCH_H
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** @ingroup lpc_arch
*/
#if NO_SYS == 1
/** \brief Enable systick rate and interrupt
*
* This enables the systick interrupt and sets up the systick rate. This
* function is only used in standalone systems.
*
* \param[in] period Period of the systick clock
*/
void SysTick_Enable(uint32_t period);
/** \brief Disable systick
*
* This disables the systick interrupt. This function is only used in
* standalone systems.
*/
void SysTick_Disable(void);
/** \brief Get the current systick time in milliSeconds
*
* Returns the current systick time in milliSeconds. This function is only
* used in standalone systems.
*
* /returns current systick time in milliSeconds
*/
uint32_t SysTick_GetMS(void);
#endif
/** \brief Delay for the specified number of milliSeconds
*
* For standalone systems. This function will block for the specified
* number of milliSconds. For RTOS based systems, this function will delay
* the task by the specified number of milliSeconds.
*
* \param[in] ms Time in milliSeconds to delay
*/
void msDelay(uint32_t ms);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __LPC_ARCH_H */
/* --------------------------------- End Of File ------------------------------ */

View File

@ -1,38 +0,0 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __PERF_H__
#define __PERF_H__
#define PERF_START /* null definition */
#define PERF_STOP(x) /* null definition */
#endif /* __PERF_H__ */

View File

@ -1,59 +0,0 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __ARCH_SYS_ARCH_H__
#define __ARCH_SYS_ARCH_H__
#include "lwip/opt.h"
#if NO_SYS == 0
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#define SYS_MBOX_NULL ( ( xQueueHandle ) NULL )
#define SYS_SEM_NULL ( ( xSemaphoreHandle ) NULL )
#define SYS_DEFAULT_THREAD_STACK_DEPTH configMINIMAL_STACK_SIZE
typedef xSemaphoreHandle sys_sem_t;
typedef xSemaphoreHandle sys_mutex_t;
typedef xQueueHandle sys_mbox_t;
typedef xTaskHandle sys_thread_t;
typedef int sys_prot_t;
#define sys_mbox_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE )
#define sys_mbox_set_invalid( x ) ( ( *x ) = NULL )
#define sys_sem_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE )
#define sys_sem_set_invalid( x ) ( ( *x ) = NULL )
#endif
#endif /* __ARCH_SYS_ARCH_H__ */

View File

@ -1,551 +0,0 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/* lwIP includes. */
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "lpc_arch.h"
#include <stdio.h>
#if NO_SYS==1
/* Returns the current time in mS. This is needed for the LWIP timers */
//u32_t sys_now(void)
//{
// return (u32_t) SysTick_GetMS();
//}
#else
/* ------------------------ System architecture includes ----------------------------- */
#include "arch/sys_arch.h"
/* ------------------------ lwIP includes --------------------------------- */
#include "lwip/opt.h"
#include "lwip/stats.h"
/*---------------------------------------------------------------------------*
* Routine: sys_mbox_new
*---------------------------------------------------------------------------*
* Description:
* Creates a new mailbox
* Inputs:
* int size -- Size of elements in the mailbox
* Outputs:
* sys_mbox_t -- Handle to new mailbox
*---------------------------------------------------------------------------*/
err_t sys_mbox_new( sys_mbox_t *pxMailBox, int iSize )
{
err_t xReturn = ERR_MEM;
*pxMailBox = xQueueCreate( iSize, sizeof( void * ) );
if( *pxMailBox != NULL )
{
xReturn = ERR_OK;
SYS_STATS_INC_USED( mbox );
}
return xReturn;
}
/*---------------------------------------------------------------------------*
* Routine: sys_mbox_free
*---------------------------------------------------------------------------*
* Description:
* Deallocates a mailbox. If there are messages still present in the
* mailbox when the mailbox is deallocated, it is an indication of a
* programming error in lwIP and the developer should be notified.
* Inputs:
* sys_mbox_t mbox -- Handle of mailbox
* Outputs:
* sys_mbox_t -- Handle to new mailbox
*---------------------------------------------------------------------------*/
void sys_mbox_free( sys_mbox_t *pxMailBox )
{
unsigned long ulMessagesWaiting;
ulMessagesWaiting = uxQueueMessagesWaiting( *pxMailBox );
configASSERT( ( ulMessagesWaiting == 0 ) );
#if SYS_STATS
{
if( ulMessagesWaiting != 0UL )
{
SYS_STATS_INC( mbox.err );
}
SYS_STATS_DEC( mbox.used );
}
#endif /* SYS_STATS */
vQueueDelete( *pxMailBox );
}
/*---------------------------------------------------------------------------*
* Routine: sys_mbox_post
*---------------------------------------------------------------------------*
* Description:
* Post the "msg" to the mailbox.
* Inputs:
* sys_mbox_t mbox -- Handle of mailbox
* void *data -- Pointer to data to post
*---------------------------------------------------------------------------*/
void sys_mbox_post( sys_mbox_t *pxMailBox, void *pxMessageToPost )
{
while( xQueueSendToBack( *pxMailBox, &pxMessageToPost, portMAX_DELAY ) != pdTRUE );
}
/*---------------------------------------------------------------------------*
* Routine: sys_mbox_trypost
*---------------------------------------------------------------------------*
* Description:
* Try to post the "msg" to the mailbox. Returns immediately with
* error if cannot.
* Inputs:
* sys_mbox_t mbox -- Handle of mailbox
* void *msg -- Pointer to data to post
* Outputs:
* err_t -- ERR_OK if message posted, else ERR_MEM
* if not.
*---------------------------------------------------------------------------*/
err_t sys_mbox_trypost( sys_mbox_t *pxMailBox, void *pxMessageToPost )
{
err_t xReturn;
if( xQueueSend( *pxMailBox, &pxMessageToPost, 0UL ) == pdPASS )
{
xReturn = ERR_OK;
}
else
{
/* The queue was already full. */
xReturn = ERR_MEM;
SYS_STATS_INC( mbox.err );
}
return xReturn;
}
/*---------------------------------------------------------------------------*
* Routine: sys_arch_mbox_fetch
*---------------------------------------------------------------------------*
* Description:
* Blocks the thread until a message arrives in the mailbox, but does
* not block the thread longer than "timeout" milliseconds (similar to
* the sys_arch_sem_wait() function). The "msg" argument is a result
* parameter that is set by the function (i.e., by doing "*msg =
* ptr"). The "msg" parameter maybe NULL to indicate that the message
* should be dropped.
*
* The return values are the same as for the sys_arch_sem_wait() function:
* Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
* timeout.
*
* Note that a function with a similar name, sys_mbox_fetch(), is
* implemented by lwIP.
* Inputs:
* sys_mbox_t mbox -- Handle of mailbox
* void **msg -- Pointer to pointer to msg received
* u32_t timeout -- Number of milliseconds until timeout
* Outputs:
* u32_t -- SYS_ARCH_TIMEOUT if timeout, else number
* of milliseconds until received.
*---------------------------------------------------------------------------*/
u32_t sys_arch_mbox_fetch( sys_mbox_t *pxMailBox, void **ppvBuffer, u32_t ulTimeOut )
{
void *pvDummy;
portTickType xStartTime, xEndTime, xElapsed;
unsigned long ulReturn;
xStartTime = xTaskGetTickCount();
if( NULL == ppvBuffer )
{
ppvBuffer = &pvDummy;
}
if( ulTimeOut != 0UL )
{
if( pdTRUE == xQueueReceive( *pxMailBox, &( *ppvBuffer ), ulTimeOut/ portTICK_RATE_MS ) )
{
xEndTime = xTaskGetTickCount();
xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS;
ulReturn = xElapsed;
}
else
{
/* Timed out. */
*ppvBuffer = NULL;
ulReturn = SYS_ARCH_TIMEOUT;
}
}
else
{
while( pdTRUE != xQueueReceive( *pxMailBox, &( *ppvBuffer ), portMAX_DELAY ) );
xEndTime = xTaskGetTickCount();
xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS;
if( xElapsed == 0UL )
{
xElapsed = 1UL;
}
ulReturn = xElapsed;
}
return ulReturn;
}
/*---------------------------------------------------------------------------*
* Routine: sys_arch_mbox_tryfetch
*---------------------------------------------------------------------------*
* Description:
* Similar to sys_arch_mbox_fetch, but if message is not ready
* immediately, we'll return with SYS_MBOX_EMPTY. On success, 0 is
* returned.
* Inputs:
* sys_mbox_t mbox -- Handle of mailbox
* void **msg -- Pointer to pointer to msg received
* Outputs:
* u32_t -- SYS_MBOX_EMPTY if no messages. Otherwise,
* return ERR_OK.
*---------------------------------------------------------------------------*/
u32_t sys_arch_mbox_tryfetch( sys_mbox_t *pxMailBox, void **ppvBuffer )
{
void *pvDummy;
unsigned long ulReturn;
if( ppvBuffer== NULL )
{
ppvBuffer = &pvDummy;
}
if( pdTRUE == xQueueReceive( *pxMailBox, &( *ppvBuffer ), 0UL ) )
{
ulReturn = ERR_OK;
}
else
{
ulReturn = SYS_MBOX_EMPTY;
}
return ulReturn;
}
/*---------------------------------------------------------------------------*
* Routine: sys_sem_new
*---------------------------------------------------------------------------*
* Description:
* Creates and returns a new semaphore. The "ucCount" argument specifies
* the initial state of the semaphore.
* NOTE: Currently this routine only creates counts of 1 or 0
* Inputs:
* sys_mbox_t mbox -- Handle of mailbox
* u8_t ucCount -- Initial ucCount of semaphore (1 or 0)
* Outputs:
* sys_sem_t -- Created semaphore or 0 if could not create.
*---------------------------------------------------------------------------*/
err_t sys_sem_new( sys_sem_t *pxSemaphore, u8_t ucCount )
{
err_t xReturn = ERR_MEM;
vSemaphoreCreateBinary( ( *pxSemaphore ) );
if( *pxSemaphore != NULL )
{
if( ucCount == 0U )
{
xSemaphoreTake( *pxSemaphore, 1UL );
}
xReturn = ERR_OK;
SYS_STATS_INC_USED( sem );
}
else
{
SYS_STATS_INC( sem.err );
}
return xReturn;
}
/*---------------------------------------------------------------------------*
* Routine: sys_arch_sem_wait
*---------------------------------------------------------------------------*
* Description:
* Blocks the thread while waiting for the semaphore to be
* signaled. If the "timeout" argument is non-zero, the thread should
* only be blocked for the specified time (measured in
* milliseconds).
*
* If the timeout argument is non-zero, the return value is the number of
* milliseconds spent waiting for the semaphore to be signaled. If the
* semaphore wasn't signaled within the specified time, the return value is
* SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
* (i.e., it was already signaled), the function may return zero.
*
* Notice that lwIP implements a function with a similar name,
* sys_sem_wait(), that uses the sys_arch_sem_wait() function.
* Inputs:
* sys_sem_t sem -- Semaphore to wait on
* u32_t timeout -- Number of milliseconds until timeout
* Outputs:
* u32_t -- Time elapsed or SYS_ARCH_TIMEOUT.
*---------------------------------------------------------------------------*/
u32_t sys_arch_sem_wait( sys_sem_t *pxSemaphore, u32_t ulTimeout )
{
portTickType xStartTime, xEndTime, xElapsed;
unsigned long ulReturn;
xStartTime = xTaskGetTickCount();
if( ulTimeout != 0UL )
{
if( xSemaphoreTake( *pxSemaphore, ulTimeout / portTICK_RATE_MS ) == pdTRUE )
{
xEndTime = xTaskGetTickCount();
xElapsed = (xEndTime - xStartTime) * portTICK_RATE_MS;
ulReturn = xElapsed;
}
else
{
ulReturn = SYS_ARCH_TIMEOUT;
}
}
else
{
while( xSemaphoreTake( *pxSemaphore, portMAX_DELAY ) != pdTRUE );
xEndTime = xTaskGetTickCount();
xElapsed = ( xEndTime - xStartTime ) * portTICK_RATE_MS;
if( xElapsed == 0UL )
{
xElapsed = 1UL;
}
ulReturn = xElapsed;
}
return ulReturn;
}
/**
* @brief Create a new mutex
* @param pxMutex pointer to the mutex to create
* @return a new mutex
*/
err_t sys_mutex_new( sys_mutex_t *pxMutex )
{
err_t xReturn = ERR_MEM;
*pxMutex = xSemaphoreCreateMutex();
if( *pxMutex != NULL )
{
xReturn = ERR_OK;
SYS_STATS_INC_USED( mutex );
}
else
{
SYS_STATS_INC( mutex.err );
}
return xReturn;
}
/** Lock a mutex
* @param pxMutex the mutex to lock */
void sys_mutex_lock( sys_mutex_t *pxMutex )
{
while( xSemaphoreTake( *pxMutex, portMAX_DELAY ) != pdPASS );
}
/** Unlock a mutex
* @param pxMutex the mutex to unlock */
void sys_mutex_unlock(sys_mutex_t *pxMutex )
{
xSemaphoreGive( *pxMutex );
}
/** Delete a semaphore
* @param pxMutex the mutex to delete */
void sys_mutex_free( sys_mutex_t *pxMutex )
{
SYS_STATS_DEC( mutex.used );
vQueueDelete( *pxMutex );
}
/*---------------------------------------------------------------------------*
* Routine: sys_sem_signal
*---------------------------------------------------------------------------*
* Description:
* Signals (releases) a semaphore
* Inputs:
* sys_sem_t sem -- Semaphore to signal
*---------------------------------------------------------------------------*/
void sys_sem_signal( sys_sem_t *pxSemaphore )
{
xSemaphoreGive( *pxSemaphore );
}
/*---------------------------------------------------------------------------*
* Routine: sys_sem_free
*---------------------------------------------------------------------------*
* Description:
* Deallocates a semaphore
* Inputs:
* sys_sem_t sem -- Semaphore to free
*---------------------------------------------------------------------------*/
void sys_sem_free( sys_sem_t *pxSemaphore )
{
SYS_STATS_DEC(sem.used);
vQueueDelete( *pxSemaphore );
}
/*---------------------------------------------------------------------------*
* Routine: sys_init
*---------------------------------------------------------------------------*
* Description:
* Initialize sys arch
*---------------------------------------------------------------------------*/
void sys_init(void)
{
}
u32_t sys_now(void)
{
return xTaskGetTickCount();
}
/*---------------------------------------------------------------------------*
* Routine: sys_thread_new
*---------------------------------------------------------------------------*
* Description:
* Starts a new thread with priority "prio" that will begin its
* execution in the function "thread()". The "arg" argument will be
* passed as an argument to the thread() function. The id of the new
* thread is returned. Both the id and the priority are system
* dependent.
* Inputs:
* char *name -- Name of thread
* void (* thread)(void *arg) -- Pointer to function to run.
* void *arg -- Argument passed into function
* int stacksize -- Required stack amount in bytes
* int prio -- Thread priority
* Outputs:
* sys_thread_t -- Pointer to per-thread timeouts.
*---------------------------------------------------------------------------*/
sys_thread_t sys_thread_new( const char *pcName, void( *pxThread )( void *pvParameters ), void *pvArg, int iStackSize, int iPriority )
{
xTaskHandle xCreatedTask;
portBASE_TYPE xResult;
sys_thread_t xReturn;
xResult = xTaskCreate( pxThread, ( signed char * ) pcName, iStackSize, pvArg, iPriority, &xCreatedTask );
if( xResult == pdPASS )
{
xReturn = xCreatedTask;
}
else
{
xReturn = NULL;
}
return xReturn;
}
/*---------------------------------------------------------------------------*
* Routine: sys_arch_protect
*---------------------------------------------------------------------------*
* Description:
* This optional function does a "fast" critical region protection and
* returns the previous protection level. This function is only called
* during very short critical regions. An embedded system which supports
* ISR-based drivers might want to implement this function by disabling
* interrupts. Task-based systems might want to implement this by using
* a mutex or disabling tasking. This function should support recursive
* calls from the same task or interrupt. In other words,
* sys_arch_protect() could be called while already protected. In
* that case the return value indicates that it is already protected.
*
* sys_arch_protect() is only required if your port is supporting an
* operating system.
* Outputs:
* sys_prot_t -- Previous protection level (not used here)
*---------------------------------------------------------------------------*/
sys_prot_t sys_arch_protect( void )
{
vPortEnterCritical();
return ( sys_prot_t ) 1;
}
/*---------------------------------------------------------------------------*
* Routine: sys_arch_unprotect
*---------------------------------------------------------------------------*
* Description:
* This optional function does a "fast" set of critical region
* protection to the value specified by pval. See the documentation for
* sys_arch_protect() for more information. This function is only
* required if your port is supporting an operating system.
* Inputs:
* sys_prot_t -- Previous protection level (not used here)
*---------------------------------------------------------------------------*/
void sys_arch_unprotect( sys_prot_t xValue )
{
(void) xValue;
taskEXIT_CRITICAL();
}
/*
* Prints an assertion messages and aborts execution.
*/
void sys_assert( const char *pcMessage )
{
(void) pcMessage;
for (;;)
{
}
}
/*-------------------------------------------------------------------------*
* End of File: sys_arch.c
*-------------------------------------------------------------------------*/
#endif
/*-----------------------------------------------------------------------------------*/

View File

@ -1,151 +0,0 @@
/**********************************************************************
* $Id$ lpc_phy.h 2011-11-20
*//**
* @file lpc_phy.h
* @brief Common PHY definitions used with all PHYs
* @version 1.0
* @date 20 Nov. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#ifndef __LPC_PHY_H_
#define __LPC_PHY_H_
#include "lwip/opt.h"
#include "lwip/err.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* These PHY functions are usually part of the EMAC driver */
/** \brief Phy status update state machine
*
* This function provides a state machine for maintaining the PHY
* status without blocking. It must be occasionally called for the
* PHY status to be maintained.
*
* \param[in] netif NETIF structure
*/
s32_t lpc_phy_sts_sm(struct netif *netif);
/** \brief Initialize the PHY
*
* This function initializes the PHY. It will block until complete.
* This function is called as part of the EMAC driver
* initialization. Configuration of the PHY at startup is
* controlled by setting up configuration defines in lpc_phy.h.
*
* \param[in] netif NETIF structure
* \param[in] rmii If set, configures the PHY for RMII mode
* \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
*/
err_t lpc_phy_init(struct netif *netif, int rmii);
/** \brief Write a value via the MII link (non-blocking)
*
* This function will write a value on the MII link interface to a PHY
* or a connected device. The function will return immediately without
* a status. Status needs to be polled later to determine if the write
* was successful.
*
* \param[in] PhyReg PHY register to write to
* \param[in] Value Value to write
*/
void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value);
/** \brief Write a value via the MII link (blocking)
*
* This function will write a value on the MII link interface to a PHY
* or a connected device. The function will block until complete.
*
* \param[in] PhyReg PHY register to write to
* \param[in] Value Value to write
* \returns 0 if the write was successful, otherwise !0
*/
err_t lpc_mii_write(u32_t PhyReg, u32_t Value);
/** \brief Reads current MII link busy status
*
* This function will return the current MII link busy status and is meant to
* be used with non-blocking functions for monitor PHY status such as
* connection state.
*
* \returns !0 if the MII link is busy, otherwise 0
*/
u32_t lpc_mii_is_busy(void);
/** \brief Starts a read operation via the MII link (non-blocking)
*
* This function returns the current value in the MII data register. It is
* meant to be used with the non-blocking oeprations. This value should
* only be read after a non-block read command has been issued and the
* MII status has been determined to be good.
*
* \returns The current value in the MII value register
*/
u32_t lpc_mii_read_data(void);
/** \brief Starts a read operation via the MII link (non-blocking)
*
* This function will start a read operation on the MII link interface
* from a PHY or a connected device. The function will not block and
* the status mist be polled until complete. Once complete, the data
* can be read.
*
* \param[in] PhyReg PHY register to read from
*/
err_t lpc_mii_read(u32_t PhyReg, u32_t *data);
/** \brief Read a value via the MII link (blocking)
*
* This function will read a value on the MII link interface from a PHY
* or a connected device. The function will block until complete.
*
* \param[in] PhyReg PHY register to read from
* \param[in] data Pointer to where to save data read via MII
* \returns 0 if the read was successful, otherwise !0
*/
void lpc_mii_read_noblock(u32_t PhyReg);
/**
* This function provides a method for the PHY to setup the EMAC
* for the PHY negotiated duplex mode.
*
* @param[in] full_duplex 0 = half duplex, 1 = full duplex
*/
void lpc_emac_set_duplex(int full_duplex);
/**
* This function provides a method for the PHY to setup the EMAC
* for the PHY negotiated bit rate.
*
* @param[in] mbs_100 0 = 10mbs mode, 1 = 100mbs mode
*/
void lpc_emac_set_speed(int mbs_100);
#ifdef __cplusplus
}
#endif
#endif /* __LPC_PHY_H_ */
/* --------------------------------- End Of File ------------------------------ */

View File

@ -1,301 +0,0 @@
/**********************************************************************
* $Id$ lpc_phy_lan8720.c 2011-11-20
*//**
* @file lpc_phy_lan8720.c
* @brief LAN8720 PHY status and control.
* @version 1.0
* @date 20 Nov. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#include "lwip/opt.h"
#include "lwip/err.h"
#include "lwip/tcpip.h"
#include "lwip/snmp.h"
#include "boards/board.h"
#include "arch/lpc_arch.h" // FIXME Ethernet
#include "lpc_phy.h"
/** @defgroup lan8720_phy PHY status and control for the LAN8720.
* @ingroup lwip_phy
*
* Various functions for controlling and monitoring the status of the
* LAN8720 PHY. In polled (standalone) systems, the PHY state must be
* monitored as part of the application. In a threaded (RTOS) system,
* the PHY state is monitored by the PHY handler thread. The MAC
* driver will not transmit unless the PHY link is active.
* @{
*/
/** \brief LAN8720 PHY register offsets */
#define LAN8_BCR_REG 0x0 /**< Basic Control Register */
#define LAN8_BSR_REG 0x1 /**< Basic Status Reg */
#define LAN8_PHYID1_REG 0x2 /**< PHY ID 1 Reg */
#define LAN8_PHYID2_REG 0x3 /**< PHY ID 2 Reg */
#define LAN8_PHYSPLCTL_REG 0x1F /**< PHY special control/status Reg */
/* LAN8720 BCR register definitions */
#define LAN8_RESET (1 << 15) /**< 1= S/W Reset */
#define LAN8_LOOPBACK (1 << 14) /**< 1=loopback Enabled */
#define LAN8_SPEED_SELECT (1 << 13) /**< 1=Select 100MBps */
#define LAN8_AUTONEG (1 << 12) /**< 1=Enable auto-negotiation */
#define LAN8_POWER_DOWN (1 << 11) /**< 1=Power down PHY */
#define LAN8_ISOLATE (1 << 10) /**< 1=Isolate PHY */
#define LAN8_RESTART_AUTONEG (1 << 9) /**< 1=Restart auto-negoatiation */
#define LAN8_DUPLEX_MODE (1 << 8) /**< 1=Full duplex mode */
/* LAN8720 BSR register definitions */
#define LAN8_100BASE_T4 (1 << 15) /**< T4 mode */
#define LAN8_100BASE_TX_FD (1 << 14) /**< 100MBps full duplex */
#define LAN8_100BASE_TX_HD (1 << 13) /**< 100MBps half duplex */
#define LAN8_10BASE_T_FD (1 << 12) /**< 100Bps full duplex */
#define LAN8_10BASE_T_HD (1 << 11) /**< 10MBps half duplex */
#define LAN8_AUTONEG_COMP (1 << 5) /**< Auto-negotation complete */
#define LAN8_RMT_FAULT (1 << 4) /**< Fault */
#define LAN8_AUTONEG_ABILITY (1 << 3) /**< Auto-negotation supported */
#define LAN8_LINK_STATUS (1 << 2) /**< 1=Link active */
#define LAN8_JABBER_DETECT (1 << 1) /**< Jabber detect */
#define LAN8_EXTEND_CAPAB (1 << 0) /**< Supports extended capabilities */
/* LAN8720 PHYSPLCTL status definitions */
#define LAN8_SPEEDMASK (7 << 2) /**< Speed and duplex mask */
#define LAN8_SPEED100F (6 << 2) /**< 100BT full duplex */
#define LAN8_SPEED10F (5 << 2) /**< 10BT full duplex */
#define LAN8_SPEED100H (2 << 2) /**< 100BT half duplex */
#define LAN8_SPEED10H (1 << 2) /**< 10BT half duplex */
/* LAN8720 PHY ID 1/2 register definitions */
#define LAN8_PHYID1_OUI 0x0007 /**< Expected PHY ID1 */
#define LAN8_PHYID2_OUI 0xC0F0 /**< Expected PHY ID2, except last 4 bits */
/**
* @brief PHY status structure used to indicate current status of PHY.
*/
typedef struct {
u32_t phy_speed_100mbs:2; /**< 10/100 MBS connection speed flag. */
u32_t phy_full_duplex:2; /**< Half/full duplex connection speed flag. */
u32_t phy_link_active:2; /**< Phy link active flag. */
} PHY_STATUS_TYPE;
/** \brief PHY update flags */
static PHY_STATUS_TYPE physts;
/** \brief Last PHY update flags, used for determing if something has changed */
static PHY_STATUS_TYPE olddphysts;
/** \brief PHY update counter for state machine */
static s32_t phyustate;
/** \brief Update PHY status from passed value
*
* This function updates the current PHY status based on the
* passed PHY status word. The PHY status indicate if the link
* is active, the connection speed, and duplex.
*
* \param[in] netif NETIF structure
* \param[in] linksts Status word with link state
* \param[in] sdsts Status word with speed and duplex states
* \return 1 if the status has changed, otherwise 0
*/
static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts, u32_t sdsts)
{
s32_t changed = 0;
/* Update link active status */
if (linksts & LAN8_LINK_STATUS)
physts.phy_link_active = 1;
else
physts.phy_link_active = 0;
switch (sdsts & LAN8_SPEEDMASK) {
case LAN8_SPEED100F:
default:
physts.phy_speed_100mbs = 1;
physts.phy_full_duplex = 1;
break;
case LAN8_SPEED10F:
physts.phy_speed_100mbs = 0;
physts.phy_full_duplex = 1;
break;
case LAN8_SPEED100H:
physts.phy_speed_100mbs = 1;
physts.phy_full_duplex = 0;
break;
case LAN8_SPEED10H:
physts.phy_speed_100mbs = 0;
physts.phy_full_duplex = 0;
break;
}
if (physts.phy_speed_100mbs != olddphysts.phy_speed_100mbs) {
changed = 1;
if (physts.phy_speed_100mbs) {
/* 100MBit mode. */
lpc_emac_set_speed(1);
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);
}
else {
/* 10MBit mode. */
lpc_emac_set_speed(0);
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
}
olddphysts.phy_speed_100mbs = physts.phy_speed_100mbs;
}
if (physts.phy_full_duplex != olddphysts.phy_full_duplex) {
changed = 1;
if (physts.phy_full_duplex)
lpc_emac_set_duplex(1);
else
lpc_emac_set_duplex(0);
olddphysts.phy_full_duplex = physts.phy_full_duplex;
}
if (physts.phy_link_active != olddphysts.phy_link_active) {
changed = 1;
#if NO_SYS == 1
if (physts.phy_link_active)
netif_set_link_up(netif);
else
netif_set_link_down(netif);
#else
if (physts.phy_link_active)
tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up,
(void*) netif, 1);
else
tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down,
(void*) netif, 1);
#endif
olddphysts.phy_link_active = physts.phy_link_active;
}
return changed;
}
/** \brief Initialize the LAN8720 PHY.
*
* This function initializes the LAN8720 PHY. It will block until
* complete. This function is called as part of the EMAC driver
* initialization. Configuration of the PHY at startup is
* controlled by setting up configuration defines in
* lpc_emac_config.h.
*
* \param[in] netif NETIF structure
* \param[in] rmii If set, configures the PHY for RMII mode
* \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
*/
err_t lpc_phy_init(struct netif *netif, int rmii)
{
u32_t tmp, tmp1;
s32_t i;
physts.phy_speed_100mbs = olddphysts.phy_speed_100mbs = 2;
physts.phy_full_duplex = olddphysts.phy_full_duplex = 2;
physts.phy_link_active = olddphysts.phy_link_active = 2;
phyustate = 0;
/* Only first read and write are checked for failure */
/* Put the LAN8720 in reset mode and wait for completion */
if (lpc_mii_write(LAN8_BCR_REG, LAN8_RESET) != 0)
return ERR_TIMEOUT;
i = 400;
while (i > 0) {
msDelay(1); /* 1 ms */
if (lpc_mii_read(LAN8_BCR_REG, &tmp) != 0)
return ERR_TIMEOUT;
if (!(tmp & (LAN8_RESET | LAN8_POWER_DOWN)))
i = -1;
else
i--;
}
/* Timeout? */
if (i == 0)
return ERR_TIMEOUT;
/* Setup link based on configuration options */
#if PHY_USE_AUTONEG==1
tmp = LAN8_AUTONEG;
#else
tmp = 0;
#endif
#if PHY_USE_100MBS==1
tmp |= LAN8_SPEED_SELECT;
#endif
#if PHY_USE_FULL_DUPLEX==1
tmp |= LAN8_DUPLEX_MODE;
#endif
lpc_mii_write(LAN8_BCR_REG, tmp);
/* The link is not set active at this point, but will be detected
later */
return ERR_OK;
}
/* Phy status update state machine */
s32_t lpc_phy_sts_sm(struct netif *netif)
{
static u32_t sts;
s32_t changed = 0;
switch (phyustate) {
default:
case 0:
/* Read BMSR to clear faults */
lpc_mii_read_noblock(LAN8_BSR_REG);
phyustate = 1;
break;
case 1:
/* Wait for read status state */
if (!lpc_mii_is_busy()) {
/* Get PHY status with link state */
sts = lpc_mii_read_data();
lpc_mii_read_noblock(LAN8_PHYSPLCTL_REG);
phyustate = 2;
}
break;
case 2:
/* Wait for read status state */
if (!lpc_mii_is_busy()) {
/* Update PHY status */
changed = lpc_update_phy_sts(netif, sts, lpc_mii_read_data());
phyustate = 0;
}
break;
}
return changed;
}
/**
* @}
*/
/* --------------------------------- End Of File ------------------------------ */

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +0,0 @@
/*
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/

View File

@ -1,4 +0,0 @@
src/ - The source code for the lwIP TCP/IP stack.
doc/ - The documentation for lwIP.
See also the FILES file in each subdirectory.

View File

@ -1,89 +0,0 @@
INTRODUCTION
lwIP is a small independent implementation of the TCP/IP protocol
suite that has been developed by Adam Dunkels at the Computer and
Networks Architectures (CNA) lab at the Swedish Institute of Computer
Science (SICS).
The focus of the lwIP TCP/IP implementation is to reduce the RAM usage
while still having a full scale TCP. This making lwIP suitable for use
in embedded systems with tens of kilobytes of free RAM and room for
around 40 kilobytes of code ROM.
FEATURES
* IP (Internet Protocol) including packet forwarding over multiple network
interfaces
* ICMP (Internet Control Message Protocol) for network maintenance and debugging
* IGMP (Internet Group Management Protocol) for multicast traffic management
* UDP (User Datagram Protocol) including experimental UDP-lite extensions
* TCP (Transmission Control Protocol) with congestion control, RTT estimation
and fast recovery/fast retransmit
* Specialized raw/native API for enhanced performance
* Optional Berkeley-like socket API
* DNS (Domain names resolver)
* SNMP (Simple Network Management Protocol)
* DHCP (Dynamic Host Configuration Protocol)
* AUTOIP (for IPv4, conform with RFC 3927)
* PPP (Point-to-Point Protocol)
* ARP (Address Resolution Protocol) for Ethernet
LICENSE
lwIP is freely available under a BSD license.
DEVELOPMENT
lwIP has grown into an excellent TCP/IP stack for embedded devices,
and developers using the stack often submit bug fixes, improvements,
and additions to the stack to further increase its usefulness.
Development of lwIP is hosted on Savannah, a central point for
software development, maintenance and distribution. Everyone can
help improve lwIP by use of Savannah's interface, CVS and the
mailing list. A core team of developers will commit changes to the
CVS source tree.
The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and
contributions (such as platform ports) are in the 'contrib' module.
See doc/savannah.txt for details on CVS server access for users and
developers.
Last night's CVS tar ball can be downloaded from:
http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING]
The current CVS trees are web-browsable:
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/
Submit patches and bugs via the lwIP project page:
http://savannah.nongnu.org/projects/lwip/
DOCUMENTATION
The original out-dated homepage of lwIP and Adam Dunkels' papers on
lwIP are at the official lwIP home page:
http://www.sics.se/~adam/lwip/
Self documentation of the source code is regularly extracted from the
current CVS sources and is available from this web page:
http://www.nongnu.org/lwip/
There is now a constantly growin wiki about lwIP at
http://lwip.wikia.com/wiki/LwIP_Wiki
Also, there are mailing lists you can subscribe at
http://savannah.nongnu.org/mail/?group=lwip
plus searchable archives:
http://lists.nongnu.org/archive/html/lwip-users/
http://lists.nongnu.org/archive/html/lwip-devel/
Reading Adam's papers, the files in docs/, browsing the source code
documentation and browsing the mailing list archives is a good way to
become familiar with the design of lwIP.
Adam Dunkels <adam@sics.se>
Leon Woestenberg <leon.woestenberg@gmx.net>

View File

@ -1,144 +0,0 @@
This file lists major changes between release versions that require
ports or applications to be changed. Use it to update a port or an
application written for an older version of lwIP to correctly work
with newer versions.
(CVS HEAD)
* [Enter new changes just after this line - do not remove this line]
++ Application changes:
* Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for
compatibility to old applications, but will be removed in the future).
* Renamed mem_realloc() to mem_trim() to prevent confusion with realloc()
+++ Raw API:
* Changed the semantics of tcp_close() (since it was rather a
shutdown before): Now the application does *NOT* get any calls to the recv
callback (aside from NULL/closed) after calling tcp_close()
* When calling tcp_abort() from a raw API TCP callback function,
make sure you return ERR_ABRT to prevent accessing unallocated memory.
(ERR_ABRT now means the applicaiton has called tcp_abort!)
+++ Netconn API:
* Changed netconn_receive() and netconn_accept() to return
err_t, not a pointer to new data/netconn.
+++ Socket API:
* LWIP_SO_RCVTIMEO: when accept() or recv() time out, they
now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT.
* Added a minimal version of posix fctl() to have a
standardised way to set O_NONBLOCK for nonblocking sockets.
+++ all APIs:
* correctly implemented SO(F)_REUSEADDR
++ Port changes
+++ new files:
* Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h:
* Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains
the actual application programmer's API
* Separated timer implementation from sys.h/.c, moved to timers.h/.c;
Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you
still want to use your own timer implementation for NO_SYS==0 (as before).
+++ sys layer:
* Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/
sys_sem_t;
* Converted sys_mbox_new/sys_sem_new to take pointers and return err_t;
* Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use
binary semaphores instead of mutexes - as before)
+++ new options:
* Don't waste memory when chaining segments, added option TCP_OVERSIZE to
prevent creating many small pbufs when calling tcp_write with many small
blocks of data. Instead, pbufs are allocated larger than needed and the
space is used for later calls to tcp_write.
* Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs
in tcp_write/udp_send.
* Added an additional option LWIP_ETHERNET to support ethernet without ARP
(necessary for pure PPPoE)
* Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may
be used to place these pools into user-defined memory by using external
declaration.
* Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT
+++ new pools:
* Netdb uses a memp pool for allocating memory when getaddrinfo() is called,
so MEMP_NUM_NETDB has to be set accordingly.
* DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so
MEMP_NUM_LOCALHOSTLIST has to be set accordingly.
* Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have
to be set accordingly.
* PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES
has to be set accordingly
* Integrated loopif into netif.c - loopif does not have to be created by the
port any more, just define LWIP_HAVE_LOOPIF to 1.
* Added define LWIP_RAND() for lwip-wide randomization (needs to be defined
in cc.h, e.g. used by igmp)
* Added printf-formatter X8_F to printf u8_t as hex
* The heap now may be moved to user-defined memory by defining
LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address
* added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work
with user-allocated structs instead of calling mem_malloc
* Added const char* name to mem- and memp-stats for easier debugging.
* Calculate the TCP/UDP checksum while copying to only fetch data once:
Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum
* Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to
more than one pcb.
* Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned
off any more, if this is set to 0, only one packet (the most recent one) is
queued (like demanded by RFC 1122).
++ Major bugfixes/improvements
* Implemented tcp_shutdown() to only shut down one end of a connection
* Implemented shutdown() at socket- and netconn-level
* Added errorset support to select() + improved select speed overhead
* Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x)
* Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1
* Use macros defined in ip_addr.h to work with IP addresses
* Implemented many nonblocking socket/netconn functions
* Fixed ARP input processing: only add a new entry if a request was directed as us
* mem_realloc() to mem_trim() to prevent confusion with realloc()
* Some improvements for AutoIP (don't route/forward link-local addresses, don't break
existing connections when assigning a routable address)
* Correctly handle remote side overrunning our rcv_wnd in ooseq case
* Removed packing from ip_addr_t, the packed version is now only used in protocol headers
* Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0
* Added support for static ARP table entries
(STABLE-1.3.2)
* initial version of this file

View File

@ -1,6 +0,0 @@
savannah.txt - How to obtain the current development source code.
contrib.txt - How to contribute to lwIP as a developer.
rawapi.txt - The documentation for the core API of lwIP.
Also provides an overview about the other APIs and multithreading.
snmp_agent.txt - The documentation for the lwIP SNMP agent.
sys_arch.txt - The documentation for a system abstraction layer of lwIP.

View File

@ -1,63 +0,0 @@
1 Introduction
This document describes some guidelines for people participating
in lwIP development.
2 How to contribute to lwIP
Here is a short list of suggestions to anybody working with lwIP and
trying to contribute bug reports, fixes, enhancements, platform ports etc.
First of all as you may already know lwIP is a volunteer project so feedback
to fixes or questions might often come late. Hopefully the bug and patch tracking
features of Savannah help us not lose users' input.
2.1 Source code style:
1. do not use tabs.
2. indentation is two spaces per level (i.e. per tab).
3. end debug messages with a trailing newline (\n).
4. one space between keyword and opening bracket.
5. no space between function and opening bracket.
6. one space and no newline before opening curly braces of a block.
7. closing curly brace on a single line.
8. spaces surrounding assignment and comparisons.
9. don't initialize static and/or global variables to zero, the compiler takes care of that.
10. use current source code style as further reference.
2.2 Source code documentation style:
1. JavaDoc compliant and Doxygen compatible.
2. Function documentation above functions in .c files, not .h files.
(This forces you to synchronize documentation and implementation.)
3. Use current documentation style as further reference.
2.3 Bug reports and patches:
1. Make sure you are reporting bugs or send patches against the latest
sources. (From the latest release and/or the current CVS sources.)
2. If you think you found a bug make sure it's not already filed in the
bugtracker at Savannah.
3. If you have a fix put the patch on Savannah. If it is a patch that affects
both core and arch specific stuff please separate them so that the core can
be applied separately while leaving the other patch 'open'. The prefered way
is to NOT touch archs you can't test and let maintainers take care of them.
This is a good way to see if they are used at all - the same goes for unix
netifs except tapif.
4. Do not file a bug and post a fix to it to the patch area. Either a bug report
or a patch will be enough.
If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area.
5. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two)
can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded
as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead
for reporting a compiler warning fix.
6. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other
trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you
change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than
if it's not to the point and long :) so the chances for it to be applied are greater.
2.4 Platform porters:
1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and
you think it could benefit others[1] you might want discuss this on the mailing list. You
can also ask for CVS access to submit and maintain your port in the contrib CVS module.

View File

@ -1,511 +0,0 @@
Raw TCP/IP interface for lwIP
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
lwIP provides three Application Program's Interfaces (APIs) for programs
to use for communication with the TCP/IP code:
* low-level "core" / "callback" or "raw" API.
* higher-level "sequential" API.
* BSD-style socket API.
The sequential API provides a way for ordinary, sequential, programs
to use the lwIP stack. It is quite similar to the BSD socket API. The
model of execution is based on the blocking open-read-write-close
paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
code and the application program must reside in different execution
contexts (threads).
The socket API is a compatibility API for existing applications,
currently it is built on top of the sequential API. It is meant to
provide all functions needed to run socket API applications running
on other platforms (e.g. unix / windows etc.). However, due to limitations
in the specification of this API, there might be incompatibilities
that require small modifications of existing programs.
** Threading
lwIP started targeting single-threaded environments. When adding multi-
threading support, instead of making the core thread-safe, another
approach was chosen: there is one main thread running the lwIP core
(also known as the "tcpip_thread"). The raw API may only be used from
this thread! Application threads using the sequential- or socket API
communicate with this main thread through message passing.
As such, the list of functions that may be called from
other threads or an ISR is very limited! Only functions
from these API header files are thread-safe:
- api.h
- netbuf.h
- netdb.h
- netifapi.h
- sockets.h
- sys.h
Additionaly, memory (de-)allocation functions may be
called from multiple threads (not ISR!) with NO_SYS=0
since they are protected by SYS_LIGHTWEIGHT_PROT and/or
semaphores.
Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1
and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
pbuf_free() may also be called from another thread or
an ISR (since only then, mem_free - for PBUF_RAM - may
be called from an ISR: otherwise, the HEAP is only
protected by semaphores).
** The remainder of this document discusses the "raw" API. **
The raw TCP/IP interface allows the application program to integrate
better with the TCP/IP code. Program execution is event based by
having callback functions being called from within the TCP/IP
code. The TCP/IP code and the application program both run in the same
thread. The sequential API has a much higher overhead and is not very
well suited for small systems since it forces a multithreaded paradigm
on the application.
The raw TCP/IP interface is not only faster in terms of code execution
time but is also less memory intensive. The drawback is that program
development is somewhat harder and application programs written for
the raw TCP/IP interface are more difficult to understand. Still, this
is the preferred way of writing applications that should be small in
code size and memory usage.
Both APIs can be used simultaneously by different application
programs. In fact, the sequential API is implemented as an application
program using the raw TCP/IP interface.
--- Callbacks
Program execution is driven by callbacks. Each callback is an ordinary
C function that is called from within the TCP/IP code. Every callback
function is passed the current TCP or UDP connection state as an
argument. Also, in order to be able to keep program specific state,
the callback functions are called with a program specified argument
that is independent of the TCP/IP state.
The function for setting the application connection state is:
- void tcp_arg(struct tcp_pcb *pcb, void *arg)
Specifies the program specific state that should be passed to all
other callback functions. The "pcb" argument is the current TCP
connection control block, and the "arg" argument is the argument
that will be passed to the callbacks.
--- TCP connection setup
The functions used for setting up connections is similar to that of
the sequential API and of the BSD socket API. A new TCP connection
identifier (i.e., a protocol control block - PCB) is created with the
tcp_new() function. This PCB can then be either set to listen for new
incoming connections or be explicitly connected to another host.
- struct tcp_pcb *tcp_new(void)
Creates a new connection identifier (PCB). If memory is not
available for creating the new pcb, NULL is returned.
- err_t tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port)
Binds the pcb to a local IP address and port number. The IP address
can be specified as IP_ADDR_ANY in order to bind the connection to
all local IP addresses.
If another connection is bound to the same port, the function will
return ERR_USE, otherwise ERR_OK is returned.
- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)
Commands a pcb to start listening for incoming connections. When an
incoming connection is accepted, the function specified with the
tcp_accept() function will be called. The pcb will have to be bound
to a local port with the tcp_bind() function.
The tcp_listen() function returns a new connection identifier, and
the one passed as an argument to the function will be
deallocated. The reason for this behavior is that less memory is
needed for a connection that is listening, so tcp_listen() will
reclaim the memory needed for the original connection and allocate a
new smaller memory block for the listening connection.
tcp_listen() may return NULL if no memory was available for the
listening connection. If so, the memory associated with the pcb
passed as an argument to tcp_listen() will not be deallocated.
- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
Same as tcp_listen, but limits the number of outstanding connections
in the listen queue to the value specified by the backlog argument.
To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.
- void tcp_accepted(struct tcp_pcb *pcb)
Inform lwIP that an incoming connection has been accepted. This would
usually be called from the accept callback. This allows lwIP to perform
housekeeping tasks, such as allowing further incoming connections to be
queued in the listen backlog.
ATTENTION: the PCB passed in must be the listening pcb, not the pcb passed
into the accept callback!
- void tcp_accept(struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
err_t err))
Specified the callback function that should be called when a new
connection arrives on a listening connection.
- err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port, err_t (* connected)(void *arg,
struct tcp_pcb *tpcb,
err_t err));
Sets up the pcb to connect to the remote host and sends the
initial SYN segment which opens the connection.
The tcp_connect() function returns immediately; it does not wait for
the connection to be properly setup. Instead, it will call the
function specified as the fourth argument (the "connected" argument)
when the connection is established. If the connection could not be
properly established, either because the other host refused the
connection or because the other host didn't answer, the "err"
callback function of this pcb (registered with tcp_err, see below)
will be called.
The tcp_connect() function can return ERR_MEM if no memory is
available for enqueueing the SYN segment. If the SYN indeed was
enqueued successfully, the tcp_connect() function returns ERR_OK.
--- Sending TCP data
TCP data is sent by enqueueing the data with a call to
tcp_write(). When the data is successfully transmitted to the remote
host, the application will be notified with a call to a specified
callback function.
- err_t tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len,
u8_t apiflags)
Enqueues the data pointed to by the argument dataptr. The length of
the data is passed as the len parameter. The apiflags can be one or more of:
- TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated
for the data to be copied into. If this flag is not given, no new memory
should be allocated and the data should only be referenced by pointer. This
also means that the memory behind dataptr must not change until the data is
ACKed by the remote host
- TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is given,
the PSH flag is set in the last segment created by this call to tcp_write.
If this flag is given, the PSH flag is not set.
The tcp_write() function will fail and return ERR_MEM if the length
of the data exceeds the current send buffer size or if the length of
the queue of outgoing segment is larger than the upper limit defined
in lwipopts.h. The number of bytes available in the output queue can
be retrieved with the tcp_sndbuf() function.
The proper way to use this function is to call the function with at
most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,
the application should wait until some of the currently enqueued
data has been successfully received by the other host and try again.
- void tcp_sent(struct tcp_pcb *pcb,
err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
u16_t len))
Specifies the callback function that should be called when data has
successfully been received (i.e., acknowledged) by the remote
host. The len argument passed to the callback function gives the
amount bytes that was acknowledged by the last acknowledgment.
--- Receiving TCP data
TCP data reception is callback based - an application specified
callback function is called when new data arrives. When the
application has taken the data, it has to call the tcp_recved()
function to indicate that TCP can advertise increase the receive
window.
- void tcp_recv(struct tcp_pcb *pcb,
err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err))
Sets the callback function that will be called when new data
arrives. The callback function will be passed a NULL pbuf to
indicate that the remote host has closed the connection. If
there are no errors and the callback function is to return
ERR_OK, then it must free the pbuf. Otherwise, it must not
free the pbuf so that lwIP core code can store it.
- void tcp_recved(struct tcp_pcb *pcb, u16_t len)
Must be called when the application has received the data. The len
argument indicates the length of the received data.
--- Application polling
When a connection is idle (i.e., no data is either transmitted or
received), lwIP will repeatedly poll the application by calling a
specified callback function. This can be used either as a watchdog
timer for killing connections that have stayed idle for too long, or
as a method of waiting for memory to become available. For instance,
if a call to tcp_write() has failed because memory wasn't available,
the application may use the polling functionality to call tcp_write()
again when the connection has been idle for a while.
- void tcp_poll(struct tcp_pcb *pcb,
err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
u8_t interval)
Specifies the polling interval and the callback function that should
be called to poll the application. The interval is specified in
number of TCP coarse grained timer shots, which typically occurs
twice a second. An interval of 10 means that the application would
be polled every 5 seconds.
--- Closing and aborting connections
- err_t tcp_close(struct tcp_pcb *pcb)
Closes the connection. The function may return ERR_MEM if no memory
was available for closing the connection. If so, the application
should wait and try again either by using the acknowledgment
callback or the polling functionality. If the close succeeds, the
function returns ERR_OK.
The pcb is deallocated by the TCP code after a call to tcp_close().
- void tcp_abort(struct tcp_pcb *pcb)
Aborts the connection by sending a RST (reset) segment to the remote
host. The pcb is deallocated. This function never fails.
ATTENTION: When calling this from one of the TCP callbacks, make
sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
or you will risk accessing deallocated memory or memory leaks!
If a connection is aborted because of an error, the application is
alerted of this event by the err callback. Errors that might abort a
connection are when there is a shortage of memory. The callback
function to be called is set using the tcp_err() function.
- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,
err_t err))
The error callback function does not get the pcb passed to it as a
parameter since the pcb may already have been deallocated.
--- Lower layer TCP interface
TCP provides a simple interface to the lower layers of the
system. During system initialization, the function tcp_init() has
to be called before any other TCP function is called. When the system
is running, the two timer functions tcp_fasttmr() and tcp_slowtmr()
must be called with regular intervals. The tcp_fasttmr() should be
called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and
tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds.
--- UDP interface
The UDP interface is similar to that of TCP, but due to the lower
level of complexity of UDP, the interface is significantly simpler.
- struct udp_pcb *udp_new(void)
Creates a new UDP pcb which can be used for UDP communication. The
pcb is not active until it has either been bound to a local address
or connected to a remote address.
- void udp_remove(struct udp_pcb *pcb)
Removes and deallocates the pcb.
- err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port)
Binds the pcb to a local address. The IP-address argument "ipaddr"
can be IP_ADDR_ANY to indicate that it should listen to any local IP
address. The function currently always return ERR_OK.
- err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port)
Sets the remote end of the pcb. This function does not generate any
network traffic, but only set the remote address of the pcb.
- err_t udp_disconnect(struct udp_pcb *pcb)
Remove the remote end of the pcb. This function does not generate
any network traffic, but only removes the remote address of the pcb.
- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
Sends the pbuf p. The pbuf is not deallocated.
- void udp_recv(struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb,
struct pbuf *p,
ip_addr_t *addr,
u16_t port),
void *recv_arg)
Specifies a callback function that should be called when a UDP
datagram is received.
--- System initalization
A truly complete and generic sequence for initializing the lwip stack
cannot be given because it depends on the build configuration (lwipopts.h)
and additional initializations for your runtime environment (e.g. timers).
We can give you some idea on how to proceed when using the raw API.
We assume a configuration using a single Ethernet netif and the
UDP and TCP transport layers, IPv4 and the DHCP client.
Call these functions in the order of appearance:
- stats_init()
Clears the structure where runtime statistics are gathered.
- sys_init()
Not of much use since we set the NO_SYS 1 option in lwipopts.h,
to be called for easy configuration changes.
- mem_init()
Initializes the dynamic memory heap defined by MEM_SIZE.
- memp_init()
Initializes the memory pools defined by MEMP_NUM_x.
- pbuf_init()
Initializes the pbuf memory pool defined by PBUF_POOL_SIZE.
- etharp_init()
Initializes the ARP table and queue.
Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval
after this initialization.
- ip_init()
Doesn't do much, it should be called to handle future changes.
- udp_init()
Clears the UDP PCB list.
- tcp_init()
Clears the TCP PCB list and clears some internal TCP timers.
Note: you must call tcp_fasttmr() and tcp_slowtmr() at the
predefined regular intervals after this initialization.
- netif_add(struct netif *netif, ip_addr_t *ipaddr,
ip_addr_t *netmask, ip_addr_t *gw,
void *state, err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif))
Adds your network interface to the netif_list. Allocate a struct
netif and pass a pointer to this structure as the first argument.
Give pointers to cleared ip_addr structures when using DHCP,
or fill them with sane numbers otherwise. The state pointer may be NULL.
The init function pointer must point to a initialization function for
your ethernet netif interface. The following code illustrates it's use.
err_t netif_if_init(struct netif *netif)
{
u8_t i;
for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i];
init_my_eth_device();
return ERR_OK;
}
For ethernet drivers, the input function pointer must point to the lwip
function ethernet_input() declared in "netif/etharp.h". Other drivers
must use ip_input() declared in "lwip/ip.h".
- netif_set_default(struct netif *netif)
Registers the default network interface.
- netif_set_up(struct netif *netif)
When the netif is fully configured this function must be called.
- dhcp_start(struct netif *netif)
Creates a new DHCP client for this interface on the first call.
Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
the predefined regular intervals after starting the client.
You can peek in the netif->dhcp struct for the actual DHCP status.
--- Optimalization hints
The first thing you want to optimize is the lwip_standard_checksum()
routine from src/core/inet.c. You can override this standard
function with the #define LWIP_CHKSUM <your_checksum_routine>.
There are C examples given in inet.c or you might want to
craft an assembly function for this. RFC1071 is a good
introduction to this subject.
Other significant improvements can be made by supplying
assembly or inline replacements for htons() and htonl()
if you're using a little-endian architecture.
#define LWIP_PLATFORM_BYTESWAP 1
#define LWIP_PLATFORM_HTONS(x) <your_htons>
#define LWIP_PLATFORM_HTONL(x) <your_htonl>
Check your network interface driver if it reads at
a higher speed than the maximum wire-speed. If the
hardware isn't serviced frequently and fast enough
buffer overflows are likely to occur.
E.g. when using the cs8900 driver, call cs8900if_service(ethif)
as frequently as possible. When using an RTOS let the cs8900 interrupt
wake a high priority task that services your driver using a binary
semaphore or event flag. Some drivers might allow additional tuning
to match your application and network.
For a production release it is recommended to set LWIP_STATS to 0.
Note that speed performance isn't influenced much by simply setting
high values to the memory options.
For more optimization hints take a look at the lwIP wiki.
--- Zero-copy MACs
To achieve zero-copy on transmit, the data passed to the raw API must
remain unchanged until sent. Because the send- (or write-)functions return
when the packets have been enqueued for sending, data must be kept stable
after that, too.
This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions
must *not* be reused by the application unless their ref-count is 1.
For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too,
but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while
PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change).
Also, data passed to tcp_write without the copy-flag must not be changed!
Therefore, be careful which type of PBUF you use and if you copy TCP data
or not!

View File

@ -1,135 +0,0 @@
Daily Use Guide for using Savannah for lwIP
Table of Contents:
1 - Obtaining lwIP from the CVS repository
2 - Committers/developers CVS access using SSH (to be written)
3 - Merging from DEVEL branch to main trunk (stable branch)
4 - How to release lwIP
1 Obtaining lwIP from the CVS repository
----------------------------------------
To perform an anonymous CVS checkout of the main trunk (this is where
bug fixes and incremental enhancements occur), do this:
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip
Or, obtain a stable branch (updated with bug fixes only) as follows:
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_7 -d lwip-0.7 lwip
Or, obtain a specific (fixed) release as follows:
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_7_0 -d lwip-0.7.0 lwip
3 Committers/developers CVS access using SSH
--------------------------------------------
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
As such, CVS commits to the server occur through a SSH tunnel for project members.
To create a SSH2 key pair in UNIX-like environments, do this:
ssh-keygen -t dsa
Under Windows, a recommended SSH client is "PuTTY", freely available with good
documentation and a graphic user interface. Use its key generator.
Now paste the id_dsa.pub contents into your Savannah account public key list. Wait
a while so that Savannah can update its configuration (This can take minutes).
Try to login using SSH:
ssh -v your_login@cvs.sv.gnu.org
If it tells you:
Authenticating with public key "your_key_name"...
Server refused to allocate pty
then you could login; Savannah refuses to give you a shell - which is OK, as we
are allowed to use SSH for CVS only. Now, you should be able to do this:
export CVS_RSH=ssh
cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip
after which you can edit your local files with bug fixes or new features and
commit them. Make sure you know what you are doing when using CVS to make
changes on the repository. If in doubt, ask on the lwip-members mailing list.
(If SSH asks about authenticity of the host, you can check the key
fingerprint against http://savannah.nongnu.org/cvs/?group=lwip)
3 Merging from DEVEL branch to main trunk (stable)
--------------------------------------------------
Merging is a delicate process in CVS and requires the
following disciplined steps in order to prevent conflicts
in the future. Conflicts can be hard to solve!
Merging from branch A to branch B requires that the A branch
has a tag indicating the previous merger. This tag is called
'merged_from_A_to_B'. After merging, the tag is moved in the
A branch to remember this merger for future merge actions.
IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE
REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE
MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME).
Merge all changes in DEVEL since our last merge to main:
In the working copy of the main trunk:
cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL
(This will apply the changes between 'merged_from_DEVEL_to_main'
and 'DEVEL' to your work set of files)
We can now commit the merge result.
cvs commit -R -m "Merged from DEVEL to main."
If this worked out OK, we now move the tag in the DEVEL branch
to this merge point, so we can use this point for future merges:
cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip
4 How to release lwIP
---------------------
First, checkout a clean copy of the branch to be released. Tag this set with
tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example).
Login CVS using pserver authentication, then export a clean copy of the
tagged tree. Export is similar to a checkout, except that the CVS metadata
is not created locally.
export CVS_RSH=ssh
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
-r STABLE-0_6_3 -d lwip-0.6.3 lwip
Archive this directory using tar, gzip'd, bzip2'd and zip'd.
tar czvf lwip-0.6.3.tar.gz lwip-0.6.3
tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3
zip -r lwip-0.6.3.zip lwip-0.6.3
Now, sign the archives with a detached GPG binary signature as follows:
gpg -b lwip-0.6.3.tar.gz
gpg -b lwip-0.6.3.tar.bz2
gpg -b lwip-0.6.3.zip
Upload these files using anonymous FTP:
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
ncftp>mput *0.6.3.*
Additionally, you may post a news item on Savannah, like this:
A new 0.6.3 release is now available here:
http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3
You will have to submit this via the user News interface, then approve
this via the Administrator News interface.

View File

@ -1,181 +0,0 @@
SNMPv1 agent for lwIP
Author: Christiaan Simons
This is a brief introduction how to use and configure the SNMP agent.
Note the agent uses the raw-API UDP interface so you may also want to
read rawapi.txt to gain a better understanding of the SNMP message handling.
0 Agent Capabilities
====================
SNMPv1 per RFC1157
This is an old(er) standard but is still widely supported.
For SNMPv2c and v3 have a greater complexity and need many
more lines of code. IMHO this breaks the idea of "lightweight IP".
Note the S in SNMP stands for "Simple". Note that "Simple" is
relative. SNMP is simple compared to the complex ISO network
management protocols CMIP (Common Management Information Protocol)
and CMOT (CMip Over Tcp).
MIB II per RFC1213
The standard lwIP stack management information base.
This is a required MIB, so this is always enabled.
When builing lwIP without TCP, the mib-2.tcp group is omitted.
The groups EGP, CMOT and transmission are disabled by default.
Most mib-2 objects are not writable except:
sysName, sysLocation, sysContact, snmpEnableAuthenTraps.
Writing to or changing the ARP and IP address and route
tables is not possible.
Note lwIP has a very limited notion of IP routing. It currently
doen't have a route table and doesn't have a notion of the U,G,H flags.
Instead lwIP uses the interface list with only one default interface
acting as a single gateway interface (G) for the default route.
The agent returns a "virtual table" with the default route 0.0.0.0
for the default interface and network routes (no H) for each
network interface in the netif_list.
All routes are considered to be up (U).
Loading additional MIBs
MIBs can only be added in compile-time, not in run-time.
There is no MIB compiler thus additional MIBs must be hand coded.
Large SNMP message support
The packet decoding and encoding routines are designed
to use pbuf-chains. Larger payloads than the minimum
SNMP requirement of 484 octets are supported if the
PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your
local requirement.
1 Building the Agent
====================
First of all you'll need to add the following define
to your local lwipopts.h:
#define LWIP_SNMP 1
and add the source files in lwip/src/core/snmp
and some snmp headers in lwip/src/include/lwip to your makefile.
Note you'll might need to adapt you network driver to update
the mib2 variables for your interface.
2 Running the Agent
===================
The following function calls must be made in your program to
actually get the SNMP agent running.
Before starting the agent you should supply pointers
to non-volatile memory for sysContact, sysLocation,
and snmpEnableAuthenTraps. You can do this by calling
snmp_set_syscontact()
snmp_set_syslocation()
snmp_set_snmpenableauthentraps()
Additionally you may want to set
snmp_set_sysdescr()
snmp_set_sysobjid() (if you have a private MIB)
snmp_set_sysname()
Also before starting the agent you need to setup
one or more trap destinations using these calls:
snmp_trap_dst_enable();
snmp_trap_dst_ip_set();
In the lwIP initialisation sequence call snmp_init() just after
the call to udp_init().
Exactly every 10 msec the SNMP uptime timestamp must be updated with
snmp_inc_sysuptime(). You should call this from a timer interrupt
or a timer signal handler depending on your runtime environment.
An alternative way to update the SNMP uptime timestamp is to do a call like
snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to
a lower frequency). Another one is to not call snmp_inc_sysuptime() or
snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro.
This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside
snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only
when it's queried (any function which need "sysuptime" have to call
snmp_get_sysuptime).
3 Private MIBs
==============
If want to extend the agent with your own private MIB you'll need to
add the following define to your local lwipopts.h:
#define SNMP_PRIVATE_MIB 1
You must provide the private_mib.h and associated files yourself.
Note we don't have a "MIB compiler" that generates C source from a MIB,
so you're required to do some serious coding if you enable this!
Note the lwIP enterprise ID (26381) is assigned to the lwIP project,
ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP
MAINTAINERS!
If you need to create your own private MIB you'll need
to apply for your own enterprise ID with IANA: http://www.iana.org/numbers.html
You can set it by passing a struct snmp_obj_id to the agent
using snmp_set_sysobjid(&my_object_id), just before snmp_init().
Note the object identifiers for thes MIB-2 and your private MIB
tree must be kept in sorted ascending (lexicographical) order.
This to ensure correct getnext operation.
An example for a private MIB is part of the "minimal Unix" project:
contrib/ports/unix/proj/minimal/lwip_prvmib.c
The next chapter gives a more detailed description of the
MIB-2 tree and the optional private MIB.
4 The Gory Details
==================
4.0 Object identifiers and the MIB tree.
We have three distinct parts for all object identifiers:
The prefix
.iso.org.dod.internet
the middle part
.mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress
and the index part
.1.192.168.0.1
Objects located above the .internet hierarchy aren't supported.
Currently only the .mgmt sub-tree is available and
when the SNMP_PRIVATE_MIB is enabled the .private tree
becomes available too.
Object identifiers from incoming requests are checked
for a matching prefix, middle part and index part
or are expanded(*) for GetNext requests with short
or inexisting names in the request.
(* we call this "expansion" but this also
resembles the "auto-completion" operation)
The middle part is usually located in ROM (const)
to preserve precious RAM on small microcontrollers.
However RAM location is possible for a dynamically
changing private tree.
The index part is handled by functions which in
turn use dynamically allocated index trees from RAM.
These trees are updated by e.g. the etharp code
when new entries are made or removed form the ARP cache.
/** @todo more gory details */

View File

@ -1,267 +0,0 @@
sys_arch interface for lwIP 0.6++
Author: Adam Dunkels
The operating system emulation layer provides a common interface
between the lwIP code and the underlying operating system kernel. The
general idea is that porting lwIP to new architectures requires only
small changes to a few header files and a new sys_arch
implementation. It is also possible to do a sys_arch implementation
that does not rely on any underlying operating system.
The sys_arch provides semaphores and mailboxes to lwIP. For the full
lwIP functionality, multiple threads support can be implemented in the
sys_arch, but this is not required for the basic lwIP
functionality. Previous versions of lwIP required the sys_arch to
implement timer scheduling as well but as of lwIP 0.5 this is
implemented in a higher layer.
In addition to the source file providing the functionality of sys_arch,
the OS emulation layer must provide several header files defining
macros used throughout lwip. The files required and the macros they
must define are listed below the sys_arch description.
Semaphores can be either counting or binary - lwIP works with both
kinds. Mailboxes are used for message passing and can be implemented
either as a queue which allows multiple messages to be posted to a
mailbox, or as a rendez-vous point where only one message can be
posted at a time. lwIP works with both kinds, but the former type will
be more efficient. A message in a mailbox is just a pointer, nothing
more.
Semaphores are represented by the type "sys_sem_t" which is typedef'd
in the sys_arch.h file. Mailboxes are equivalently represented by the
type "sys_mbox_t". lwIP does not place any restrictions on how
sys_sem_t or sys_mbox_t are represented internally.
Since lwIP 1.4.0, semaphore and mailbox functions are prototyped in a way that
allows both using pointers or actual OS structures to be used. This way, memory
required for such types can be either allocated in place (globally or on the
stack) or on the heap (allocated internally in the "*_new()" functions).
The following functions must be implemented by the sys_arch:
- void sys_init(void)
Is called to initialize the sys_arch layer.
- err_t sys_sem_new(sys_sem_t *sem, u8_t count)
Creates a new semaphore. The semaphore is allocated to the memory that 'sem'
points to (which can be both a pointer or the actual OS structure).
The "count" argument specifies the initial state of the semaphore (which is
either 0 or 1).
If the semaphore has been created, ERR_OK should be returned. Returning any
other error will provide a hint what went wrong, but except for assertions,
no real error handling is implemented.
- void sys_sem_free(sys_sem_t *sem)
Deallocates a semaphore.
- void sys_sem_signal(sys_sem_t *sem)
Signals a semaphore.
- u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
Blocks the thread while waiting for the semaphore to be
signaled. If the "timeout" argument is non-zero, the thread should
only be blocked for the specified time (measured in
milliseconds). If the "timeout" argument is zero, the thread should be
blocked until the semaphore is signalled.
If the timeout argument is non-zero, the return value is the number of
milliseconds spent waiting for the semaphore to be signaled. If the
semaphore wasn't signaled within the specified time, the return value is
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
(i.e., it was already signaled), the function may return zero.
Notice that lwIP implements a function with a similar name,
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
- int sys_sem_valid(sys_sem_t *sem)
Returns 1 if the semaphore is valid, 0 if it is not valid.
When using pointers, a simple way is to check the pointer for != NULL.
When directly using OS structures, implementing this may be more complex.
This may also be a define, in which case the function is not prototyped.
- void sys_sem_set_invalid(sys_sem_t *sem)
Invalidate a semaphore so that sys_sem_valid() returns 0.
ATTENTION: This does NOT mean that the semaphore shall be deallocated:
sys_sem_free() is always called before calling this function!
This may also be a define, in which case the function is not prototyped.
- err_t sys_mbox_new(sys_mbox_t *mbox, int size)
Creates an empty mailbox for maximum "size" elements. Elements stored
in mailboxes are pointers. You have to define macros "_MBOX_SIZE"
in your lwipopts.h, or ignore this parameter in your implementation
and use a default size.
If the mailbox has been created, ERR_OK should be returned. Returning any
other error will provide a hint what went wrong, but except for assertions,
no real error handling is implemented.
- void sys_mbox_free(sys_mbox_t *mbox)
Deallocates a mailbox. If there are messages still present in the
mailbox when the mailbox is deallocated, it is an indication of a
programming error in lwIP and the developer should be notified.
- void sys_mbox_post(sys_mbox_t *mbox, void *msg)
Posts the "msg" to the mailbox. This function have to block until
the "msg" is really posted.
- err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
Try to post the "msg" to the mailbox. Returns ERR_MEM if this one
is full, else, ERR_OK if the "msg" is posted.
- u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
Blocks the thread until a message arrives in the mailbox, but does
not block the thread longer than "timeout" milliseconds (similar to
the sys_arch_sem_wait() function). If "timeout" is 0, the thread should
be blocked until a message arrives. The "msg" argument is a result
parameter that is set by the function (i.e., by doing "*msg =
ptr"). The "msg" parameter maybe NULL to indicate that the message
should be dropped.
The return values are the same as for the sys_arch_sem_wait() function:
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
timeout.
Note that a function with a similar name, sys_mbox_fetch(), is
implemented by lwIP.
- u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
This is similar to sys_arch_mbox_fetch, however if a message is not
present in the mailbox, it immediately returns with the code
SYS_MBOX_EMPTY. On success 0 is returned.
To allow for efficient implementations, this can be defined as a
function-like macro in sys_arch.h instead of a normal function. For
example, a naive implementation could be:
#define sys_arch_mbox_tryfetch(mbox,msg) \
sys_arch_mbox_fetch(mbox,msg,1)
although this would introduce unnecessary delays.
- int sys_mbox_valid(sys_mbox_t *mbox)
Returns 1 if the mailbox is valid, 0 if it is not valid.
When using pointers, a simple way is to check the pointer for != NULL.
When directly using OS structures, implementing this may be more complex.
This may also be a define, in which case the function is not prototyped.
- void sys_mbox_set_invalid(sys_mbox_t *mbox)
Invalidate a mailbox so that sys_mbox_valid() returns 0.
ATTENTION: This does NOT mean that the mailbox shall be deallocated:
sys_mbox_free() is always called before calling this function!
This may also be a define, in which case the function is not prototyped.
If threads are supported by the underlying operating system and if
such functionality is needed in lwIP, the following function will have
to be implemented as well:
- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
Starts a new thread named "name" with priority "prio" that will begin its
execution in the function "thread()". The "arg" argument will be passed as an
argument to the thread() function. The stack size to used for this thread is
the "stacksize" parameter. The id of the new thread is returned. Both the id
and the priority are system dependent.
- sys_prot_t sys_arch_protect(void)
This optional function does a "fast" critical region protection and returns
the previous protection level. This function is only called during very short
critical regions. An embedded system which supports ISR-based drivers might
want to implement this function by disabling interrupts. Task-based systems
might want to implement this by using a mutex or disabling tasking. This
function should support recursive calls from the same task or interrupt. In
other words, sys_arch_protect() could be called while already protected. In
that case the return value indicates that it is already protected.
sys_arch_protect() is only required if your port is supporting an operating
system.
- void sys_arch_unprotect(sys_prot_t pval)
This optional function does a "fast" set of critical region protection to the
value specified by pval. See the documentation for sys_arch_protect() for
more information. This function is only required if your port is supporting
an operating system.
For some configurations, you also need:
- u32_t sys_now(void)
This optional function returns the current time in milliseconds (don't care
for wraparound, this is only used for time diffs).
Not implementing this function means you cannot use some modules (e.g. TCP
timestamps, internal timeouts for NO_SYS==1).
Note:
Be carefull with using mem_malloc() in sys_arch. When malloc() refers to
mem_malloc() you can run into a circular function call problem. In mem.c
mem_init() tries to allcate a semaphore using mem_malloc, which of course
can't be performed when sys_arch uses mem_malloc.
-------------------------------------------------------------------------------
Additional files required for the "OS support" emulation layer:
-------------------------------------------------------------------------------
cc.h - Architecture environment, some compiler specific, some
environment specific (probably should move env stuff
to sys_arch.h.)
Typedefs for the types used by lwip -
u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t
Compiler hints for packing lwip's structures -
PACK_STRUCT_FIELD(x)
PACK_STRUCT_STRUCT
PACK_STRUCT_BEGIN
PACK_STRUCT_END
Platform specific diagnostic output -
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
Portability defines for printf formatters:
U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
"lightweight" synchronization mechanisms -
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
SYS_ARCH_PROTECT(x) - enter protection mode.
SYS_ARCH_UNPROTECT(x) - leave protection mode.
If the compiler does not provide memset() this file must include a
definition of it, or include a file which defines it.
This file must either include a system-local <errno.h> which defines
the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO
to make lwip/arch.h define the codes which are used throughout.
perf.h - Architecture specific performance measurement.
Measurement calls made throughout lwip, these can be defined to nothing.
PERF_START - start measuring something.
PERF_STOP(x) - stop measuring something, and record the result.
sys_arch.h - Tied to sys_arch.c
Arch dependent types for the following objects:
sys_sem_t, sys_mbox_t, sys_thread_t,
And, optionally:
sys_prot_t
Defines to set vars of sys_mbox_t and sys_sem_t to NULL.
SYS_MBOX_NULL NULL
SYS_SEM_NULL NULL

View File

@ -1,13 +0,0 @@
api/ - The code for the high-level wrapper API. Not needed if
you use the lowel-level call-back/raw API.
core/ - The core of the TPC/IP stack; protocol implementations,
memory and buffer management, and the low-level raw API.
include/ - lwIP include files.
netif/ - Generic network interface device drivers are kept here,
as well as the ARP module.
For more information on the various subdirectories, check the FILES
file in each directory.

View File

@ -1,780 +0,0 @@
/**
* @file
* Sequential API External module
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/* This is the part of the API that is linked with
the application */
#include "lwip/opt.h"
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
#include "lwip/api.h"
#include "lwip/tcpip.h"
#include "lwip/memp.h"
#include "lwip/ip.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include <string.h>
/**
* Create a new netconn (of a specific type) that has a callback function.
* The corresponding pcb is also created.
*
* @param t the type of 'connection' to create (@see enum netconn_type)
* @param proto the IP protocol for RAW IP pcbs
* @param callback a function to call on status changes (RX available, TX'ed)
* @return a newly allocated struct netconn or
* NULL on memory error
*/
struct netconn*
netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
{
struct netconn *conn;
struct api_msg msg;
conn = netconn_alloc(t, callback);
if (conn != NULL) {
msg.function = do_newconn;
msg.msg.msg.n.proto = proto;
msg.msg.conn = conn;
if (TCPIP_APIMSG(&msg) != ERR_OK) {
LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
#if LWIP_TCP
LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
#endif /* LWIP_TCP */
sys_sem_free(&conn->op_completed);
sys_mbox_free(&conn->recvmbox);
memp_free(MEMP_NETCONN, conn);
return NULL;
}
}
return conn;
}
/**
* Close a netconn 'connection' and free its resources.
* UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
* after this returns.
*
* @param conn the netconn to delete
* @return ERR_OK if the connection was deleted
*/
err_t
netconn_delete(struct netconn *conn)
{
struct api_msg msg;
/* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
if (conn == NULL) {
return ERR_OK;
}
msg.function = do_delconn;
msg.msg.conn = conn;
tcpip_apimsg(&msg);
netconn_free(conn);
/* don't care for return value of do_delconn since it only calls void functions */
return ERR_OK;
}
/**
* Get the local or remote IP address and port of a netconn.
* For RAW netconns, this returns the protocol instead of a port!
*
* @param conn the netconn to query
* @param addr a pointer to which to save the IP address
* @param port a pointer to which to save the port (or protocol for RAW)
* @param local 1 to get the local IP address, 0 to get the remote one
* @return ERR_CONN for invalid connections
* ERR_OK if the information was retrieved
*/
err_t
netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
msg.function = do_getaddr;
msg.msg.conn = conn;
msg.msg.msg.ad.ipaddr = addr;
msg.msg.msg.ad.port = port;
msg.msg.msg.ad.local = local;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Bind a netconn to a specific local IP address and port.
* Binding one netconn twice might not always be checked correctly!
*
* @param conn the netconn to bind
* @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY
* to bind to all addresses)
* @param port the local port to bind the netconn to (not used for RAW)
* @return ERR_OK if bound, any other err_t on failure
*/
err_t
netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_bind;
msg.msg.conn = conn;
msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Connect a netconn to a specific remote IP address and port.
*
* @param conn the netconn to connect
* @param addr the remote IP address to connect to
* @param port the remote port to connect to (no used for RAW)
* @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
*/
err_t
netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_connect;
msg.msg.conn = conn;
msg.msg.msg.bc.ipaddr = addr;
msg.msg.msg.bc.port = port;
/* This is the only function which need to not block tcpip_thread */
err = tcpip_apimsg(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Disconnect a netconn from its current peer (only valid for UDP netconns).
*
* @param conn the netconn to disconnect
* @return TODO: return value is not set here...
*/
err_t
netconn_disconnect(struct netconn *conn)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_disconnect;
msg.msg.conn = conn;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Set a TCP netconn into listen mode
*
* @param conn the tcp netconn to set to listen mode
* @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
* @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
* don't return any error (yet?))
*/
err_t
netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
{
#if LWIP_TCP
struct api_msg msg;
err_t err;
/* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
LWIP_UNUSED_ARG(backlog);
LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_listen;
msg.msg.conn = conn;
#if TCP_LISTEN_BACKLOG
msg.msg.msg.lb.backlog = backlog;
#endif /* TCP_LISTEN_BACKLOG */
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(backlog);
return ERR_ARG;
#endif /* LWIP_TCP */
}
/**
* Accept a new connection on a TCP listening netconn.
*
* @param conn the TCP listen netconn
* @param new_conn pointer where the new connection is stored
* @return ERR_OK if a new connection has been received or an error
* code otherwise
*/
err_t
netconn_accept(struct netconn *conn, struct netconn **new_conn)
{
#if LWIP_TCP
struct netconn *newconn;
err_t err;
#if TCP_LISTEN_BACKLOG
struct api_msg msg;
#endif /* TCP_LISTEN_BACKLOG */
LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
*new_conn = NULL;
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;);
err = conn->last_err;
if (ERR_IS_FATAL(err)) {
/* don't recv on fatal errors: this might block the application task
waiting on acceptmbox forever! */
return err;
}
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
return ERR_TIMEOUT;
}
#else
sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);
#endif /* LWIP_SO_RCVTIMEO*/
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
if (newconn == NULL) {
/* connection has been aborted */
NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
return ERR_ABRT;
}
#if TCP_LISTEN_BACKLOG
/* Let the stack know that we have accepted the connection. */
msg.function = do_recv;
msg.msg.conn = conn;
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
#endif /* TCP_LISTEN_BACKLOG */
*new_conn = newconn;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(new_conn);
return ERR_ARG;
#endif /* LWIP_TCP */
}
/**
* Receive data: actual implementation that doesn't care whether pbuf or netbuf
* is received
*
* @param conn the netconn from which to receive data
* @param new_buf pointer where a new pbuf/netbuf is stored when received data
* @return ERR_OK if data has been received, an error code otherwise (timeout,
* memory error or another error)
*/
static err_t
netconn_recv_data(struct netconn *conn, void **new_buf)
{
void *buf = NULL;
u16_t len;
err_t err;
#if LWIP_TCP
struct api_msg msg;
#endif /* LWIP_TCP */
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
*new_buf = NULL;
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
err = conn->last_err;
if (ERR_IS_FATAL(err)) {
/* don't recv on fatal errors: this might block the application task
waiting on recvmbox forever! */
/* @todo: this does not allow us to fetch data that has been put into recvmbox
before the fatal error occurred - is that a problem? */
return err;
}
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
return ERR_TIMEOUT;
}
#else
sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
#endif /* LWIP_SO_RCVTIMEO*/
#if LWIP_TCP
#if (LWIP_UDP || LWIP_RAW)
if (conn->type == NETCONN_TCP)
#endif /* (LWIP_UDP || LWIP_RAW) */
{
if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
/* Let the stack know that we have taken the data. */
/* TODO: Speedup: Don't block and wait for the answer here
(to prevent multiple thread-switches). */
msg.function = do_recv;
msg.msg.conn = conn;
if (buf != NULL) {
msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;
} else {
msg.msg.msg.r.len = 1;
}
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
}
/* If we are closed, we indicate that we no longer wish to use the socket */
if (buf == NULL) {
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
/* Avoid to lose any previous error code */
NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
return ERR_CLSD;
}
len = ((struct pbuf *)buf)->tot_len;
}
#endif /* LWIP_TCP */
#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
else
#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
#if (LWIP_UDP || LWIP_RAW)
{
LWIP_ASSERT("buf != NULL", buf != NULL);
len = netbuf_len((struct netbuf *)buf);
}
#endif /* (LWIP_UDP || LWIP_RAW) */
#if LWIP_SO_RCVBUF
SYS_ARCH_DEC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
*new_buf = buf;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
}
/**
* Receive data (in form of a pbuf) from a TCP netconn
*
* @param conn the netconn from which to receive data
* @param new_buf pointer where a new pbuf is stored when received data
* @return ERR_OK if data has been received, an error code otherwise (timeout,
* memory error or another error)
* ERR_ARG if conn is not a TCP netconn
*/
err_t
netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
{
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
netconn_type(conn) == NETCONN_TCP, return ERR_ARG;);
return netconn_recv_data(conn, (void **)new_buf);
}
/**
* Receive data (in form of a netbuf containing a packet buffer) from a netconn
*
* @param conn the netconn from which to receive data
* @param new_buf pointer where a new netbuf is stored when received data
* @return ERR_OK if data has been received, an error code otherwise (timeout,
* memory error or another error)
*/
err_t
netconn_recv(struct netconn *conn, struct netbuf **new_buf)
{
#if LWIP_TCP
struct netbuf *buf = NULL;
err_t err;
#endif /* LWIP_TCP */
LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
*new_buf = NULL;
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
#if LWIP_TCP
#if (LWIP_UDP || LWIP_RAW)
if (conn->type == NETCONN_TCP)
#endif /* (LWIP_UDP || LWIP_RAW) */
{
struct pbuf *p = NULL;
/* This is not a listening netconn, since recvmbox is set */
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
if (buf == NULL) {
NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
return ERR_MEM;
}
err = netconn_recv_data(conn, (void **)&p);
if (err != ERR_OK) {
memp_free(MEMP_NETBUF, buf);
return err;
}
LWIP_ASSERT("p != NULL", p != NULL);
buf->p = p;
buf->ptr = p;
buf->port = 0;
ip_addr_set_any(&buf->addr);
*new_buf = buf;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
}
#endif /* LWIP_TCP */
#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
else
#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
{
#if (LWIP_UDP || LWIP_RAW)
return netconn_recv_data(conn, (void **)new_buf);
#endif /* (LWIP_UDP || LWIP_RAW) */
}
}
/**
* TCP: update the receive window: by calling this, the application
* tells the stack that it has processed data and is able to accept
* new data.
* ATTENTION: use with care, this is mainly used for sockets!
* Can only be used when calling netconn_set_noautorecved(conn, 1) before.
*
* @param conn the netconn for which to update the receive window
* @param length amount of data processed (ATTENTION: this must be accurate!)
*/
void
netconn_recved(struct netconn *conn, u32_t length)
{
#if LWIP_TCP
if ((conn != NULL) && (conn->type == NETCONN_TCP) &&
(netconn_get_noautorecved(conn))) {
struct api_msg msg;
/* Let the stack know that we have taken the data. */
/* TODO: Speedup: Don't block and wait for the answer here
(to prevent multiple thread-switches). */
msg.function = do_recv;
msg.msg.conn = conn;
msg.msg.msg.r.len = length;
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
}
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(length);
#endif /* LWIP_TCP */
}
/**
* Send data (in form of a netbuf) to a specific remote IP address and port.
* Only to be used for UDP and RAW netconns (not TCP).
*
* @param conn the netconn over which to send data
* @param buf a netbuf containing the data to send
* @param addr the remote IP address to which to send the data
* @param port the remote port to which to send the data
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)
{
if (buf != NULL) {
ip_addr_set(&buf->addr, addr);
buf->port = port;
return netconn_send(conn, buf);
}
return ERR_VAL;
}
/**
* Send data over a UDP or RAW netconn (that is already connected).
*
* @param conn the UDP or RAW netconn over which to send data
* @param buf a netbuf containing the data to send
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_send(struct netconn *conn, struct netbuf *buf)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
msg.function = do_send;
msg.msg.conn = conn;
msg.msg.msg.b = buf;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Send data over a TCP netconn.
*
* @param conn the TCP netconn over which to send data
* @param dataptr pointer to the application buffer that contains the data to send
* @param size size of the application data to send
* @param apiflags combination of following flags :
* - NETCONN_COPY: data will be copied into memory belonging to the stack
* - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
* - NETCONN_DONTBLOCK: only write the data if all dat can be written at once
* @param bytes_written pointer to a location that receives the number of written bytes
* @return ERR_OK if data was sent, any other err_t on error
*/
err_t
netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
u8_t apiflags, size_t *bytes_written)
{
struct api_msg msg;
err_t err;
u8_t dontblock;
LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
if (size == 0) {
return ERR_OK;
}
dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
if (dontblock && !bytes_written) {
/* This implies netconn_write() cannot be used for non-blocking send, since
it has no way to return the number of bytes written. */
return ERR_VAL;
}
/* non-blocking write sends as much */
msg.function = do_write;
msg.msg.conn = conn;
msg.msg.msg.w.dataptr = dataptr;
msg.msg.msg.w.apiflags = apiflags;
msg.msg.msg.w.len = size;
#if LWIP_SO_SNDTIMEO
if (conn->send_timeout != 0) {
/* get the time we started, which is later compared to
sys_now() + conn->send_timeout */
msg.msg.msg.w.time_started = sys_now();
} else {
msg.msg.msg.w.time_started = 0;
}
#endif /* LWIP_SO_SNDTIMEO */
/* For locking the core: this _can_ be delayed on low memory/low send buffer,
but if it is, this is done inside api_msg.c:do_write(), so we can use the
non-blocking version here. */
err = TCPIP_APIMSG(&msg);
if ((err == ERR_OK) && (bytes_written != NULL)) {
if (dontblock
#if LWIP_SO_SNDTIMEO
|| (conn->send_timeout != 0)
#endif /* LWIP_SO_SNDTIMEO */
) {
/* nonblocking write: maybe the data has been sent partly */
*bytes_written = msg.msg.msg.w.len;
} else {
/* blocking call succeeded: all data has been sent if it */
*bytes_written = size;
}
}
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Close ot shutdown a TCP netconn (doesn't delete it).
*
* @param conn the TCP netconn to close or shutdown
* @param how fully close or only shutdown one side?
* @return ERR_OK if the netconn was closed, any other err_t on error
*/
static err_t
netconn_close_shutdown(struct netconn *conn, u8_t how)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_close;
msg.msg.conn = conn;
/* shutting down both ends is the same as closing */
msg.msg.msg.sd.shut = how;
/* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,
don't use TCPIP_APIMSG here */
err = tcpip_apimsg(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
* Close a TCP netconn (doesn't delete it).
*
* @param conn the TCP netconn to close
* @return ERR_OK if the netconn was closed, any other err_t on error
*/
err_t
netconn_close(struct netconn *conn)
{
/* shutting down both ends is the same as closing */
return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
}
/**
* Shut down one or both sides of a TCP netconn (doesn't delete it).
*
* @param conn the TCP netconn to shut down
* @return ERR_OK if the netconn was closed, any other err_t on error
*/
err_t
netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
{
return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
}
#if LWIP_IGMP
/**
* Join multicast groups for UDP netconns.
*
* @param conn the UDP netconn for which to change multicast addresses
* @param multiaddr IP address of the multicast group to join or leave
* @param netif_addr the IP address of the network interface on which to send
* the igmp message
* @param join_or_leave flag whether to send a join- or leave-message
* @return ERR_OK if the action was taken, any err_t on error
*/
err_t
netconn_join_leave_group(struct netconn *conn,
ip_addr_t *multiaddr,
ip_addr_t *netif_addr,
enum netconn_igmp join_or_leave)
{
struct api_msg msg;
err_t err;
LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_join_leave_group;
msg.msg.conn = conn;
msg.msg.msg.jl.multiaddr = multiaddr;
msg.msg.msg.jl.netif_addr = netif_addr;
msg.msg.msg.jl.join_or_leave = join_or_leave;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
#endif /* LWIP_IGMP */
#if LWIP_DNS
/**
* Execute a DNS query, only one IP address is returned
*
* @param name a string representation of the DNS host name to query
* @param addr a preallocated ip_addr_t where to store the resolved IP address
* @return ERR_OK: resolving succeeded
* ERR_MEM: memory error, try again later
* ERR_ARG: dns client not initialized or invalid hostname
* ERR_VAL: dns server response was invalid
*/
err_t
netconn_gethostbyname(const char *name, ip_addr_t *addr)
{
struct dns_api_msg msg;
err_t err;
sys_sem_t sem;
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
err = sys_sem_new(&sem, 0);
if (err != ERR_OK) {
return err;
}
msg.name = name;
msg.addr = addr;
msg.err = &err;
msg.sem = &sem;
tcpip_callback(do_gethostbyname, &msg);
sys_sem_wait(&sem);
sys_sem_free(&sem);
return err;
}
#endif /* LWIP_DNS*/
#endif /* LWIP_NETCONN */

File diff suppressed because it is too large Load Diff

View File

@ -1,75 +0,0 @@
/**
* @file
* Error Management module
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/err.h"
#ifdef LWIP_DEBUG
static const char *err_strerr[] = {
"Ok.", /* ERR_OK 0 */
"Out of memory error.", /* ERR_MEM -1 */
"Buffer error.", /* ERR_BUF -2 */
"Timeout.", /* ERR_TIMEOUT -3 */
"Routing problem.", /* ERR_RTE -4 */
"Operation in progress.", /* ERR_INPROGRESS -5 */
"Illegal value.", /* ERR_VAL -6 */
"Operation would block.", /* ERR_WOULDBLOCK -7 */
"Address in use.", /* ERR_USE -8 */
"Already connected.", /* ERR_ISCONN -9 */
"Connection aborted.", /* ERR_ABRT -10 */
"Connection reset.", /* ERR_RST -11 */
"Connection closed.", /* ERR_CLSD -12 */
"Not connected.", /* ERR_CONN -13 */
"Illegal argument.", /* ERR_ARG -14 */
"Low-level netif error.", /* ERR_IF -15 */
};
/**
* Convert an lwip internal error to a string representation.
*
* @param err an lwip internal err_t
* @return a string representation for err
*/
const char *
lwip_strerr(err_t err)
{
return err_strerr[-err];
}
#endif /* LWIP_DEBUG */

View File

@ -1,245 +0,0 @@
/**
* @file
* Network buffer management
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
#include "lwip/netbuf.h"
#include "lwip/memp.h"
#include <string.h>
/**
* Create (allocate) and initialize a new netbuf.
* The netbuf doesn't yet contain a packet buffer!
*
* @return a pointer to a new netbuf
* NULL on lack of memory
*/
struct
netbuf *netbuf_new(void)
{
struct netbuf *buf;
buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
if (buf != NULL) {
buf->p = NULL;
buf->ptr = NULL;
ip_addr_set_any(&buf->addr);
buf->port = 0;
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
#if LWIP_CHECKSUM_ON_COPY
buf->flags = 0;
#endif /* LWIP_CHECKSUM_ON_COPY */
buf->toport_chksum = 0;
#if LWIP_NETBUF_RECVINFO
ip_addr_set_any(&buf->toaddr);
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
return buf;
} else {
return NULL;
}
}
/**
* Deallocate a netbuf allocated by netbuf_new().
*
* @param buf pointer to a netbuf allocated by netbuf_new()
*/
void
netbuf_delete(struct netbuf *buf)
{
if (buf != NULL) {
if (buf->p != NULL) {
pbuf_free(buf->p);
buf->p = buf->ptr = NULL;
}
memp_free(MEMP_NETBUF, buf);
}
}
/**
* Allocate memory for a packet buffer for a given netbuf.
*
* @param buf the netbuf for which to allocate a packet buffer
* @param size the size of the packet buffer to allocate
* @return pointer to the allocated memory
* NULL if no memory could be allocated
*/
void *
netbuf_alloc(struct netbuf *buf, u16_t size)
{
LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;);
/* Deallocate any previously allocated memory. */
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
if (buf->p == NULL) {
return NULL;
}
LWIP_ASSERT("check that first pbuf can hold size",
(buf->p->len >= size));
buf->ptr = buf->p;
return buf->p->payload;
}
/**
* Free the packet buffer included in a netbuf
*
* @param buf pointer to the netbuf which contains the packet buffer to free
*/
void
netbuf_free(struct netbuf *buf)
{
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = buf->ptr = NULL;
}
/**
* Let a netbuf reference existing (non-volatile) data.
*
* @param buf netbuf which should reference the data
* @param dataptr pointer to the data to reference
* @param size size of the data
* @return ERR_OK if data is referenced
* ERR_MEM if data couldn't be referenced due to lack of memory
*/
err_t
netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
{
LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;);
if (buf->p != NULL) {
pbuf_free(buf->p);
}
buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
if (buf->p == NULL) {
buf->ptr = NULL;
return ERR_MEM;
}
buf->p->payload = (void*)dataptr;
buf->p->len = buf->p->tot_len = size;
buf->ptr = buf->p;
return ERR_OK;
}
/**
* Chain one netbuf to another (@see pbuf_chain)
*
* @param head the first netbuf
* @param tail netbuf to chain after head, freed by this function, may not be reference after returning
*/
void
netbuf_chain(struct netbuf *head, struct netbuf *tail)
{
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
pbuf_cat(head->p, tail->p);
head->ptr = head->p;
memp_free(MEMP_NETBUF, tail);
}
/**
* Get the data pointer and length of the data inside a netbuf.
*
* @param buf netbuf to get the data from
* @param dataptr pointer to a void pointer where to store the data pointer
* @param len pointer to an u16_t where the length of the data is stored
* @return ERR_OK if the information was retreived,
* ERR_BUF on error.
*/
err_t
netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
{
LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;);
LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;);
LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;);
if (buf->ptr == NULL) {
return ERR_BUF;
}
*dataptr = buf->ptr->payload;
*len = buf->ptr->len;
return ERR_OK;
}
/**
* Move the current data pointer of a packet buffer contained in a netbuf
* to the next part.
* The packet buffer itself is not modified.
*
* @param buf the netbuf to modify
* @return -1 if there is no next part
* 1 if moved to the next part but now there is no next part
* 0 if moved to the next part and there are still more parts
*/
s8_t
netbuf_next(struct netbuf *buf)
{
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);
if (buf->ptr->next == NULL) {
return -1;
}
buf->ptr = buf->ptr->next;
if (buf->ptr->next == NULL) {
return 1;
}
return 0;
}
/**
* Move the current data pointer of a packet buffer contained in a netbuf
* to the beginning of the packet.
* The packet buffer itself is not modified.
*
* @param buf the netbuf to modify
*/
void
netbuf_first(struct netbuf *buf)
{
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
buf->ptr = buf->p;
}
#endif /* LWIP_NETCONN */

View File

@ -1,353 +0,0 @@
/**
* @file
* API functions for name resolving
*
*/
/*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt
*
*/
#include "lwip/netdb.h"
#if LWIP_DNS && LWIP_SOCKET
#include "lwip/err.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/ip_addr.h"
#include "lwip/api.h"
#include "lwip/dns.h"
#include <string.h>
#include <stdlib.h>
/** helper struct for gethostbyname_r to access the char* buffer */
struct gethostbyname_r_helper {
ip_addr_t *addr_list[2];
ip_addr_t addr;
char *aliases;
};
/** h_errno is exported in netdb.h for access by applications. */
#if LWIP_DNS_API_DECLARE_H_ERRNO
int h_errno;
#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */
/** define "hostent" variables storage: 0 if we use a static (but unprotected)
* set of variables for lwip_gethostbyname, 1 if we use a local storage */
#ifndef LWIP_DNS_API_HOSTENT_STORAGE
#define LWIP_DNS_API_HOSTENT_STORAGE 0
#endif
/** define "hostent" variables storage */
#if LWIP_DNS_API_HOSTENT_STORAGE
#define HOSTENT_STORAGE
#else
#define HOSTENT_STORAGE static
#endif /* LWIP_DNS_API_STATIC_HOSTENT */
/**
* Returns an entry containing addresses of address family AF_INET
* for the host with name name.
* Due to dns_gethostbyname limitations, only one address is returned.
*
* @param name the hostname to resolve
* @return an entry containing addresses of address family AF_INET
* for the host with name name
*/
struct hostent*
lwip_gethostbyname(const char *name)
{
err_t err;
ip_addr_t addr;
/* buffer variables for lwip_gethostbyname() */
HOSTENT_STORAGE struct hostent s_hostent;
HOSTENT_STORAGE char *s_aliases;
HOSTENT_STORAGE ip_addr_t s_hostent_addr;
HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
/* query host IP address */
err = netconn_gethostbyname(name, &addr);
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
h_errno = HOST_NOT_FOUND;
return NULL;
}
/* fill hostent */
s_hostent_addr = addr;
s_phostent_addr[0] = &s_hostent_addr;
s_phostent_addr[1] = NULL;
s_hostent.h_name = (char*)name;
s_hostent.h_aliases = &s_aliases;
s_hostent.h_addrtype = AF_INET;
s_hostent.h_length = sizeof(ip_addr_t);
s_hostent.h_addr_list = (char**)&s_phostent_addr;
#if DNS_DEBUG
/* dump hostent */
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases));
if (s_hostent.h_aliases != NULL) {
u8_t idx;
for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
}
}
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list));
if (s_hostent.h_addr_list != NULL) {
u8_t idx;
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx])));
}
}
#endif /* DNS_DEBUG */
#if LWIP_DNS_API_HOSTENT_STORAGE
/* this function should return the "per-thread" hostent after copy from s_hostent */
return sys_thread_hostent(&s_hostent);
#else
return &s_hostent;
#endif /* LWIP_DNS_API_HOSTENT_STORAGE */
}
/**
* Thread-safe variant of lwip_gethostbyname: instead of using a static
* buffer, this function takes buffer and errno pointers as arguments
* and uses these for the result.
*
* @param name the hostname to resolve
* @param ret pre-allocated struct where to store the result
* @param buf pre-allocated buffer where to store additional data
* @param buflen the size of buf
* @param result pointer to a hostent pointer that is set to ret on success
* and set to zero on error
* @param h_errnop pointer to an int where to store errors (instead of modifying
* the global h_errno)
* @return 0 on success, non-zero on error, additional error information
* is stored in *h_errnop instead of h_errno to be thread-safe
*/
int
lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
size_t buflen, struct hostent **result, int *h_errnop)
{
err_t err;
struct gethostbyname_r_helper *h;
char *hostname;
size_t namelen;
int lh_errno;
if (h_errnop == NULL) {
/* ensure h_errnop is never NULL */
h_errnop = &lh_errno;
}
if (result == NULL) {
/* not all arguments given */
*h_errnop = EINVAL;
return -1;
}
/* first thing to do: set *result to nothing */
*result = NULL;
if ((name == NULL) || (ret == NULL) || (buf == NULL)) {
/* not all arguments given */
*h_errnop = EINVAL;
return -1;
}
namelen = strlen(name);
if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {
/* buf can't hold the data needed + a copy of name */
*h_errnop = ERANGE;
return -1;
}
h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);
hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
/* query host IP address */
err = netconn_gethostbyname(name, &h->addr);
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
*h_errnop = HOST_NOT_FOUND;
return -1;
}
/* copy the hostname into buf */
MEMCPY(hostname, name, namelen);
hostname[namelen] = 0;
/* fill hostent */
h->addr_list[0] = &h->addr;
h->addr_list[1] = NULL;
h->aliases = NULL;
ret->h_name = hostname;
ret->h_aliases = &h->aliases;
ret->h_addrtype = AF_INET;
ret->h_length = sizeof(ip_addr_t);
ret->h_addr_list = (char**)&h->addr_list;
/* set result != NULL */
*result = ret;
/* return success */
return 0;
}
/**
* Frees one or more addrinfo structures returned by getaddrinfo(), along with
* any additional storage associated with those structures. If the ai_next field
* of the structure is not null, the entire list of structures is freed.
*
* @param ai struct addrinfo to free
*/
void
lwip_freeaddrinfo(struct addrinfo *ai)
{
struct addrinfo *next;
while (ai != NULL) {
next = ai->ai_next;
memp_free(MEMP_NETDB, ai);
ai = next;
}
}
/**
* Translates the name of a service location (for example, a host name) and/or
* a service name and returns a set of socket addresses and associated
* information to be used in creating a socket with which to address the
* specified service.
* Memory for the result is allocated internally and must be freed by calling
* lwip_freeaddrinfo()!
*
* Due to a limitation in dns_gethostbyname, only the first address of a
* host is returned.
* Also, service names are not supported (only port numbers)!
*
* @param nodename descriptive name or address string of the host
* (may be NULL -> local address)
* @param servname port number as string of NULL
* @param hints structure containing input values that set socktype and protocol
* @param res pointer to a pointer where to store the result (set to NULL on failure)
* @return 0 on success, non-zero on failure
*/
int
lwip_getaddrinfo(const char *nodename, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
err_t err;
ip_addr_t addr;
struct addrinfo *ai;
struct sockaddr_in *sa = NULL;
int port_nr = 0;
size_t total_size;
size_t namelen = 0;
if (res == NULL) {
return EAI_FAIL;
}
*res = NULL;
if ((nodename == NULL) && (servname == NULL)) {
return EAI_NONAME;
}
if (servname != NULL) {
/* service name specified: convert to port number
* @todo?: currently, only ASCII integers (port numbers) are supported! */
port_nr = atoi(servname);
if ((port_nr <= 0) || (port_nr > 0xffff)) {
return EAI_SERVICE;
}
}
if (nodename != NULL) {
/* service location specified, try to resolve */
err = netconn_gethostbyname(nodename, &addr);
if (err != ERR_OK) {
return EAI_FAIL;
}
} else {
/* service location specified, use loopback address */
ip_addr_set_loopback(&addr);
}
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
if (nodename != NULL) {
namelen = strlen(nodename);
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
total_size += namelen + 1;
}
/* If this fails, please report to lwip-devel! :-) */
LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
total_size <= NETDB_ELEM_SIZE);
ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
if (ai == NULL) {
goto memerr;
}
memset(ai, 0, total_size);
sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
/* set up sockaddr */
inet_addr_from_ipaddr(&sa->sin_addr, &addr);
sa->sin_family = AF_INET;
sa->sin_len = sizeof(struct sockaddr_in);
sa->sin_port = htons((u16_t)port_nr);
/* set up addrinfo */
ai->ai_family = AF_INET;
if (hints != NULL) {
/* copy socktype & protocol from hints if specified */
ai->ai_socktype = hints->ai_socktype;
ai->ai_protocol = hints->ai_protocol;
}
if (nodename != NULL) {
/* copy nodename to canonname if specified */
ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
MEMCPY(ai->ai_canonname, nodename, namelen);
ai->ai_canonname[namelen] = 0;
}
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr = (struct sockaddr*)sa;
*res = ai;
return 0;
memerr:
if (ai != NULL) {
memp_free(MEMP_NETDB, ai);
}
return EAI_MEMORY;
}
#endif /* LWIP_DNS && LWIP_SOCKET */

View File

@ -1,160 +0,0 @@
/**
* @file
* Network Interface Sequential API module
*
*/
/*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwip/opt.h"
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
#include "lwip/netifapi.h"
#include "lwip/tcpip.h"
/**
* Call netif_add() inside the tcpip_thread context.
*/
void
do_netifapi_netif_add(struct netifapi_msg_msg *msg)
{
if (!netif_add( msg->netif,
msg->msg.add.ipaddr,
msg->msg.add.netmask,
msg->msg.add.gw,
msg->msg.add.state,
msg->msg.add.init,
msg->msg.add.input)) {
msg->err = ERR_IF;
} else {
msg->err = ERR_OK;
}
TCPIP_NETIFAPI_ACK(msg);
}
/**
* Call netif_set_addr() inside the tcpip_thread context.
*/
void
do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
{
netif_set_addr( msg->netif,
msg->msg.add.ipaddr,
msg->msg.add.netmask,
msg->msg.add.gw);
msg->err = ERR_OK;
TCPIP_NETIFAPI_ACK(msg);
}
/**
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
* tcpip_thread context.
*/
void
do_netifapi_netif_common(struct netifapi_msg_msg *msg)
{
if (msg->msg.common.errtfunc != NULL) {
msg->err = msg->msg.common.errtfunc(msg->netif);
} else {
msg->err = ERR_OK;
msg->msg.common.voidfunc(msg->netif);
}
TCPIP_NETIFAPI_ACK(msg);
}
/**
* Call netif_add() in a thread-safe way by running that function inside the
* tcpip_thread context.
*
* @note for params @see netif_add()
*/
err_t
netifapi_netif_add(struct netif *netif,
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw,
void *state,
netif_init_fn init,
netif_input_fn input)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_add;
msg.msg.netif = netif;
msg.msg.msg.add.ipaddr = ipaddr;
msg.msg.msg.add.netmask = netmask;
msg.msg.msg.add.gw = gw;
msg.msg.msg.add.state = state;
msg.msg.msg.add.init = init;
msg.msg.msg.add.input = input;
TCPIP_NETIFAPI(&msg);
return msg.msg.err;
}
/**
* Call netif_set_addr() in a thread-safe way by running that function inside the
* tcpip_thread context.
*
* @note for params @see netif_set_addr()
*/
err_t
netifapi_netif_set_addr(struct netif *netif,
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_set_addr;
msg.msg.netif = netif;
msg.msg.msg.add.ipaddr = ipaddr;
msg.msg.msg.add.netmask = netmask;
msg.msg.msg.add.gw = gw;
TCPIP_NETIFAPI(&msg);
return msg.msg.err;
}
/**
* call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
* way by running that function inside the tcpip_thread context.
*
* @note use only for functions where there is only "netif" parameter.
*/
err_t
netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,
netifapi_errt_fn errtfunc)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_common;
msg.msg.netif = netif;
msg.msg.msg.common.voidfunc = voidfunc;
msg.msg.msg.common.errtfunc = errtfunc;
TCPIP_NETIFAPI(&msg);
return msg.msg.err;
}
#endif /* LWIP_NETIF_API */

File diff suppressed because it is too large Load Diff

View File

@ -1,511 +0,0 @@
/**
* @file
* Sequential API Main thread module
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
#include "lwip/sys.h"
#include "lwip/memp.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/tcpip.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "netif/ppp_oe.h"
/* global variables */
static tcpip_init_done_fn tcpip_init_done;
static void *tcpip_init_done_arg;
static sys_mbox_t mbox;
#if LWIP_TCPIP_CORE_LOCKING
/** The global semaphore to lock the stack. */
sys_mutex_t lock_tcpip_core;
#endif /* LWIP_TCPIP_CORE_LOCKING */
/**
* The main lwIP thread. This thread has exclusive access to lwIP core functions
* (unless access to them is not locked). Other threads communicate with this
* thread using message boxes.
*
* It also starts all the timers to make sure they are running in the right
* thread context.
*
* @param arg unused argument
*/
static void
tcpip_thread(void *arg)
{
struct tcpip_msg *msg;
LWIP_UNUSED_ARG(arg);
if (tcpip_init_done != NULL) {
tcpip_init_done(tcpip_init_done_arg);
}
LOCK_TCPIP_CORE();
while (1) { /* MAIN Loop */
UNLOCK_TCPIP_CORE();
LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */
sys_timeouts_mbox_fetch(&mbox, (void **)&msg);
LOCK_TCPIP_CORE();
switch (msg->type) {
#if LWIP_NETCONN
case TCPIP_MSG_API:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
break;
#endif /* LWIP_NETCONN */
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
case TCPIP_MSG_INPKT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
#if LWIP_ETHERNET
if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
} else
#endif /* LWIP_ETHERNET */
{
ip_input(msg->msg.inp.p, msg->msg.inp.netif);
}
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
break;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
#if LWIP_NETIF_API
case TCPIP_MSG_NETIFAPI:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
break;
#endif /* LWIP_NETIF_API */
#if LWIP_TCPIP_TIMEOUT
case TCPIP_MSG_TIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
case TCPIP_MSG_UNTIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
#endif /* LWIP_TCPIP_TIMEOUT */
case TCPIP_MSG_CALLBACK:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
case TCPIP_MSG_CALLBACK_STATIC:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
break;
default:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
break;
}
}
}
/**
* Pass a received packet to tcpip_thread for input processing
*
* @param p the received packet, p->payload pointing to the Ethernet header or
* to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
* NETIF_FLAG_ETHERNET flags)
* @param inp the network interface on which the packet was received
*/
err_t
tcpip_input(struct pbuf *p, struct netif *inp)
{
#if LWIP_TCPIP_CORE_LOCKING_INPUT
err_t ret;
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp));
LOCK_TCPIP_CORE();
#if LWIP_ETHERNET
if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
ret = ethernet_input(p, inp);
} else
#endif /* LWIP_ETHERNET */
{
ret = ip_input(p, inp);
}
UNLOCK_TCPIP_CORE();
return ret;
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
struct tcpip_msg *msg;
if (!sys_mbox_valid(&mbox)) {
return ERR_VAL;
}
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_INPKT;
msg->msg.inp.p = p;
msg->msg.inp.netif = inp;
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
return ERR_MEM;
}
return ERR_OK;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
}
/**
* Call a specific function in the thread context of
* tcpip_thread for easy access synchronization.
* A function called in that way may access lwIP core code
* without fearing concurrent access.
*
* @param f the function to call
* @param ctx parameter passed to f
* @param block 1 to block until the request is posted, 0 to non-blocking mode
* @return ERR_OK if the function was called, another err_t if not
*/
err_t
tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)
{
struct tcpip_msg *msg;
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_CALLBACK;
msg->msg.cb.function = function;
msg->msg.cb.ctx = ctx;
if (block) {
sys_mbox_post(&mbox, msg);
} else {
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_API, msg);
return ERR_MEM;
}
}
return ERR_OK;
}
return ERR_VAL;
}
#if LWIP_TCPIP_TIMEOUT
/**
* call sys_timeout in tcpip_thread
*
* @param msec time in milliseconds for timeout
* @param h function to be called on timeout
* @param arg argument to pass to timeout function h
* @return ERR_MEM on memory error, ERR_OK otherwise
*/
err_t
tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_TIMEOUT;
msg->msg.tmo.msecs = msecs;
msg->msg.tmo.h = h;
msg->msg.tmo.arg = arg;
sys_mbox_post(&mbox, msg);
return ERR_OK;
}
return ERR_VAL;
}
/**
* call sys_untimeout in tcpip_thread
*
* @param msec time in milliseconds for timeout
* @param h function to be called on timeout
* @param arg argument to pass to timeout function h
* @return ERR_MEM on memory error, ERR_OK otherwise
*/
err_t
tcpip_untimeout(sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_UNTIMEOUT;
msg->msg.tmo.h = h;
msg->msg.tmo.arg = arg;
sys_mbox_post(&mbox, msg);
return ERR_OK;
}
return ERR_VAL;
}
#endif /* LWIP_TCPIP_TIMEOUT */
#if LWIP_NETCONN
/**
* Call the lower part of a netconn_* function
* This function is then running in the thread context
* of tcpip_thread and has exclusive access to lwIP core code.
*
* @param apimsg a struct containing the function to call and its parameters
* @return ERR_OK if the function was called, another err_t if not
*/
err_t
tcpip_apimsg(struct api_msg *apimsg)
{
struct tcpip_msg msg;
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
if (sys_mbox_valid(&mbox)) {
msg.type = TCPIP_MSG_API;
msg.msg.apimsg = apimsg;
sys_mbox_post(&mbox, &msg);
sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);
return apimsg->msg.err;
}
return ERR_VAL;
}
#if LWIP_TCPIP_CORE_LOCKING
/**
* Call the lower part of a netconn_* function
* This function has exclusive access to lwIP core code by locking it
* before the function is called.
*
* @param apimsg a struct containing the function to call and its parameters
* @return ERR_OK (only for compatibility fo tcpip_apimsg())
*/
err_t
tcpip_apimsg_lock(struct api_msg *apimsg)
{
#ifdef LWIP_DEBUG
/* catch functions that don't set err */
apimsg->msg.err = ERR_VAL;
#endif
LOCK_TCPIP_CORE();
apimsg->function(&(apimsg->msg));
UNLOCK_TCPIP_CORE();
return apimsg->msg.err;
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETCONN */
#if LWIP_NETIF_API
#if !LWIP_TCPIP_CORE_LOCKING
/**
* Much like tcpip_apimsg, but calls the lower part of a netifapi_*
* function.
*
* @param netifapimsg a struct containing the function to call and its parameters
* @return error code given back by the function that was called
*/
err_t
tcpip_netifapi(struct netifapi_msg* netifapimsg)
{
struct tcpip_msg msg;
if (sys_mbox_valid(&mbox)) {
err_t err = sys_sem_new(&netifapimsg->msg.sem, 0);
if (err != ERR_OK) {
netifapimsg->msg.err = err;
return err;
}
msg.type = TCPIP_MSG_NETIFAPI;
msg.msg.netifapimsg = netifapimsg;
sys_mbox_post(&mbox, &msg);
sys_sem_wait(&netifapimsg->msg.sem);
sys_sem_free(&netifapimsg->msg.sem);
return netifapimsg->msg.err;
}
return ERR_VAL;
}
#else /* !LWIP_TCPIP_CORE_LOCKING */
/**
* Call the lower part of a netifapi_* function
* This function has exclusive access to lwIP core code by locking it
* before the function is called.
*
* @param netifapimsg a struct containing the function to call and its parameters
* @return ERR_OK (only for compatibility fo tcpip_netifapi())
*/
err_t
tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
{
LOCK_TCPIP_CORE();
netifapimsg->function(&(netifapimsg->msg));
UNLOCK_TCPIP_CORE();
return netifapimsg->msg.err;
}
#endif /* !LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETIF_API */
/**
* Allocate a structure for a static callback message and initialize it.
* This is intended to be used to send "static" messages from interrupt context.
*
* @param function the function to call
* @param ctx parameter passed to function
* @return a struct pointer to pass to tcpip_trycallback().
*/
struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
{
struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return NULL;
}
msg->type = TCPIP_MSG_CALLBACK_STATIC;
msg->msg.cb.function = function;
msg->msg.cb.ctx = ctx;
return (struct tcpip_callback_msg*)msg;
}
/**
* Free a callback message allocated by tcpip_callbackmsg_new().
*
* @param msg the message to free
*/
void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
{
memp_free(MEMP_TCPIP_MSG_API, msg);
}
/**
* Try to post a callback-message to the tcpip_thread mbox
* This is intended to be used to send "static" messages from interrupt context.
*
* @param msg pointer to the message to post
* @return sys_mbox_trypost() return code
*/
err_t
tcpip_trycallback(struct tcpip_callback_msg* msg)
{
if (!sys_mbox_valid(&mbox)) {
return ERR_VAL;
}
return sys_mbox_trypost(&mbox, msg);
}
/**
* Initialize this module:
* - initialize all sub modules
* - start the tcpip_thread
*
* @param initfunc a function to call when tcpip_thread is running and finished initializing
* @param arg argument to pass to initfunc
*/
void
tcpip_init(tcpip_init_done_fn initfunc, void *arg)
{
lwip_init();
tcpip_init_done = initfunc;
tcpip_init_done_arg = arg;
if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
}
#if LWIP_TCPIP_CORE_LOCKING
if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
LWIP_ASSERT("failed to create lock_tcpip_core", 0);
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
}
/**
* Simple callback function used with tcpip_callback to free a pbuf
* (pbuf_free has a wrong signature for tcpip_callback)
*
* @param p The pbuf (chain) to be dereferenced.
*/
static void
pbuf_free_int(void *p)
{
struct pbuf *q = (struct pbuf *)p;
pbuf_free(q);
}
/**
* A simple wrapper function that allows you to free a pbuf from interrupt context.
*
* @param p The pbuf (chain) to be dereferenced.
* @return ERR_OK if callback could be enqueued, an err_t if not
*/
err_t
pbuf_free_callback(struct pbuf *p)
{
return tcpip_callback_with_block(pbuf_free_int, p, 0);
}
/**
* A simple wrapper function that allows you to free heap memory from
* interrupt context.
*
* @param m the heap memory to free
* @return ERR_OK if callback could be enqueued, an err_t if not
*/
err_t
mem_free_callback(void *m)
{
return tcpip_callback_with_block(mem_free, m, 0);
}
#endif /* !NO_SYS */

View File

@ -1,108 +0,0 @@
/**
* @file
* Common functions used throughout the stack.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt
*
*/
#include "lwip/opt.h"
#include "lwip/def.h"
/**
* These are reference implementations of the byte swapping functions.
* Again with the aim of being simple, correct and fully portable.
* Byte swapping is the second thing you would want to optimize. You will
* need to port it to your architecture and in your cc.h:
*
* #define LWIP_PLATFORM_BYTESWAP 1
* #define LWIP_PLATFORM_HTONS(x) <your_htons>
* #define LWIP_PLATFORM_HTONL(x) <your_htonl>
*
* Note ntohs() and ntohl() are merely references to the htonx counterparts.
*/
#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
/**
* Convert an u16_t from host- to network byte order.
*
* @param n u16_t in host byte order
* @return n in network byte order
*/
u16_t
lwip_htons(u16_t n)
{
return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
}
/**
* Convert an u16_t from network- to host byte order.
*
* @param n u16_t in network byte order
* @return n in host byte order
*/
u16_t
lwip_ntohs(u16_t n)
{
return lwip_htons(n);
}
/**
* Convert an u32_t from host- to network byte order.
*
* @param n u32_t in host byte order
* @return n in network byte order
*/
u32_t
lwip_htonl(u32_t n)
{
return ((n & 0xff) << 24) |
((n & 0xff00) << 8) |
((n & 0xff0000UL) >> 8) |
((n & 0xff000000UL) >> 24);
}
/**
* Convert an u32_t from network- to host byte order.
*
* @param n u32_t in network byte order
* @return n in host byte order
*/
u32_t
lwip_ntohl(u32_t n)
{
return lwip_htonl(n);
}
#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */

File diff suppressed because it is too large Load Diff

View File

@ -1,970 +0,0 @@
/**
* @file
* DNS - host name to IP address resolver.
*
*/
/**
* This file implements a DNS host name to IP address resolver.
* Port to lwIP from uIP
* by Jim Pettinato April 2007
* uIP version Copyright (c) 2002-2003, Adam Dunkels.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* DNS.C
*
* The lwIP DNS resolver functions are used to lookup a host name and
* map it to a numerical IP address. It maintains a list of resolved
* hostnames that can be queried with the dns_lookup() function.
* New hostnames can be resolved using the dns_query() function.
*
* The lwIP version of the resolver also adds a non-blocking version of
* gethostbyname() that will work with a raw API application. This function
* checks for an IP address string first and converts it if it is valid.
* gethostbyname() then does a dns_lookup() to see if the name is
* already in the table. If so, the IP is returned. If not, a query is
* issued and the function returns with a ERR_INPROGRESS status. The app
* using the dns client must then go into a waiting state.
*
* Once a hostname has been resolved (or found to be non-existent),
* the resolver code calls a specified callback function (which
* must be implemented by the module that uses the resolver).
*/
/*-----------------------------------------------------------------------------
* RFC 1035 - Domain names - implementation and specification
* RFC 2181 - Clarifications to the DNS Specification
*----------------------------------------------------------------------------*/
/** @todo: define good default values (rfc compliance) */
/** @todo: improve answer parsing, more checkings... */
/** @todo: check RFC1035 - 7.3. Processing responses */
/*-----------------------------------------------------------------------------
* Includes
*----------------------------------------------------------------------------*/
#include "lwip/opt.h"
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#include "lwip/udp.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/dns.h"
#include <string.h>
/** DNS server IP address */
#ifndef DNS_SERVER_ADDRESS
#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
#endif
/** DNS server port address */
#ifndef DNS_SERVER_PORT
#define DNS_SERVER_PORT 53
#endif
/** DNS maximum number of retries when asking for a name, before "timeout". */
#ifndef DNS_MAX_RETRIES
#define DNS_MAX_RETRIES 4
#endif
/** DNS resource record max. TTL (one week as default) */
#ifndef DNS_MAX_TTL
#define DNS_MAX_TTL 604800
#endif
/* DNS protocol flags */
#define DNS_FLAG1_RESPONSE 0x80
#define DNS_FLAG1_OPCODE_STATUS 0x10
#define DNS_FLAG1_OPCODE_INVERSE 0x08
#define DNS_FLAG1_OPCODE_STANDARD 0x00
#define DNS_FLAG1_AUTHORATIVE 0x04
#define DNS_FLAG1_TRUNC 0x02
#define DNS_FLAG1_RD 0x01
#define DNS_FLAG2_RA 0x80
#define DNS_FLAG2_ERR_MASK 0x0f
#define DNS_FLAG2_ERR_NONE 0x00
#define DNS_FLAG2_ERR_NAME 0x03
/* DNS protocol states */
#define DNS_STATE_UNUSED 0
#define DNS_STATE_NEW 1
#define DNS_STATE_ASKING 2
#define DNS_STATE_DONE 3
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** DNS message header */
struct dns_hdr {
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u8_t flags1);
PACK_STRUCT_FIELD(u8_t flags2);
PACK_STRUCT_FIELD(u16_t numquestions);
PACK_STRUCT_FIELD(u16_t numanswers);
PACK_STRUCT_FIELD(u16_t numauthrr);
PACK_STRUCT_FIELD(u16_t numextrarr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_DNS_HDR 12
/** DNS query message structure.
No packing needed: only used locally on the stack. */
struct dns_query {
/* DNS query record starts with either a domain name or a pointer
to a name already present somewhere in the packet. */
u16_t type;
u16_t cls;
};
#define SIZEOF_DNS_QUERY 4
/** DNS answer message structure.
No packing needed: only used locally on the stack. */
struct dns_answer {
/* DNS answer record starts with either a domain name or a pointer
to a name already present somewhere in the packet. */
u16_t type;
u16_t cls;
u32_t ttl;
u16_t len;
};
#define SIZEOF_DNS_ANSWER 10
/** DNS table entry */
struct dns_table_entry {
u8_t state;
u8_t numdns;
u8_t tmr;
u8_t retries;
u8_t seqno;
u8_t err;
u32_t ttl;
char name[DNS_MAX_NAME_LENGTH];
ip_addr_t ipaddr;
/* pointer to callback on DNS query done */
dns_found_callback found;
void *arg;
};
#if DNS_LOCAL_HOSTLIST
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
/** Local host-list. For hostnames in this list, no
* external name resolution is performed */
static struct local_hostlist_entry *local_hostlist_dynamic;
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
/** Defining this allows the local_hostlist_static to be placed in a different
* linker section (e.g. FLASH) */
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
/** Defining this allows the local_hostlist_static to be placed in a different
* linker section (e.g. FLASH) */
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
#define DNS_LOCAL_HOSTLIST_STORAGE_POST
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
static void dns_init_local();
#endif /* DNS_LOCAL_HOSTLIST */
/* forward declarations */
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
static void dns_check_entries(void);
/*-----------------------------------------------------------------------------
* Globales
*----------------------------------------------------------------------------*/
/* DNS variables */
static struct udp_pcb *dns_pcb;
static u8_t dns_seqno;
static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
static ip_addr_t dns_servers[DNS_MAX_SERVERS];
/** Contiguous buffer for processing responses */
static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
static u8_t* dns_payload;
/**
* Initialize the resolver: set up the UDP pcb and configure the default server
* (DNS_SERVER_ADDRESS).
*/
void
dns_init()
{
ip_addr_t dnsserver;
dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
/* initialize default DNS server address */
DNS_SERVER_ADDRESS(&dnsserver);
LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
/* if dns client not yet initialized... */
if (dns_pcb == NULL) {
dns_pcb = udp_new();
if (dns_pcb != NULL) {
/* initialize DNS table not needed (initialized to zero since it is a
* global variable) */
LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
DNS_STATE_UNUSED == 0);
/* initialize DNS client */
udp_bind(dns_pcb, IP_ADDR_ANY, 0);
udp_recv(dns_pcb, dns_recv, NULL);
/* initialize default DNS primary server */
dns_setserver(0, &dnsserver);
}
}
#if DNS_LOCAL_HOSTLIST
dns_init_local();
#endif
}
/**
* Initialize one of the DNS servers.
*
* @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
* @param dnsserver IP address of the DNS server to set
*/
void
dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
{
if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
(dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
dns_servers[numdns] = (*dnsserver);
}
}
/**
* Obtain one of the currently configured DNS server.
*
* @param numdns the index of the DNS server
* @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
* server has not been configured.
*/
ip_addr_t
dns_getserver(u8_t numdns)
{
if (numdns < DNS_MAX_SERVERS) {
return dns_servers[numdns];
} else {
return *IP_ADDR_ANY;
}
}
/**
* The DNS resolver client timer - handle retries and timeouts and should
* be called every DNS_TMR_INTERVAL milliseconds (every second by default).
*/
void
dns_tmr(void)
{
if (dns_pcb != NULL) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
dns_check_entries();
}
}
#if DNS_LOCAL_HOSTLIST
static void
dns_init_local()
{
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
int i;
struct local_hostlist_entry *entry;
/* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
size_t namelen;
for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
namelen = strlen(init_entry->name);
LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
if (entry != NULL) {
entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
MEMCPY((char*)entry->name, init_entry->name, namelen);
((char*)entry->name)[namelen] = 0;
entry->addr = init_entry->addr;
entry->next = local_hostlist_dynamic;
local_hostlist_dynamic = entry;
}
}
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
}
/**
* Scans the local host-list for a hostname.
*
* @param hostname Hostname to look for in the local host-list
* @return The first IP address for the hostname in the local host-list or
* IPADDR_NONE if not found.
*/
static u32_t
dns_lookup_local(const char *hostname)
{
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
struct local_hostlist_entry *entry = local_hostlist_dynamic;
while(entry != NULL) {
if(strcmp(entry->name, hostname) == 0) {
return ip4_addr_get_u32(&entry->addr);
}
entry = entry->next;
}
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
int i;
for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
return ip4_addr_get_u32(&local_hostlist_static[i].addr);
}
}
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
return IPADDR_NONE;
}
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
/** Remove all entries from the local host-list for a specific hostname
* and/or IP addess
*
* @param hostname hostname for which entries shall be removed from the local
* host-list
* @param addr address for which entries shall be removed from the local host-list
* @return the number of removed entries
*/
int
dns_local_removehost(const char *hostname, const ip_addr_t *addr)
{
int removed = 0;
struct local_hostlist_entry *entry = local_hostlist_dynamic;
struct local_hostlist_entry *last_entry = NULL;
while (entry != NULL) {
if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
struct local_hostlist_entry *free_entry;
if (last_entry != NULL) {
last_entry->next = entry->next;
} else {
local_hostlist_dynamic = entry->next;
}
free_entry = entry;
entry = entry->next;
memp_free(MEMP_LOCALHOSTLIST, free_entry);
removed++;
} else {
last_entry = entry;
entry = entry->next;
}
}
return removed;
}
/**
* Add a hostname/IP address pair to the local host-list.
* Duplicates are not checked.
*
* @param hostname hostname of the new entry
* @param addr IP address of the new entry
* @return ERR_OK if succeeded or ERR_MEM on memory error
*/
err_t
dns_local_addhost(const char *hostname, const ip_addr_t *addr)
{
struct local_hostlist_entry *entry;
size_t namelen;
LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
namelen = strlen(hostname);
LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
if (entry == NULL) {
return ERR_MEM;
}
entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
MEMCPY((char*)entry->name, hostname, namelen);
((char*)entry->name)[namelen] = 0;
ip_addr_copy(entry->addr, *addr);
entry->next = local_hostlist_dynamic;
local_hostlist_dynamic = entry;
return ERR_OK;
}
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
#endif /* DNS_LOCAL_HOSTLIST */
/**
* Look up a hostname in the array of known hostnames.
*
* @note This function only looks in the internal array of known
* hostnames, it does not send out a query for the hostname if none
* was found. The function dns_enqueue() can be used to send a query
* for a hostname.
*
* @param name the hostname to look up
* @return the hostname's IP address, as u32_t (instead of ip_addr_t to
* better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname
* was not found in the cached dns_table.
*/
static u32_t
dns_lookup(const char *name)
{
u8_t i;
#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
u32_t addr;
#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
#if DNS_LOCAL_HOSTLIST
if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
return addr;
}
#endif /* DNS_LOCAL_HOSTLIST */
#ifdef DNS_LOOKUP_LOCAL_EXTERN
if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
return addr;
}
#endif /* DNS_LOOKUP_LOCAL_EXTERN */
/* Walk through name list, return entry if found. If not, return NULL. */
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
if ((dns_table[i].state == DNS_STATE_DONE) &&
(strcmp(name, dns_table[i].name) == 0)) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
return ip4_addr_get_u32(&dns_table[i].ipaddr);
}
}
return IPADDR_NONE;
}
#if DNS_DOES_NAME_CHECK
/**
* Compare the "dotted" name "query" with the encoded name "response"
* to make sure an answer from the DNS server matches the current dns_table
* entry (otherwise, answers might arrive late for hostname not on the list
* any more).
*
* @param query hostname (not encoded) from the dns_table
* @param response encoded hostname in the DNS response
* @return 0: names equal; 1: names differ
*/
static u8_t
dns_compare_name(unsigned char *query, unsigned char *response)
{
unsigned char n;
do {
n = *response++;
/** @see RFC 1035 - 4.1.4. Message compression */
if ((n & 0xc0) == 0xc0) {
/* Compressed name */
break;
} else {
/* Not compressed name */
while (n > 0) {
if ((*query) != (*response)) {
return 1;
}
++response;
++query;
--n;
};
++query;
}
} while (*response != 0);
return 0;
}
#endif /* DNS_DOES_NAME_CHECK */
/**
* Walk through a compact encoded DNS name and return the end of the name.
*
* @param query encoded DNS name in the DNS server response
* @return end of the name
*/
static unsigned char *
dns_parse_name(unsigned char *query)
{
unsigned char n;
do {
n = *query++;
/** @see RFC 1035 - 4.1.4. Message compression */
if ((n & 0xc0) == 0xc0) {
/* Compressed name */
break;
} else {
/* Not compressed name */
while (n > 0) {
++query;
--n;
};
}
} while (*query != 0);
return query + 1;
}
/**
* Send a DNS query packet.
*
* @param numdns index of the DNS server in the dns_servers table
* @param name hostname to query
* @param id index of the hostname in dns_table, used as transaction ID in the
* DNS query packet
* @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
*/
static err_t
dns_send(u8_t numdns, const char* name, u8_t id)
{
err_t err;
struct dns_hdr *hdr;
struct dns_query qry;
struct pbuf *p;
char *query, *nptr;
const char *pHostname;
u8_t n;
LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
(u16_t)(numdns), name));
LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
/* if here, we have either a new query or a retry on a previous query to process */
p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
SIZEOF_DNS_QUERY, PBUF_RAM);
if (p != NULL) {
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
/* fill dns header */
hdr = (struct dns_hdr*)p->payload;
memset(hdr, 0, SIZEOF_DNS_HDR);
hdr->id = htons(id);
hdr->flags1 = DNS_FLAG1_RD;
hdr->numquestions = PP_HTONS(1);
query = (char*)hdr + SIZEOF_DNS_HDR;
pHostname = name;
--pHostname;
/* convert hostname into suitable query format. */
do {
++pHostname;
nptr = query;
++query;
for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
*query = *pHostname;
++query;
++n;
}
*nptr = n;
} while(*pHostname != 0);
*query++='\0';
/* fill dns query */
qry.type = PP_HTONS(DNS_RRTYPE_A);
qry.cls = PP_HTONS(DNS_RRCLASS_IN);
SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
/* resize pbuf to the exact dns query */
pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
/* connect to the server for faster receiving */
udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
/* send dns packet */
err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
/* free pbuf */
pbuf_free(p);
} else {
err = ERR_MEM;
}
return err;
}
/**
* dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.
* Check an entry in the dns_table:
* - send out query for new entries
* - retry old pending entries on timeout (also with different servers)
* - remove completed entries from the table if their TTL has expired
*
* @param i index of the dns_table entry to check
*/
static void
dns_check_entry(u8_t i)
{
err_t err;
struct dns_table_entry *pEntry = &dns_table[i];
LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
switch(pEntry->state) {
case DNS_STATE_NEW: {
/* initialize new entry */
pEntry->state = DNS_STATE_ASKING;
pEntry->numdns = 0;
pEntry->tmr = 1;
pEntry->retries = 0;
/* send DNS packet for this entry */
err = dns_send(pEntry->numdns, pEntry->name, i);
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
("dns_send returned error: %s\n", lwip_strerr(err)));
}
break;
}
case DNS_STATE_ASKING: {
if (--pEntry->tmr == 0) {
if (++pEntry->retries == DNS_MAX_RETRIES) {
if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
/* change of server */
pEntry->numdns++;
pEntry->tmr = 1;
pEntry->retries = 0;
break;
} else {
LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
/* call specified callback function if provided */
if (pEntry->found)
(*pEntry->found)(pEntry->name, NULL, pEntry->arg);
/* flush this entry */
pEntry->state = DNS_STATE_UNUSED;
pEntry->found = NULL;
break;
}
}
/* wait longer for the next retry */
pEntry->tmr = pEntry->retries;
/* send DNS packet for this entry */
err = dns_send(pEntry->numdns, pEntry->name, i);
if (err != ERR_OK) {
LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
("dns_send returned error: %s\n", lwip_strerr(err)));
}
}
break;
}
case DNS_STATE_DONE: {
/* if the time to live is nul */
if (--pEntry->ttl == 0) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
/* flush this entry */
pEntry->state = DNS_STATE_UNUSED;
pEntry->found = NULL;
}
break;
}
case DNS_STATE_UNUSED:
/* nothing to do */
break;
default:
LWIP_ASSERT("unknown dns_table entry state:", 0);
break;
}
}
/**
* Call dns_check_entry for each entry in dns_table - check all entries.
*/
static void
dns_check_entries(void)
{
u8_t i;
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
dns_check_entry(i);
}
}
/**
* Receive input function for DNS response packets arriving for the dns UDP pcb.
*
* @params see udp.h
*/
static void
dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
{
u16_t i;
char *pHostname;
struct dns_hdr *hdr;
struct dns_answer ans;
struct dns_table_entry *pEntry;
u16_t nquestions, nanswers;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(pcb);
LWIP_UNUSED_ARG(addr);
LWIP_UNUSED_ARG(port);
/* is the dns message too big ? */
if (p->tot_len > DNS_MSG_SIZE) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
/* free pbuf and return */
goto memerr;
}
/* is the dns message big enough ? */
if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
/* free pbuf and return */
goto memerr;
}
/* copy dns payload inside static buffer for processing */
if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
/* The ID in the DNS header should be our entry into the name table. */
hdr = (struct dns_hdr*)dns_payload;
i = htons(hdr->id);
if (i < DNS_TABLE_SIZE) {
pEntry = &dns_table[i];
if(pEntry->state == DNS_STATE_ASKING) {
/* This entry is now completed. */
pEntry->state = DNS_STATE_DONE;
pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
/* We only care about the question(s) and the answers. The authrr
and the extrarr are simply discarded. */
nquestions = htons(hdr->numquestions);
nanswers = htons(hdr->numanswers);
/* Check for error. If so, call callback to inform. */
if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
/* call callback to indicate error, clean up memory and return */
goto responseerr;
}
#if DNS_DOES_NAME_CHECK
/* Check if the name in the "question" part match with the name in the entry. */
if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
/* call callback to indicate error, clean up memory and return */
goto responseerr;
}
#endif /* DNS_DOES_NAME_CHECK */
/* Skip the name in the "question" part */
pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
while (nanswers > 0) {
/* skip answer resource record's host name */
pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
/* Check for IP address type and Internet class. Others are discarded. */
SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&
(ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {
/* read the answer resource record's TTL, and maximize it if needed */
pEntry->ttl = ntohl(ans.ttl);
if (pEntry->ttl > DNS_MAX_TTL) {
pEntry->ttl = DNS_MAX_TTL;
}
/* read the IP address after answer resource record's header */
SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
/* call specified callback function if provided */
if (pEntry->found) {
(*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
}
/* deallocate memory and return */
goto memerr;
} else {
pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
}
--nanswers;
}
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
/* call callback to indicate error, clean up memory and return */
goto responseerr;
}
}
}
/* deallocate memory and return */
goto memerr;
responseerr:
/* ERROR: call specified callback function with NULL as name to indicate an error */
if (pEntry->found) {
(*pEntry->found)(pEntry->name, NULL, pEntry->arg);
}
/* flush this entry */
pEntry->state = DNS_STATE_UNUSED;
pEntry->found = NULL;
memerr:
/* free pbuf */
pbuf_free(p);
return;
}
/**
* Queues a new hostname to resolve and sends out a DNS query for that hostname
*
* @param name the hostname that is to be queried
* @param found a callback founction to be called on success, failure or timeout
* @param callback_arg argument to pass to the callback function
* @return @return a err_t return code.
*/
static err_t
dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
{
u8_t i;
u8_t lseq, lseqi;
struct dns_table_entry *pEntry = NULL;
size_t namelen;
/* search an unused entry, or the oldest one */
lseq = lseqi = 0;
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
pEntry = &dns_table[i];
/* is it an unused entry ? */
if (pEntry->state == DNS_STATE_UNUSED)
break;
/* check if this is the oldest completed entry */
if (pEntry->state == DNS_STATE_DONE) {
if ((dns_seqno - pEntry->seqno) > lseq) {
lseq = dns_seqno - pEntry->seqno;
lseqi = i;
}
}
}
/* if we don't have found an unused entry, use the oldest completed one */
if (i == DNS_TABLE_SIZE) {
if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
/* no entry can't be used now, table is full */
LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
return ERR_MEM;
} else {
/* use the oldest completed one */
i = lseqi;
pEntry = &dns_table[i];
}
}
/* use this entry */
LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
/* fill the entry */
pEntry->state = DNS_STATE_NEW;
pEntry->seqno = dns_seqno++;
pEntry->found = found;
pEntry->arg = callback_arg;
namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1);
MEMCPY(pEntry->name, name, namelen);
pEntry->name[namelen] = 0;
/* force to send query without waiting timer */
dns_check_entry(i);
/* dns query is enqueued */
return ERR_INPROGRESS;
}
/**
* Resolve a hostname (string) into an IP address.
* NON-BLOCKING callback version for use with raw API!!!
*
* Returns immediately with one of err_t return codes:
* - ERR_OK if hostname is a valid IP address string or the host
* name is already in the local names table.
* - ERR_INPROGRESS enqueue a request to be sent to the DNS server
* for resolution if no errors are present.
* - ERR_ARG: dns client not initialized or invalid hostname
*
* @param hostname the hostname that is to be queried
* @param addr pointer to a ip_addr_t where to store the address if it is already
* cached in the dns_table (only valid if ERR_OK is returned!)
* @param found a callback function to be called on success, failure or timeout (only if
* ERR_INPROGRESS is returned!)
* @param callback_arg argument to pass to the callback function
* @return a err_t return code.
*/
err_t
dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
void *callback_arg)
{
u32_t ipaddr;
/* not initialized or no valid server yet, or invalid addr pointer
* or invalid hostname or invalid hostname length */
if ((dns_pcb == NULL) || (addr == NULL) ||
(!hostname) || (!hostname[0]) ||
(strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
return ERR_ARG;
}
#if LWIP_HAVE_LOOPIF
if (strcmp(hostname, "localhost")==0) {
ip_addr_set_loopback(addr);
return ERR_OK;
}
#endif /* LWIP_HAVE_LOOPIF */
/* host name already in octet notation? set ip addr and return ERR_OK */
ipaddr = ipaddr_addr(hostname);
if (ipaddr == IPADDR_NONE) {
/* already have this address cached? */
ipaddr = dns_lookup(hostname);
}
if (ipaddr != IPADDR_NONE) {
ip4_addr_set_u32(addr, ipaddr);
return ERR_OK;
}
/* queue query with specified callback */
return dns_enqueue(hostname, found, callback_arg);
}
#endif /* LWIP_DNS */

View File

@ -1,332 +0,0 @@
/**
* @file
* Modules initialization
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/init.h"
#include "lwip/stats.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/sockets.h"
#include "lwip/ip.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcp_impl.h"
#include "lwip/snmp_msg.h"
#include "lwip/autoip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
#include "lwip/timers.h"
#include "netif/etharp.h"
#include "lwip/api.h"
/* Compile-time sanity checks for configuration errors.
* These can be done independently of LWIP_DEBUG, without penalty.
*/
#ifndef BYTE_ORDER
#error "BYTE_ORDER is not defined, you have to define it in your cc.h"
#endif
#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV)
#error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h"
#endif
#if (!LWIP_UDP && LWIP_UDPLITE)
#error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
#if (!LWIP_UDP && LWIP_SNMP)
#error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
#if (!LWIP_UDP && LWIP_DHCP)
#error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
#if (!LWIP_UDP && LWIP_IGMP)
#error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
#if (!LWIP_UDP && LWIP_SNMP)
#error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
#if (!LWIP_UDP && LWIP_DNS)
#error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"
#endif
#if !MEMP_MEM_MALLOC /* MEMP_NUM_* checks are disabled when not using the pool allocator */
#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))
#error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"
#endif
#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0))
#error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h"
#endif
#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0))
#error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h"
#endif
#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))
#error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"
#endif
#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
#endif
#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
#endif
/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))
#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
#endif
#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
#endif
#endif /* !MEMP_MEM_MALLOC */
#if (LWIP_TCP && (TCP_WND > 0xffff))
#error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
#endif
#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))
#error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
#endif
#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2))
#error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work"
#endif
#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))
#error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h"
#endif
#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))
#error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t"
#endif
#if (LWIP_NETIF_API && (NO_SYS==1))
#error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"
#endif
#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
#error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
#endif
#if (!LWIP_NETCONN && LWIP_SOCKET)
#error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"
#endif
#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP)
#error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h"
#endif
#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK)
#error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h"
#endif
#if (!LWIP_ARP && LWIP_AUTOIP)
#error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h"
#endif
#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0))
#error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h"
#endif
#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))
#error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
#endif
#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))
#error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
#endif
#if (MEM_LIBC_MALLOC && MEM_USE_POOLS)
#error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h"
#endif
#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)
#error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"
#endif
#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT)
#error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf"
#endif
#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))
#error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST"
#endif
#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT
#error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on"
#endif
#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT)
#error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT"
#endif
#if LWIP_IGMP && !defined(LWIP_RAND)
#error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value"
#endif
#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING
#error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too"
#endif
#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE
#error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets"
#endif
#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF
#error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues"
#endif
#if LWIP_NETCONN && LWIP_TCP
#if NETCONN_COPY != TCP_WRITE_FLAG_COPY
#error "NETCONN_COPY != TCP_WRITE_FLAG_COPY"
#endif
#if NETCONN_MORE != TCP_WRITE_FLAG_MORE
#error "NETCONN_MORE != TCP_WRITE_FLAG_MORE"
#endif
#endif /* LWIP_NETCONN && LWIP_TCP */
#if LWIP_SOCKET
/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */
#if SO_ACCEPTCONN != SOF_ACCEPTCONN
#error "SO_ACCEPTCONN != SOF_ACCEPTCONN"
#endif
#if SO_REUSEADDR != SOF_REUSEADDR
#error "WARNING: SO_REUSEADDR != SOF_REUSEADDR"
#endif
#if SO_KEEPALIVE != SOF_KEEPALIVE
#error "WARNING: SO_KEEPALIVE != SOF_KEEPALIVE"
#endif
#if SO_BROADCAST != SOF_BROADCAST
#error "WARNING: SO_BROADCAST != SOF_BROADCAST"
#endif
#if SO_LINGER != SOF_LINGER
#error "WARNING: SO_LINGER != SOF_LINGER"
#endif
#endif /* LWIP_SOCKET */
/* Compile-time checks for deprecated options.
*/
#ifdef MEMP_NUM_TCPIP_MSG
#error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h."
#endif
#ifdef MEMP_NUM_API_MSG
#error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h."
#endif
#ifdef TCP_REXMIT_DEBUG
#error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h."
#endif
#ifdef RAW_STATS
#error "RAW_STATS option is deprecated. Remove it from your lwipopts.h."
#endif
#ifdef ETHARP_QUEUE_FIRST
#error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h."
#endif
#ifdef ETHARP_ALWAYS_INSERT
#error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
#endif
#ifndef LWIP_DISABLE_TCP_SANITY_CHECKS
#define LWIP_DISABLE_TCP_SANITY_CHECKS 0
#endif
#ifndef LWIP_DISABLE_MEMP_SANITY_CHECKS
#define LWIP_DISABLE_MEMP_SANITY_CHECKS 0
#endif
/* MEMP sanity checks */
#if !LWIP_DISABLE_MEMP_SANITY_CHECKS
#if LWIP_NETCONN
#if MEMP_MEM_MALLOC
#if !MEMP_NUM_NETCONN && LWIP_SOCKET
#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN cannot be 0 when using sockets!"
#endif
#else /* MEMP_MEM_MALLOC */
#if MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB)
#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN. If you know what you are doing, define LWIP_DISABLE_MEMP_SANITY_CHECKS to 1 to disable this error."
#endif
#endif /* MEMP_MEM_MALLOC */
#endif /* LWIP_NETCONN */
#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */
/* TCP sanity checks */
#if !LWIP_DISABLE_TCP_SANITY_CHECKS
#if LWIP_TCP
#if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
#error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_SND_BUF < (2 * TCP_MSS)
#error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS))
#error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_SNDLOWAT >= TCP_SND_BUF
#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN
#error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if !MEMP_MEM_MALLOC && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))))
#error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#if TCP_WND < TCP_MSS
#error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error."
#endif
#endif /* LWIP_TCP */
#endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */
/**
* Perform Sanity check of user-configurable values, and initialize all modules.
*/
void
lwip_init(void)
{
/* Modules initialization */
stats_init();
#if !NO_SYS
sys_init();
#endif /* !NO_SYS */
mem_init();
memp_init();
pbuf_init();
netif_init();
#if LWIP_SOCKET
lwip_socket_init();
#endif /* LWIP_SOCKET */
ip_init();
#if LWIP_ARP
etharp_init();
#endif /* LWIP_ARP */
#if LWIP_RAW
raw_init();
#endif /* LWIP_RAW */
#if LWIP_UDP
udp_init();
#endif /* LWIP_UDP */
#if LWIP_TCP
tcp_init();
#endif /* LWIP_TCP */
#if LWIP_SNMP
snmp_init();
#endif /* LWIP_SNMP */
#if LWIP_AUTOIP
autoip_init();
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
igmp_init();
#endif /* LWIP_IGMP */
#if LWIP_DNS
dns_init();
#endif /* LWIP_DNS */
#if LWIP_TIMERS
sys_timeouts_init();
#endif /* LWIP_TIMERS */
}

View File

@ -1,528 +0,0 @@
/**
* @file
* AutoIP Automatic LinkLocal IP Configuration
*
*/
/*
*
* Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Dominik Spies <kontakt@dspies.de>
*
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
* with RFC 3927.
*
*
* Please coordinate changes and requests with Dominik Spies
* <kontakt@dspies.de>
*/
/*******************************************************************************
* USAGE:
*
* define LWIP_AUTOIP 1 in your lwipopts.h
*
* If you don't use tcpip.c (so, don't call, you don't call tcpip_init):
* - First, call autoip_init().
* - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,
* that should be defined in autoip.h.
* I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
* Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
*
* Without DHCP:
* - Call autoip_start() after netif_add().
*
* With DHCP:
* - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
* - Configure your DHCP Client.
*
*/
#include "lwip/opt.h"
#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
#include "lwip/mem.h"
#include "lwip/udp.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/autoip.h"
#include "netif/etharp.h"
#include <stdlib.h>
#include <string.h>
/* 169.254.0.0 */
#define AUTOIP_NET 0xA9FE0000
/* 169.254.1.0 */
#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)
/* 169.254.254.255 */
#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF)
/** Pseudo random macro based on netif informations.
* You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
#ifndef LWIP_AUTOIP_RAND
#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
((u32_t)((netif->hwaddr[4]) & 0xff))) + \
(netif->autoip?netif->autoip->tried_llipaddr:0))
#endif /* LWIP_AUTOIP_RAND */
/**
* Macro that generates the initial IP address to be tried by AUTOIP.
* If you want to override this, define it to something else in lwipopts.h.
*/
#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
/* static functions */
static void autoip_handle_arp_conflict(struct netif *netif);
/* creates a pseudo random LL IP-Address for a network interface */
static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr);
/* sends an ARP probe */
static err_t autoip_arp_probe(struct netif *netif);
/* sends an ARP announce */
static err_t autoip_arp_announce(struct netif *netif);
/* configure interface for use with current LL IP-Address */
static err_t autoip_bind(struct netif *netif);
/* start sending probes for llipaddr */
static void autoip_start_probing(struct netif *netif);
/** Set a statically allocated struct autoip to work with.
* Using this prevents autoip_start to allocate it using mem_malloc.
*
* @param netif the netif for which to set the struct autoip
* @param dhcp (uninitialised) dhcp struct allocated by the application
*/
void
autoip_set_struct(struct netif *netif, struct autoip *autoip)
{
LWIP_ASSERT("netif != NULL", netif != NULL);
LWIP_ASSERT("autoip != NULL", autoip != NULL);
LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL);
/* clear data structure */
memset(autoip, 0, sizeof(struct autoip));
/* autoip->state = AUTOIP_STATE_OFF; */
netif->autoip = autoip;
}
/** Restart AutoIP client and check the next address (conflict detected)
*
* @param netif The netif under AutoIP control
*/
static void
autoip_restart(struct netif *netif)
{
netif->autoip->tried_llipaddr++;
autoip_start(netif);
}
/**
* Handle a IP address conflict after an ARP conflict detection
*/
static void
autoip_handle_arp_conflict(struct netif *netif)
{
/* Somehow detect if we are defending or retreating */
unsigned char defend = 1; /* tbd */
if (defend) {
if (netif->autoip->lastconflict > 0) {
/* retreat, there was a conflicting ARP in the last
* DEFEND_INTERVAL seconds
*/
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
/* TODO: close all TCP sessions */
autoip_restart(netif);
} else {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
autoip_arp_announce(netif);
netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
}
} else {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
/* TODO: close all TCP sessions */
autoip_restart(netif);
}
}
/**
* Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
*
* @param netif network interface on which create the IP-Address
* @param ipaddr ip address to initialize
*/
static void
autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)
{
/* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
* compliant to RFC 3927 Section 2.1
* We have 254 * 256 possibilities */
u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
addr += netif->autoip->tried_llipaddr;
addr = AUTOIP_NET | (addr & 0xffff);
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
if (addr < AUTOIP_RANGE_START) {
addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
}
if (addr > AUTOIP_RANGE_END) {
addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
}
LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
(addr <= AUTOIP_RANGE_END));
ip4_addr_set_u32(ipaddr, htonl(addr));
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
(u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),
ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
}
/**
* Sends an ARP probe from a network interface
*
* @param netif network interface used to send the probe
*/
static err_t
autoip_arp_probe(struct netif *netif)
{
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
(struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, &ethzero,
&netif->autoip->llipaddr, ARP_REQUEST);
}
/**
* Sends an ARP announce from a network interface
*
* @param netif network interface used to send the announce
*/
static err_t
autoip_arp_announce(struct netif *netif)
{
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
(struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, &ethzero,
&netif->autoip->llipaddr, ARP_REQUEST);
}
/**
* Configure interface for use with current LL IP-Address
*
* @param netif network interface to configure with current LL IP-Address
*/
static err_t
autoip_bind(struct netif *netif)
{
struct autoip *autoip = netif->autoip;
ip_addr_t sn_mask, gw_addr;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num,
ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),
ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));
IP4_ADDR(&sn_mask, 255, 255, 0, 0);
IP4_ADDR(&gw_addr, 0, 0, 0, 0);
netif_set_ipaddr(netif, &autoip->llipaddr);
netif_set_netmask(netif, &sn_mask);
netif_set_gw(netif, &gw_addr);
/* bring the interface up */
netif_set_up(netif);
return ERR_OK;
}
/**
* Start AutoIP client
*
* @param netif network interface on which start the AutoIP client
*/
err_t
autoip_start(struct netif *netif)
{
struct autoip *autoip = netif->autoip;
err_t result = ERR_OK;
if (netif_is_up(netif)) {
netif_set_down(netif);
}
/* Set IP-Address, Netmask and Gateway to 0 to make sure that
* ARP Packets are formed correctly
*/
ip_addr_set_zero(&netif->ip_addr);
ip_addr_set_zero(&netif->netmask);
ip_addr_set_zero(&netif->gw);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
netif->name[1], (u16_t)netif->num));
if (autoip == NULL) {
/* no AutoIP client attached yet? */
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_start(): starting new AUTOIP client\n"));
autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));
if (autoip == NULL) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_start(): could not allocate autoip\n"));
return ERR_MEM;
}
memset(autoip, 0, sizeof(struct autoip));
/* store this AutoIP client in the netif */
netif->autoip = autoip;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
} else {
autoip->state = AUTOIP_STATE_OFF;
autoip->ttw = 0;
autoip->sent_num = 0;
ip_addr_set_zero(&autoip->llipaddr);
autoip->lastconflict = 0;
}
autoip_create_addr(netif, &(autoip->llipaddr));
autoip_start_probing(netif);
return result;
}
static void
autoip_start_probing(struct netif *netif)
{
struct autoip *autoip = netif->autoip;
autoip->state = AUTOIP_STATE_PROBING;
autoip->sent_num = 0;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
/* time to wait to first probe, this is randomly
* choosen out of 0 to PROBE_WAIT seconds.
* compliant to RFC 3927 Section 2.2.1
*/
autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));
/*
* if we tried more then MAX_CONFLICTS we must limit our rate for
* accquiring and probing address
* compliant to RFC 3927 Section 2.2.1
*/
if (autoip->tried_llipaddr > MAX_CONFLICTS) {
autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
}
}
/**
* Handle a possible change in the network configuration.
*
* If there is an AutoIP address configured, take the interface down
* and begin probing with the same address.
*/
void
autoip_network_changed(struct netif *netif)
{
if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
netif_set_down(netif);
autoip_start_probing(netif);
}
}
/**
* Stop AutoIP client
*
* @param netif network interface on which stop the AutoIP client
*/
err_t
autoip_stop(struct netif *netif)
{
netif->autoip->state = AUTOIP_STATE_OFF;
netif_set_down(netif);
return ERR_OK;
}
/**
* Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
*/
void
autoip_tmr()
{
struct netif *netif = netif_list;
/* loop through netif's */
while (netif != NULL) {
/* only act on AutoIP configured interfaces */
if (netif->autoip != NULL) {
if (netif->autoip->lastconflict > 0) {
netif->autoip->lastconflict--;
}
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
(u16_t)(netif->autoip->state), netif->autoip->ttw));
switch(netif->autoip->state) {
case AUTOIP_STATE_PROBING:
if (netif->autoip->ttw > 0) {
netif->autoip->ttw--;
} else {
if (netif->autoip->sent_num >= PROBE_NUM) {
netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
netif->autoip->sent_num = 0;
netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
} else {
autoip_arp_probe(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_tmr() PROBING Sent Probe\n"));
netif->autoip->sent_num++;
/* calculate time to wait to next probe */
netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
}
}
break;
case AUTOIP_STATE_ANNOUNCING:
if (netif->autoip->ttw > 0) {
netif->autoip->ttw--;
} else {
if (netif->autoip->sent_num == 0) {
/* We are here the first time, so we waited ANNOUNCE_WAIT seconds
* Now we can bind to an IP address and use it.
*
* autoip_bind calls netif_set_up. This triggers a gratuitous ARP
* which counts as an announcement.
*/
autoip_bind(netif);
} else {
autoip_arp_announce(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_tmr() ANNOUNCING Sent Announce\n"));
}
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
netif->autoip->sent_num++;
if (netif->autoip->sent_num >= ANNOUNCE_NUM) {
netif->autoip->state = AUTOIP_STATE_BOUND;
netif->autoip->sent_num = 0;
netif->autoip->ttw = 0;
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),
ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));
}
}
break;
}
}
/* proceed to next network interface */
netif = netif->next;
}
}
/**
* Handles every incoming ARP Packet, called by etharp_arp_input.
*
* @param netif network interface to use for autoip processing
* @param hdr Incoming ARP packet
*/
void
autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
{
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {
/* when ip.src == llipaddr && hw.src != netif->hwaddr
*
* when probing ip.dst == llipaddr && hw.src != netif->hwaddr
* we have a conflict and must solve it
*/
ip_addr_t sipaddr, dipaddr;
struct eth_addr netifaddr;
ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
* structure packing (not using structure copy which breaks strict-aliasing rules).
*/
IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
(netif->autoip->sent_num == 0))) {
/* RFC 3927 Section 2.2.1:
* from beginning to after ANNOUNCE_WAIT
* seconds we have a conflict if
* ip.src == llipaddr OR
* ip.dst == llipaddr && hw.src != own hwaddr
*/
if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
(ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
!eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
("autoip_arp_reply(): Probe Conflict detected\n"));
autoip_restart(netif);
}
} else {
/* RFC 3927 Section 2.5:
* in any state we have a conflict if
* ip.src == llipaddr && hw.src != own hwaddr
*/
if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
!eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
autoip_handle_arp_conflict(netif);
}
}
}
}
#endif /* LWIP_AUTOIP */

View File

@ -1,339 +0,0 @@
/**
* @file
* ICMP - Internet Control Message Protocol
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/* Some ICMP messages should be passed to the transport protocols. This
is not implemented. */
#include "lwip/opt.h"
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/icmp.h"
#include "lwip/inet_chksum.h"
#include "lwip/ip.h"
#include "lwip/def.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include <string.h>
/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be
* used to modify and send a response packet (and to 1 if this is not the case,
* e.g. when link header is stripped of when receiving) */
#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
/* The amount of data from the original packet to return in a dest-unreachable */
#define ICMP_DEST_UNREACH_DATASIZE 8
static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
/**
* Processes ICMP input packets, called from ip_input().
*
* Currently only processes icmp echo requests and sends
* out the echo response.
*
* @param p the icmp echo request packet, p->payload pointing to the ip header
* @param inp the netif on which this packet was received
*/
void
icmp_input(struct pbuf *p, struct netif *inp)
{
u8_t type;
#ifdef LWIP_DEBUG
u8_t code;
#endif /* LWIP_DEBUG */
struct icmp_echo_hdr *iecho;
struct ip_hdr *iphdr;
s16_t hlen;
ICMP_STATS_INC(icmp.recv);
snmp_inc_icmpinmsgs();
iphdr = (struct ip_hdr *)p->payload;
hlen = IPH_HL(iphdr) * 4;
if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
goto lenerr;
}
type = *((u8_t *)p->payload);
#ifdef LWIP_DEBUG
code = *(((u8_t *)p->payload)+1);
#endif /* LWIP_DEBUG */
switch (type) {
case ICMP_ER:
/* This is OK, echo reply might have been parsed by a raw PCB
(as obviously, an echo request has been sent, too). */
break;
case ICMP_ECHO:
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
{
int accepted = 1;
#if !LWIP_MULTICAST_PING
/* multicast destination address? */
if (ip_addr_ismulticast(&current_iphdr_dest)) {
accepted = 0;
}
#endif /* LWIP_MULTICAST_PING */
#if !LWIP_BROADCAST_PING
/* broadcast destination address? */
if (ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
accepted = 0;
}
#endif /* LWIP_BROADCAST_PING */
/* broadcast or multicast destination address not acceptd? */
if (!accepted) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
ICMP_STATS_INC(icmp.err);
pbuf_free(p);
return;
}
}
#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
goto lenerr;
}
if (inet_chksum_pbuf(p) != 0) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
pbuf_free(p);
ICMP_STATS_INC(icmp.chkerr);
snmp_inc_icmpinerrors();
return;
}
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
/* p is not big enough to contain link headers
* allocate a new one and copy p into it
*/
struct pbuf *r;
/* switch p->payload to ip header */
if (pbuf_header(p, hlen)) {
LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
goto memerr;
}
/* allocate new packet buffer with space for link headers */
r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
if (r == NULL) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
goto memerr;
}
LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
(r->len >= hlen + sizeof(struct icmp_echo_hdr)));
/* copy the whole packet including ip header */
if (pbuf_copy(r, p) != ERR_OK) {
LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
goto memerr;
}
iphdr = (struct ip_hdr *)r->payload;
/* switch r->payload back to icmp header */
if (pbuf_header(r, -hlen)) {
LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
goto memerr;
}
/* free the original p */
pbuf_free(p);
/* we now have an identical copy of p that has room for link headers */
p = r;
} else {
/* restore p->payload to point to icmp header */
if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
goto memerr;
}
}
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
/* At this point, all checks are OK. */
/* We generate an answer by switching the dest and src ip addresses,
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
iecho = (struct icmp_echo_hdr *)p->payload;
ip_addr_copy(iphdr->src, *ip_current_dest_addr());
ip_addr_copy(iphdr->dest, *ip_current_src_addr());
ICMPH_TYPE_SET(iecho, ICMP_ER);
#if CHECKSUM_GEN_ICMP
/* adjust the checksum */
if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
} else {
iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
}
#else /* CHECKSUM_GEN_ICMP */
iecho->chksum = 0;
#endif /* CHECKSUM_GEN_ICMP */
/* Set the correct TTL and recalculate the header checksum. */
IPH_TTL_SET(iphdr, ICMP_TTL);
IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
#endif /* CHECKSUM_GEN_IP */
ICMP_STATS_INC(icmp.xmit);
/* increase number of messages attempted to send */
snmp_inc_icmpoutmsgs();
/* increase number of echo replies attempted to send */
snmp_inc_icmpoutechoreps();
if(pbuf_header(p, hlen)) {
LWIP_ASSERT("Can't move over header in packet", 0);
} else {
err_t ret;
/* send an ICMP packet, src addr is the dest addr of the curren packet */
ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL,
ICMP_TTL, 0, IP_PROTO_ICMP, inp);
if (ret != ERR_OK) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
}
}
break;
default:
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
(s16_t)type, (s16_t)code));
ICMP_STATS_INC(icmp.proterr);
ICMP_STATS_INC(icmp.drop);
}
pbuf_free(p);
return;
lenerr:
pbuf_free(p);
ICMP_STATS_INC(icmp.lenerr);
snmp_inc_icmpinerrors();
return;
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
memerr:
pbuf_free(p);
ICMP_STATS_INC(icmp.err);
snmp_inc_icmpinerrors();
return;
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
}
/**
* Send an icmp 'destination unreachable' packet, called from ip_input() if
* the transport layer protocol is unknown and from udp_input() if the local
* port is not bound.
*
* @param p the input packet for which the 'unreachable' should be sent,
* p->payload pointing to the IP header
* @param t type of the 'unreachable' packet
*/
void
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
{
icmp_send_response(p, ICMP_DUR, t);
}
#if IP_FORWARD || IP_REASSEMBLY
/**
* Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.
*
* @param p the input packet for which the 'time exceeded' should be sent,
* p->payload pointing to the IP header
* @param t type of the 'time exceeded' packet
*/
void
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
{
icmp_send_response(p, ICMP_TE, t);
}
#endif /* IP_FORWARD || IP_REASSEMBLY */
/**
* Send an icmp packet in response to an incoming packet.
*
* @param p the input packet for which the 'unreachable' should be sent,
* p->payload pointing to the IP header
* @param type Type of the ICMP header
* @param code Code of the ICMP header
*/
static void
icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
{
struct pbuf *q;
struct ip_hdr *iphdr;
/* we can use the echo header here */
struct icmp_echo_hdr *icmphdr;
ip_addr_t iphdr_src;
/* ICMP header + IP header + 8 bytes of data */
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
PBUF_RAM);
if (q == NULL) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
return;
}
LWIP_ASSERT("check that first pbuf can hold icmp message",
(q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
iphdr = (struct ip_hdr *)p->payload;
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
LWIP_DEBUGF(ICMP_DEBUG, (" to "));
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
icmphdr = (struct icmp_echo_hdr *)q->payload;
icmphdr->type = type;
icmphdr->code = code;
icmphdr->id = 0;
icmphdr->seqno = 0;
/* copy fields from original packet */
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
/* calculate checksum */
icmphdr->chksum = 0;
icmphdr->chksum = inet_chksum(icmphdr, q->len);
ICMP_STATS_INC(icmp.xmit);
/* increase number of messages attempted to send */
snmp_inc_icmpoutmsgs();
/* increase number of destination unreachable messages attempted to send */
snmp_inc_icmpouttimeexcds();
ip_addr_copy(iphdr_src, iphdr->src);
ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
pbuf_free(q);
}
#endif /* LWIP_ICMP */

View File

@ -1,805 +0,0 @@
/**
* @file
* IGMP - Internet Group Management Protocol
*
*/
/*
* Copyright (c) 2002 CITEL Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is a contribution to the lwIP TCP/IP stack.
* The Swedish Institute of Computer Science and Adam Dunkels
* are specifically granted permission to redistribute this
* source code.
*/
/*-------------------------------------------------------------
Note 1)
Although the rfc requires V1 AND V2 capability
we will only support v2 since now V1 is very old (August 1989)
V1 can be added if required
a debug print and statistic have been implemented to
show this up.
-------------------------------------------------------------
-------------------------------------------------------------
Note 2)
A query for a specific group address (as opposed to ALLHOSTS)
has now been implemented as I am unsure if it is required
a debug print and statistic have been implemented to
show this up.
-------------------------------------------------------------
-------------------------------------------------------------
Note 3)
The router alert rfc 2113 is implemented in outgoing packets
but not checked rigorously incoming
-------------------------------------------------------------
Steve Reynolds
------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
* RFC 988 - Host extensions for IP multicasting - V0
* RFC 1054 - Host extensions for IP multicasting -
* RFC 1112 - Host extensions for IP multicasting - V1
* RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard)
* RFC 3376 - Internet Group Management Protocol, Version 3 - V3
* RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+
* RFC 2113 - IP Router Alert Option -
*----------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------
* Includes
*----------------------------------------------------------------------------*/
#include "lwip/opt.h"
#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/igmp.h"
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/ip.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/icmp.h"
#include "lwip/udp.h"
#include "lwip/tcp.h"
#include "lwip/stats.h"
#include "string.h"
/*
* IGMP constants
*/
#define IGMP_TTL 1
#define IGMP_MINLEN 8
#define ROUTER_ALERT 0x9404U
#define ROUTER_ALERTLEN 4
/*
* IGMP message types, including version number.
*/
#define IGMP_MEMB_QUERY 0x11 /* Membership query */
#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
/* Group membership states */
#define IGMP_GROUP_NON_MEMBER 0
#define IGMP_GROUP_DELAYING_MEMBER 1
#define IGMP_GROUP_IDLE_MEMBER 2
/**
* IGMP packet format.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct igmp_msg {
PACK_STRUCT_FIELD(u8_t igmp_msgtype);
PACK_STRUCT_FIELD(u8_t igmp_maxresp);
PACK_STRUCT_FIELD(u16_t igmp_checksum);
PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
static err_t igmp_remove_group(struct igmp_group *group);
static void igmp_timeout( struct igmp_group *group);
static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
static void igmp_send(struct igmp_group *group, u8_t type);
static struct igmp_group* igmp_group_list;
static ip_addr_t allsystems;
static ip_addr_t allrouters;
/**
* Initialize the IGMP module
*/
void
igmp_init(void)
{
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
IP4_ADDR(&allsystems, 224, 0, 0, 1);
IP4_ADDR(&allrouters, 224, 0, 0, 2);
}
#ifdef LWIP_DEBUG
/**
* Dump global IGMP groups list
*/
void
igmp_dump_group_list()
{
struct igmp_group *group = igmp_group_list;
while (group != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
group = group->next;
}
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
}
#else
#define igmp_dump_group_list()
#endif /* LWIP_DEBUG */
/**
* Start IGMP processing on interface
*
* @param netif network interface on which start IGMP processing
*/
err_t
igmp_start(struct netif *netif)
{
struct igmp_group* group;
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
group = igmp_lookup_group(netif, &allsystems);
if (group != NULL) {
group->group_state = IGMP_GROUP_IDLE_MEMBER;
group->use++;
/* Allow the igmp messages at the MAC level */
if (netif->igmp_mac_filter != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
ip_addr_debug_print(IGMP_DEBUG, &allsystems);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
}
return ERR_OK;
}
return ERR_MEM;
}
/**
* Stop IGMP processing on interface
*
* @param netif network interface on which stop IGMP processing
*/
err_t
igmp_stop(struct netif *netif)
{
struct igmp_group *group = igmp_group_list;
struct igmp_group *prev = NULL;
struct igmp_group *next;
/* look for groups joined on this interface further down the list */
while (group != NULL) {
next = group->next;
/* is it a group joined on this interface? */
if (group->netif == netif) {
/* is it the first group of the list? */
if (group == igmp_group_list) {
igmp_group_list = next;
}
/* is there a "previous" group defined? */
if (prev != NULL) {
prev->next = next;
}
/* disable the group at the MAC level */
if (netif->igmp_mac_filter != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
}
/* free group */
memp_free(MEMP_IGMP_GROUP, group);
} else {
/* change the "previous" */
prev = group;
}
/* move to "next" */
group = next;
}
return ERR_OK;
}
/**
* Report IGMP memberships for this interface
*
* @param netif network interface on which report IGMP memberships
*/
void
igmp_report_groups(struct netif *netif)
{
struct igmp_group *group = igmp_group_list;
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
while (group != NULL) {
if (group->netif == netif) {
igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
}
group = group->next;
}
}
/**
* Search for a group in the global igmp_group_list
*
* @param ifp the network interface for which to look
* @param addr the group ip address to search for
* @return a struct igmp_group* if the group has been found,
* NULL if the group wasn't found.
*/
struct igmp_group *
igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)
{
struct igmp_group *group = igmp_group_list;
while (group != NULL) {
if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
return group;
}
group = group->next;
}
/* to be clearer, we return NULL here instead of
* 'group' (which is also NULL at this point).
*/
return NULL;
}
/**
* Search for a specific igmp group and create a new one if not found-
*
* @param ifp the network interface for which to look
* @param addr the group ip address to search
* @return a struct igmp_group*,
* NULL on memory error.
*/
struct igmp_group *
igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)
{
struct igmp_group *group = igmp_group_list;
/* Search if the group already exists */
group = igmp_lookfor_group(ifp, addr);
if (group != NULL) {
/* Group already exists. */
return group;
}
/* Group doesn't exist yet, create a new one */
group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);
if (group != NULL) {
group->netif = ifp;
ip_addr_set(&(group->group_address), addr);
group->timer = 0; /* Not running */
group->group_state = IGMP_GROUP_NON_MEMBER;
group->last_reporter_flag = 0;
group->use = 0;
group->next = igmp_group_list;
igmp_group_list = group;
}
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
ip_addr_debug_print(IGMP_DEBUG, addr);
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
return group;
}
/**
* Remove a group in the global igmp_group_list
*
* @param group the group to remove from the global igmp_group_list
* @return ERR_OK if group was removed from the list, an err_t otherwise
*/
static err_t
igmp_remove_group(struct igmp_group *group)
{
err_t err = ERR_OK;
/* Is it the first group? */
if (igmp_group_list == group) {
igmp_group_list = group->next;
} else {
/* look for group further down the list */
struct igmp_group *tmpGroup;
for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
if (tmpGroup->next == group) {
tmpGroup->next = group->next;
break;
}
}
/* Group not found in the global igmp_group_list */
if (tmpGroup == NULL)
err = ERR_ARG;
}
/* free group */
memp_free(MEMP_IGMP_GROUP, group);
return err;
}
/**
* Called from ip_input() if a new IGMP packet is received.
*
* @param p received igmp packet, p->payload pointing to the ip header
* @param inp network interface on which the packet was received
* @param dest destination ip address of the igmp packet
*/
void
igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
{
struct ip_hdr * iphdr;
struct igmp_msg* igmp;
struct igmp_group* group;
struct igmp_group* groupref;
IGMP_STATS_INC(igmp.recv);
/* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
iphdr = (struct ip_hdr *)p->payload;
if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
pbuf_free(p);
IGMP_STATS_INC(igmp.lenerr);
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
return;
}
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
/* Now calculate and check the checksum */
igmp = (struct igmp_msg *)p->payload;
if (inet_chksum(igmp, p->len)) {
pbuf_free(p);
IGMP_STATS_INC(igmp.chkerr);
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
return;
}
/* Packet is ok so find an existing group */
group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */
/* If group can be found or create... */
if (!group) {
pbuf_free(p);
IGMP_STATS_INC(igmp.drop);
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
return;
}
/* NOW ACT ON THE INCOMING MESSAGE TYPE... */
switch (igmp->igmp_msgtype) {
case IGMP_MEMB_QUERY: {
/* IGMP_MEMB_QUERY to the "all systems" address ? */
if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {
/* THIS IS THE GENERAL QUERY */
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
if (igmp->igmp_maxresp == 0) {
IGMP_STATS_INC(igmp.rx_v1);
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
} else {
IGMP_STATS_INC(igmp.rx_general);
}
groupref = igmp_group_list;
while (groupref) {
/* Do not send messages on the all systems group address! */
if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
igmp_delaying_member(groupref, igmp->igmp_maxresp);
}
groupref = groupref->next;
}
} else {
/* IGMP_MEMB_QUERY to a specific group ? */
if (!ip_addr_isany(&igmp->igmp_group_address)) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
if (ip_addr_cmp(dest, &allsystems)) {
ip_addr_t groupaddr;
LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
/* we first need to re-look for the group since we used dest last time */
ip_addr_copy(groupaddr, igmp->igmp_group_address);
group = igmp_lookfor_group(inp, &groupaddr);
} else {
LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
}
if (group != NULL) {
IGMP_STATS_INC(igmp.rx_group);
igmp_delaying_member(group, igmp->igmp_maxresp);
} else {
IGMP_STATS_INC(igmp.drop);
}
} else {
IGMP_STATS_INC(igmp.proterr);
}
}
break;
}
case IGMP_V2_MEMB_REPORT: {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
IGMP_STATS_INC(igmp.rx_report);
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
/* This is on a specific group we have already looked up */
group->timer = 0; /* stopped */
group->group_state = IGMP_GROUP_IDLE_MEMBER;
group->last_reporter_flag = 0;
}
break;
}
default: {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
igmp->igmp_msgtype, group->group_state, &group, group->netif));
IGMP_STATS_INC(igmp.proterr);
break;
}
}
pbuf_free(p);
return;
}
/**
* Join a group on one network interface.
*
* @param ifaddr ip address of the network interface which should join a new group
* @param groupaddr the ip address of the group which to join
* @return ERR_OK if group was joined on the netif(s), an err_t otherwise
*/
err_t
igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
{
err_t err = ERR_VAL; /* no matching interface */
struct igmp_group *group;
struct netif *netif;
/* make sure it is multicast address */
LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
/* loop through netif's */
netif = netif_list;
while (netif != NULL) {
/* Should we join this interface ? */
if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
/* find group or create a new one if not found */
group = igmp_lookup_group(netif, groupaddr);
if (group != NULL) {
/* This should create a new group, check the state to make sure */
if (group->group_state != IGMP_GROUP_NON_MEMBER) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
} else {
/* OK - it was new group */
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
/* If first use of the group, allow the group at the MAC level */
if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
}
IGMP_STATS_INC(igmp.tx_join);
igmp_send(group, IGMP_V2_MEMB_REPORT);
igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
/* Need to work out where this timer comes from */
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
}
/* Increment group use */
group->use++;
/* Join on this interface */
err = ERR_OK;
} else {
/* Return an error even if some network interfaces are joined */
/** @todo undo any other netif already joined */
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
return ERR_MEM;
}
}
/* proceed to next network interface */
netif = netif->next;
}
return err;
}
/**
* Leave a group on one network interface.
*
* @param ifaddr ip address of the network interface which should leave a group
* @param groupaddr the ip address of the group which to leave
* @return ERR_OK if group was left on the netif(s), an err_t otherwise
*/
err_t
igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)
{
err_t err = ERR_VAL; /* no matching interface */
struct igmp_group *group;
struct netif *netif;
/* make sure it is multicast address */
LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
/* loop through netif's */
netif = netif_list;
while (netif != NULL) {
/* Should we leave this interface ? */
if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
/* find group */
group = igmp_lookfor_group(netif, groupaddr);
if (group != NULL) {
/* Only send a leave if the flag is set according to the state diagram */
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
/* If there is no other use of the group */
if (group->use <= 1) {
/* If we are the last reporter for this group */
if (group->last_reporter_flag) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
IGMP_STATS_INC(igmp.tx_leave);
igmp_send(group, IGMP_LEAVE_GROUP);
}
/* Disable the group at the MAC level */
if (netif->igmp_mac_filter != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
}
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
/* Free the group */
igmp_remove_group(group);
} else {
/* Decrement group use */
group->use--;
}
/* Leave on this interface */
err = ERR_OK;
} else {
/* It's not a fatal error on "leavegroup" */
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
}
}
/* proceed to next network interface */
netif = netif->next;
}
return err;
}
/**
* The igmp timer function (both for NO_SYS=1 and =0)
* Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).
*/
void
igmp_tmr(void)
{
struct igmp_group *group = igmp_group_list;
while (group != NULL) {
if (group->timer > 0) {
group->timer--;
if (group->timer == 0) {
igmp_timeout(group);
}
}
group = group->next;
}
}
/**
* Called if a timeout for one group is reached.
* Sends a report for this group.
*
* @param group an igmp_group for which a timeout is reached
*/
static void
igmp_timeout(struct igmp_group *group)
{
/* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
IGMP_STATS_INC(igmp.tx_report);
igmp_send(group, IGMP_V2_MEMB_REPORT);
}
}
/**
* Start a timer for an igmp group
*
* @param group the igmp_group for which to start a timer
* @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
* every call to igmp_tmr())
*/
static void
igmp_start_timer(struct igmp_group *group, u8_t max_time)
{
/* ensure the input value is > 0 */
if (max_time == 0) {
max_time = 1;
}
/* ensure the random value is > 0 */
group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
}
/**
* Delaying membership report for a group if necessary
*
* @param group the igmp_group for which "delaying" membership report
* @param maxresp query delay
*/
static void
igmp_delaying_member(struct igmp_group *group, u8_t maxresp)
{
if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&
((group->timer == 0) || (maxresp < group->timer)))) {
igmp_start_timer(group, maxresp);
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
}
}
/**
* Sends an IP packet on a network interface. This function constructs the IP header
* and calculates the IP header checksum. If the source IP address is NULL,
* the IP address of the outgoing network interface is filled in as source address.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an IP
header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
* IP address of the netif used to send is used as source address)
* @param dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header
* @param proto the PROTOCOL to be set in the IP header
* @param netif the netif on which to send this packet
* @return ERR_OK if the packet was sent OK
* ERR_BUF if p doesn't have enough space for IP/LINK headers
* returns errors returned by netif->output
*/
static err_t
igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)
{
/* This is the "router alert" option */
u16_t ra[2];
ra[0] = PP_HTONS(ROUTER_ALERT);
ra[1] = 0x0000; /* Router shall examine packet */
IGMP_STATS_INC(igmp.xmit);
return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
}
/**
* Send an igmp packet to a specific group.
*
* @param group the group to which to send the packet
* @param type the type of igmp packet to send
*/
static void
igmp_send(struct igmp_group *group, u8_t type)
{
struct pbuf* p = NULL;
struct igmp_msg* igmp = NULL;
ip_addr_t src = *IP_ADDR_ANY;
ip_addr_t* dest = NULL;
/* IP header + "router alert" option + IGMP header */
p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
if (p) {
igmp = (struct igmp_msg *)p->payload;
LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
(p->len >= sizeof(struct igmp_msg)));
ip_addr_copy(src, group->netif->ip_addr);
if (type == IGMP_V2_MEMB_REPORT) {
dest = &(group->group_address);
ip_addr_copy(igmp->igmp_group_address, group->group_address);
group->last_reporter_flag = 1; /* Remember we were the last to report */
} else {
if (type == IGMP_LEAVE_GROUP) {
dest = &allrouters;
ip_addr_copy(igmp->igmp_group_address, group->group_address);
}
}
if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
igmp->igmp_msgtype = type;
igmp->igmp_maxresp = 0;
igmp->igmp_checksum = 0;
igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);
igmp_ip_output_if(p, &src, dest, group->netif);
}
pbuf_free(p);
} else {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
IGMP_STATS_INC(igmp.memerr);
}
}
#endif /* LWIP_IGMP */

View File

@ -1,42 +0,0 @@
/**
* @file
* Functions common to all TCP/IPv4 modules, such as the byte order functions.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/inet.h"

View File

@ -1,450 +0,0 @@
/**
* @file
* Incluse internet checksum functions.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/inet_chksum.h"
#include "lwip/def.h"
#include <stddef.h>
#include <string.h>
/* These are some reference implementations of the checksum algorithm, with the
* aim of being simple, correct and fully portable. Checksumming is the
* first thing you would want to optimize for your platform. If you create
* your own version, link it in and in your cc.h put:
*
* #define LWIP_CHKSUM <your_checksum_routine>
*
* Or you can select from the implementations below by defining
* LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
*/
#ifndef LWIP_CHKSUM
# define LWIP_CHKSUM lwip_standard_chksum
# ifndef LWIP_CHKSUM_ALGORITHM
# define LWIP_CHKSUM_ALGORITHM 2
# endif
#endif
/* If none set: */
#ifndef LWIP_CHKSUM_ALGORITHM
# define LWIP_CHKSUM_ALGORITHM 0
#endif
#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
/**
* lwip checksum
*
* @param dataptr points to start of data to be summed at any boundary
* @param len length of data to be summed
* @return host order (!) lwip checksum (non-inverted Internet sum)
*
* @note accumulator size limits summable length to 64k
* @note host endianess is irrelevant (p3 RFC1071)
*/
static u16_t
lwip_standard_chksum(void *dataptr, u16_t len)
{
u32_t acc;
u16_t src;
u8_t *octetptr;
acc = 0;
/* dataptr may be at odd or even addresses */
octetptr = (u8_t*)dataptr;
while (len > 1) {
/* declare first octet as most significant
thus assume network order, ignoring host order */
src = (*octetptr) << 8;
octetptr++;
/* declare second octet as least significant */
src |= (*octetptr);
octetptr++;
acc += src;
len -= 2;
}
if (len > 0) {
/* accumulate remaining octet */
src = (*octetptr) << 8;
acc += src;
}
/* add deferred carry bits */
acc = (acc >> 16) + (acc & 0x0000ffffUL);
if ((acc & 0xffff0000UL) != 0) {
acc = (acc >> 16) + (acc & 0x0000ffffUL);
}
/* This maybe a little confusing: reorder sum using htons()
instead of ntohs() since it has a little less call overhead.
The caller must invert bits for Internet sum ! */
return htons((u16_t)acc);
}
#endif
#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
/*
* Curt McDowell
* Broadcom Corp.
* csm@broadcom.com
*
* IP checksum two bytes at a time with support for
* unaligned buffer.
* Works for len up to and including 0x20000.
* by Curt McDowell, Broadcom Corp. 12/08/2005
*
* @param dataptr points to start of data to be summed at any boundary
* @param len length of data to be summed
* @return host order (!) lwip checksum (non-inverted Internet sum)
*/
static u16_t
lwip_standard_chksum(void *dataptr, int len)
{
u8_t *pb = (u8_t *)dataptr;
u16_t *ps, t = 0;
u32_t sum = 0;
int odd = ((mem_ptr_t)pb & 1);
/* Get aligned to u16_t */
if (odd && len > 0) {
((u8_t *)&t)[1] = *pb++;
len--;
}
/* Add the bulk of the data */
ps = (u16_t *)(void *)pb;
while (len > 1) {
sum += *ps++;
len -= 2;
}
/* Consume left-over byte, if any */
if (len > 0) {
((u8_t *)&t)[0] = *(u8_t *)ps;
}
/* Add end bytes */
sum += t;
/* Fold 32-bit sum to 16 bits
calling this twice is propably faster than if statements... */
sum = FOLD_U32T(sum);
sum = FOLD_U32T(sum);
/* Swap if alignment was odd */
if (odd) {
sum = SWAP_BYTES_IN_WORD(sum);
}
return (u16_t)sum;
}
#endif
#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
/**
* An optimized checksum routine. Basically, it uses loop-unrolling on
* the checksum loop, treating the head and tail bytes specially, whereas
* the inner loop acts on 8 bytes at a time.
*
* @arg start of buffer to be checksummed. May be an odd byte address.
* @len number of bytes in the buffer to be checksummed.
* @return host order (!) lwip checksum (non-inverted Internet sum)
*
* by Curt McDowell, Broadcom Corp. December 8th, 2005
*/
static u16_t
lwip_standard_chksum(void *dataptr, int len)
{
u8_t *pb = (u8_t *)dataptr;
u16_t *ps, t = 0;
u32_t *pl;
u32_t sum = 0, tmp;
/* starts at odd byte address? */
int odd = ((mem_ptr_t)pb & 1);
if (odd && len > 0) {
((u8_t *)&t)[1] = *pb++;
len--;
}
ps = (u16_t *)pb;
if (((mem_ptr_t)ps & 3) && len > 1) {
sum += *ps++;
len -= 2;
}
pl = (u32_t *)ps;
while (len > 7) {
tmp = sum + *pl++; /* ping */
if (tmp < sum) {
tmp++; /* add back carry */
}
sum = tmp + *pl++; /* pong */
if (sum < tmp) {
sum++; /* add back carry */
}
len -= 8;
}
/* make room in upper bits */
sum = FOLD_U32T(sum);
ps = (u16_t *)pl;
/* 16-bit aligned word remaining? */
while (len > 1) {
sum += *ps++;
len -= 2;
}
/* dangling tail byte remaining? */
if (len > 0) { /* include odd byte */
((u8_t *)&t)[0] = *(u8_t *)ps;
}
sum += t; /* add end bytes */
/* Fold 32-bit sum to 16 bits
calling this twice is propably faster than if statements... */
sum = FOLD_U32T(sum);
sum = FOLD_U32T(sum);
if (odd) {
sum = SWAP_BYTES_IN_WORD(sum);
}
return (u16_t)sum;
}
#endif
/* inet_chksum_pseudo:
*
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
* IP addresses are expected to be in network byte order.
*
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
* @param src source ip address (used for checksum of pseudo header)
* @param dst destination ip address (used for checksum of pseudo header)
* @param proto ip protocol (used for checksum of pseudo header)
* @param proto_len length of the ip data part (used for checksum of pseudo header)
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
inet_chksum_pseudo(struct pbuf *p,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len)
{
u32_t acc;
u32_t addr;
struct pbuf *q;
u8_t swapped;
acc = 0;
swapped = 0;
/* iterate through all pbuf in chain */
for(q = p; q != NULL; q = q->next) {
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
(void *)q, (void *)q->next));
acc += LWIP_CHKSUM(q->payload, q->len);
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
/* just executing this next line is probably faster that the if statement needed
to check whether we really need to execute it, and does no harm */
acc = FOLD_U32T(acc);
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = SWAP_BYTES_IN_WORD(acc);
}
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
}
if (swapped) {
acc = SWAP_BYTES_IN_WORD(acc);
}
addr = ip4_addr_get_u32(src);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = ip4_addr_get_u32(dest);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
/* Fold 32-bit sum to 16 bits
calling this twice is propably faster than if statements... */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
return (u16_t)~(acc & 0xffffUL);
}
/* inet_chksum_pseudo:
*
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
* IP addresses are expected to be in network byte order.
*
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
* @param src source ip address (used for checksum of pseudo header)
* @param dst destination ip address (used for checksum of pseudo header)
* @param proto ip protocol (used for checksum of pseudo header)
* @param proto_len length of the ip data part (used for checksum of pseudo header)
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
inet_chksum_pseudo_partial(struct pbuf *p,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len, u16_t chksum_len)
{
u32_t acc;
u32_t addr;
struct pbuf *q;
u8_t swapped;
u16_t chklen;
acc = 0;
swapped = 0;
/* iterate through all pbuf in chain */
for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
(void *)q, (void *)q->next));
chklen = q->len;
if (chklen > chksum_len) {
chklen = chksum_len;
}
acc += LWIP_CHKSUM(q->payload, chklen);
chksum_len -= chklen;
LWIP_ASSERT("delete me", chksum_len < 0x7fff);
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
/* fold the upper bit down */
acc = FOLD_U32T(acc);
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = SWAP_BYTES_IN_WORD(acc);
}
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
}
if (swapped) {
acc = SWAP_BYTES_IN_WORD(acc);
}
addr = ip4_addr_get_u32(src);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = ip4_addr_get_u32(dest);
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
/* Fold 32-bit sum to 16 bits
calling this twice is propably faster than if statements... */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
return (u16_t)~(acc & 0xffffUL);
}
/* inet_chksum:
*
* Calculates the Internet checksum over a portion of memory. Used primarily for IP
* and ICMP.
*
* @param dataptr start of the buffer to calculate the checksum (no alignment needed)
* @param len length of the buffer to calculate the checksum
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
inet_chksum(void *dataptr, u16_t len)
{
return ~LWIP_CHKSUM(dataptr, len);
}
/**
* Calculate a checksum over a chain of pbufs (without pseudo-header, much like
* inet_chksum only pbufs are used).
*
* @param p pbuf chain over that the checksum should be calculated
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
inet_chksum_pbuf(struct pbuf *p)
{
u32_t acc;
struct pbuf *q;
u8_t swapped;
acc = 0;
swapped = 0;
for(q = p; q != NULL; q = q->next) {
acc += LWIP_CHKSUM(q->payload, q->len);
acc = FOLD_U32T(acc);
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = SWAP_BYTES_IN_WORD(acc);
}
}
if (swapped) {
acc = SWAP_BYTES_IN_WORD(acc);
}
return (u16_t)~(acc & 0xffffUL);
}
/* These are some implementations for LWIP_CHKSUM_COPY, which copies data
* like MEMCPY but generates a checksum at the same time. Since this is a
* performance-sensitive function, you might want to create your own version
* in assembly targeted at your hardware by defining it in lwipopts.h:
* #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)
*/
#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */
/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM.
* For architectures with big caches, data might still be in cache when
* generating the checksum after copying.
*/
u16_t
lwip_chksum_copy(void *dst, const void *src, u16_t len)
{
MEMCPY(dst, src, len);
return LWIP_CHKSUM(dst, len);
}
#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */

View File

@ -1,924 +0,0 @@
/**
* @file
* This is the IPv4 layer implementation for incoming and outgoing IP traffic.
*
* @see ip_frag.c
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/ip.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/ip_frag.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/icmp.h"
#include "lwip/igmp.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcp_impl.h"
#include "lwip/snmp.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "lwip/stats.h"
#include "arch/perf.h"
#include <string.h>
/** Set this to 0 in the rare case of wanting to call an extra function to
* generate the IP checksum (in contrast to calculating it on-the-fly). */
#ifndef LWIP_INLINE_IP_CHKSUM
#define LWIP_INLINE_IP_CHKSUM 1
#endif
#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP
#define CHECKSUM_GEN_IP_INLINE 1
#else
#define CHECKSUM_GEN_IP_INLINE 0
#endif
#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT)
#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1
/** Some defines for DHCP to let link-layer-addressed packets through while the
* netif is down.
* To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT
* to return 1 if the port is accepted and 0 if the port is not accepted.
*/
#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT)
/* accept DHCP client port and custom port */
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \
|| (LWIP_IP_ACCEPT_UDP_PORT(port)))
#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
/* accept custom port only */
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(port))
#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
/* accept DHCP client port only */
#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
#else /* LWIP_DHCP */
#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0
#endif /* LWIP_DHCP */
/**
* The interface that provided the packet for the current callback
* invocation.
*/
struct netif *current_netif;
/**
* Header of the input packet currently being processed.
*/
const struct ip_hdr *current_header;
/** Source IP address of current_header */
ip_addr_t current_iphdr_src;
/** Destination IP address of current_header */
ip_addr_t current_iphdr_dest;
/** The IP header ID of the next outgoing IP packet */
static u16_t ip_id;
/**
* Finds the appropriate network interface for a given IP address. It
* searches the list of network interfaces linearly. A match is found
* if the masked IP address of the network interface equals the masked
* IP address given to the function.
*
* @param dest the destination IP address for which to find the route
* @return the netif on which to send to reach dest
*/
struct netif *
ip_route(ip_addr_t *dest)
{
struct netif *netif;
#ifdef LWIP_HOOK_IP4_ROUTE
netif = LWIP_HOOK_IP4_ROUTE(dest);
if (netif != NULL) {
return netif;
}
#endif
/* iterate through netifs */
for (netif = netif_list; netif != NULL; netif = netif->next) {
/* network mask matches? */
if (netif_is_up(netif)) {
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
/* return netif on which to forward IP packet */
return netif;
}
}
}
if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
IP_STATS_INC(ip.rterr);
snmp_inc_ipoutnoroutes();
return NULL;
}
/* no matching netif found, use default netif */
return netif_default;
}
#if IP_FORWARD
/**
* Determine whether an IP address is in a reserved set of addresses
* that may not be forwarded, or whether datagrams to that destination
* may be forwarded.
* @param p the packet to forward
* @param dest the destination IP address
* @return 1: can forward 0: discard
*/
static int
ip_canforward(struct pbuf *p)
{
u32_t addr = ip4_addr_get_u32(ip_current_dest_addr());
if (p->flags & PBUF_FLAG_LLBCAST) {
/* don't route link-layer broadcasts */
return 0;
}
if ((p->flags & PBUF_FLAG_LLMCAST) && !IP_MULTICAST(addr)) {
/* don't route link-layer multicasts unless the destination address is an IP
multicast address */
return 0;
}
if (IP_EXPERIMENTAL(addr)) {
return 0;
}
if (IP_CLASSA(addr)) {
u32_t net = addr & IP_CLASSA_NET;
if ((net == 0) || (net == (IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) {
/* don't route loopback packets */
return 0;
}
}
return 1;
}
/**
* Forwards an IP packet. It finds an appropriate route for the
* packet, decrements the TTL value of the packet, adjusts the
* checksum and outputs the packet on the appropriate interface.
*
* @param p the packet to forward (p->payload points to IP header)
* @param iphdr the IP header of the input packet
* @param inp the netif on which this packet was received
*/
static void
ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
{
struct netif *netif;
PERF_START;
if (!ip_canforward(p)) {
goto return_noroute;
}
/* RFC3927 2.7: do not forward link-local addresses */
if (ip_addr_islinklocal(&current_iphdr_dest)) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
goto return_noroute;
}
/* Find network interface where to forward this IP packet to. */
netif = ip_route(&current_iphdr_dest);
if (netif == NULL) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n",
ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
/* @todo: send ICMP_DUR_NET? */
goto return_noroute;
}
#if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF
/* Do not forward packets onto the same network interface on which
* they arrived. */
if (netif == inp) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
goto return_noroute;
}
#endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */
/* decrement TTL */
IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
/* send ICMP if TTL == 0 */
if (IPH_TTL(iphdr) == 0) {
snmp_inc_ipinhdrerrors();
#if LWIP_ICMP
/* Don't send ICMP messages in response to ICMP messages */
if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
icmp_time_exceeded(p, ICMP_TE_TTL);
}
#endif /* LWIP_ICMP */
return;
}
/* Incrementally update the IP checksum. */
if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) {
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
} else {
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
}
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),
ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));
IP_STATS_INC(ip.fw);
IP_STATS_INC(ip.xmit);
snmp_inc_ipforwdatagrams();
PERF_STOP("ip_forward");
/* don't fragment if interface has mtu set to 0 [loopif] */
if (netif->mtu && (p->tot_len > netif->mtu)) {
if ((IPH_OFFSET(iphdr) & PP_NTOHS(IP_DF)) == 0) {
#if IP_FRAG
ip_frag(p, netif, ip_current_dest_addr());
#else /* IP_FRAG */
/* @todo: send ICMP Destination Unreacheable code 13 "Communication administratively prohibited"? */
#endif /* IP_FRAG */
} else {
/* send ICMP Destination Unreacheable code 4: "Fragmentation Needed and DF Set" */
icmp_dest_unreach(p, ICMP_DUR_FRAG);
}
return;
}
/* transmit pbuf on chosen interface */
netif->output(netif, p, &current_iphdr_dest);
return;
return_noroute:
snmp_inc_ipoutnoroutes();
}
#endif /* IP_FORWARD */
/**
* This function is called by the network interface device driver when
* an IP packet is received. The function does the basic checks of the
* IP header such as packet size being at least larger than the header
* size etc. If the packet was not destined for us, the packet is
* forwarded (using ip_forward). The IP checksum is always checked.
*
* Finally, the packet is sent to the upper layer protocol input function.
*
* @param p the received IP packet (p->payload points to IP header)
* @param inp the netif on which this packet was received
* @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
* processed, but currently always returns ERR_OK)
*/
err_t
ip_input(struct pbuf *p, struct netif *inp)
{
struct ip_hdr *iphdr;
struct netif *netif;
u16_t iphdr_hlen;
u16_t iphdr_len;
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
int check_ip_src=1;
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
IP_STATS_INC(ip.recv);
snmp_inc_ipinreceives();
/* identify the IP header */
iphdr = (struct ip_hdr *)p->payload;
if (IPH_V(iphdr) != 4) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
ip_debug_print(p);
pbuf_free(p);
IP_STATS_INC(ip.err);
IP_STATS_INC(ip.drop);
snmp_inc_ipinhdrerrors();
return ERR_OK;
}
#ifdef LWIP_HOOK_IP4_INPUT
if (LWIP_HOOK_IP4_INPUT(p, inp)) {
/* the packet has been eaten */
return ERR_OK;
}
#endif
/* obtain IP header length in number of 32-bit words */
iphdr_hlen = IPH_HL(iphdr);
/* calculate IP header length in bytes */
iphdr_hlen *= 4;
/* obtain ip length in bytes */
iphdr_len = ntohs(IPH_LEN(iphdr));
/* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
if (iphdr_hlen > p->len) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
iphdr_hlen, p->len));
}
if (iphdr_len > p->tot_len) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
iphdr_len, p->tot_len));
}
/* free (drop) packet pbufs */
pbuf_free(p);
IP_STATS_INC(ip.lenerr);
IP_STATS_INC(ip.drop);
snmp_inc_ipindiscards();
return ERR_OK;
}
/* verify checksum */
#if CHECKSUM_CHECK_IP
if (inet_chksum(iphdr, iphdr_hlen) != 0) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
ip_debug_print(p);
pbuf_free(p);
IP_STATS_INC(ip.chkerr);
IP_STATS_INC(ip.drop);
snmp_inc_ipinhdrerrors();
return ERR_OK;
}
#endif
/* Trim pbuf. This should have been done at the netif layer,
* but we'll do it anyway just to be sure that its done. */
pbuf_realloc(p, iphdr_len);
/* copy IP addresses to aligned ip_addr_t */
ip_addr_copy(current_iphdr_dest, iphdr->dest);
ip_addr_copy(current_iphdr_src, iphdr->src);
/* match packet against an interface, i.e. is this packet for us? */
#if LWIP_IGMP
if (ip_addr_ismulticast(&current_iphdr_dest)) {
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &current_iphdr_dest))) {
netif = inp;
} else {
netif = NULL;
}
} else
#endif /* LWIP_IGMP */
{
/* start trying with inp. if that's not acceptable, start walking the
list of configured netifs.
'first' is used as a boolean to mark whether we started walking the list */
int first = 1;
netif = inp;
do {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr),
ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask),
ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask),
ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask)));
/* interface is up and configured? */
if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
/* unicast to this interface address? */
if (ip_addr_cmp(&current_iphdr_dest, &(netif->ip_addr)) ||
/* or broadcast on this interface network address? */
ip_addr_isbroadcast(&current_iphdr_dest, netif)) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
netif->name[0], netif->name[1]));
/* break out of for loop */
break;
}
#if LWIP_AUTOIP
/* connections to link-local addresses must persist after changing
the netif's address (RFC3927 ch. 1.9) */
if ((netif->autoip != NULL) &&
ip_addr_cmp(&current_iphdr_dest, &(netif->autoip->llipaddr))) {
LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n",
netif->name[0], netif->name[1]));
/* break out of for loop */
break;
}
#endif /* LWIP_AUTOIP */
}
if (first) {
first = 0;
netif = netif_list;
} else {
netif = netif->next;
}
if (netif == inp) {
netif = netif->next;
}
} while(netif != NULL);
}
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
/* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
* using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
* According to RFC 1542 section 3.1.1, referred by RFC 2131).
*
* If you want to accept private broadcast communication while a netif is down,
* define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.:
*
* #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))
*/
if (netif == NULL) {
/* remote port is DHCP server? */
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen);
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
ntohs(udphdr->dest)));
if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
netif = inp;
check_ip_src = 0;
}
}
}
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
/* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
#if IP_ACCEPT_LINK_LAYER_ADDRESSING
/* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
if (check_ip_src && !ip_addr_isany(&current_iphdr_src))
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
{ if ((ip_addr_isbroadcast(&current_iphdr_src, inp)) ||
(ip_addr_ismulticast(&current_iphdr_src))) {
/* packet source is not valid */
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
/* free (drop) packet pbufs */
pbuf_free(p);
IP_STATS_INC(ip.drop);
snmp_inc_ipinaddrerrors();
snmp_inc_ipindiscards();
return ERR_OK;
}
}
/* packet not for us? */
if (netif == NULL) {
/* packet not for us, route or discard */
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
#if IP_FORWARD
/* non-broadcast packet? */
if (!ip_addr_isbroadcast(&current_iphdr_dest, inp)) {
/* try to forward IP packet on (other) interfaces */
ip_forward(p, iphdr, inp);
} else
#endif /* IP_FORWARD */
{
snmp_inc_ipinaddrerrors();
snmp_inc_ipindiscards();
}
pbuf_free(p);
return ERR_OK;
}
/* packet consists of multiple fragments? */
if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
#if IP_REASSEMBLY /* packet fragment reassembly code present? */
LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
/* reassemble the packet*/
p = ip_reass(p);
/* packet not fully reassembled yet? */
if (p == NULL) {
return ERR_OK;
}
iphdr = (struct ip_hdr *)p->payload;
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
pbuf_free(p);
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
ntohs(IPH_OFFSET(iphdr))));
IP_STATS_INC(ip.opterr);
IP_STATS_INC(ip.drop);
/* unsupported protocol feature */
snmp_inc_ipinunknownprotos();
return ERR_OK;
#endif /* IP_REASSEMBLY */
}
#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */
#if LWIP_IGMP
/* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
#else
if (iphdr_hlen > IP_HLEN) {
#endif /* LWIP_IGMP */
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
pbuf_free(p);
IP_STATS_INC(ip.opterr);
IP_STATS_INC(ip.drop);
/* unsupported protocol feature */
snmp_inc_ipinunknownprotos();
return ERR_OK;
}
#endif /* IP_OPTIONS_ALLOWED == 0 */
/* send to upper layers */
LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
ip_debug_print(p);
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
current_netif = inp;
current_header = iphdr;
#if LWIP_RAW
/* raw input did not eat the packet? */
if (raw_input(p, inp) == 0)
#endif /* LWIP_RAW */
{
switch (IPH_PROTO(iphdr)) {
#if LWIP_UDP
case IP_PROTO_UDP:
#if LWIP_UDPLITE
case IP_PROTO_UDPLITE:
#endif /* LWIP_UDPLITE */
snmp_inc_ipindelivers();
udp_input(p, inp);
break;
#endif /* LWIP_UDP */
#if LWIP_TCP
case IP_PROTO_TCP:
snmp_inc_ipindelivers();
tcp_input(p, inp);
break;
#endif /* LWIP_TCP */
#if LWIP_ICMP
case IP_PROTO_ICMP:
snmp_inc_ipindelivers();
icmp_input(p, inp);
break;
#endif /* LWIP_ICMP */
#if LWIP_IGMP
case IP_PROTO_IGMP:
igmp_input(p, inp, &current_iphdr_dest);
break;
#endif /* LWIP_IGMP */
default:
#if LWIP_ICMP
/* send ICMP destination protocol unreachable unless is was a broadcast */
if (!ip_addr_isbroadcast(&current_iphdr_dest, inp) &&
!ip_addr_ismulticast(&current_iphdr_dest)) {
p->payload = iphdr;
icmp_dest_unreach(p, ICMP_DUR_PROTO);
}
#endif /* LWIP_ICMP */
pbuf_free(p);
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
IP_STATS_INC(ip.proterr);
IP_STATS_INC(ip.drop);
snmp_inc_ipinunknownprotos();
}
}
current_netif = NULL;
current_header = NULL;
ip_addr_set_any(&current_iphdr_src);
ip_addr_set_any(&current_iphdr_dest);
return ERR_OK;
}
/**
* Sends an IP packet on a network interface. This function constructs
* the IP header and calculates the IP header checksum. If the source
* IP address is NULL, the IP address of the outgoing network
* interface is filled in as source address.
* If the destination IP address is IP_HDRINCL, p is assumed to already
* include an IP header and p->payload points to it instead of the data.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an IP
header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
* IP address of the netif used to send is used as source address)
* @param dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header
* @param tos the TOS value to be set in the IP header
* @param proto the PROTOCOL to be set in the IP header
* @param netif the netif on which to send this packet
* @return ERR_OK if the packet was sent OK
* ERR_BUF if p doesn't have enough space for IP/LINK headers
* returns errors returned by netif->output
*
* @note ip_id: RFC791 "some host may be able to simply use
* unique identifiers independent of destination"
*/
err_t
ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos,
u8_t proto, struct netif *netif)
{
#if IP_OPTIONS_SEND
return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
}
/**
* Same as ip_output_if() but with the possibility to include IP options:
*
* @ param ip_options pointer to the IP options, copied into the IP header
* @ param optlen length of ip_options
*/
err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
u16_t optlen)
{
#endif /* IP_OPTIONS_SEND */
struct ip_hdr *iphdr;
ip_addr_t dest_addr;
#if CHECKSUM_GEN_IP_INLINE
u32_t chk_sum = 0;
#endif /* CHECKSUM_GEN_IP_INLINE */
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
gets altered as the packet is passed down the stack */
LWIP_ASSERT("p->ref == 1", p->ref == 1);
snmp_inc_ipoutrequests();
/* Should the IP header be generated or is it already included in p? */
if (dest != IP_HDRINCL) {
u16_t ip_hlen = IP_HLEN;
#if IP_OPTIONS_SEND
u16_t optlen_aligned = 0;
if (optlen != 0) {
#if CHECKSUM_GEN_IP_INLINE
int i;
#endif /* CHECKSUM_GEN_IP_INLINE */
/* round up to a multiple of 4 */
optlen_aligned = ((optlen + 3) & ~3);
ip_hlen += optlen_aligned;
/* First write in the IP options */
if (pbuf_header(p, optlen_aligned)) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
IP_STATS_INC(ip.err);
snmp_inc_ipoutdiscards();
return ERR_BUF;
}
MEMCPY(p->payload, ip_options, optlen);
if (optlen < optlen_aligned) {
/* zero the remaining bytes */
memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
}
#if CHECKSUM_GEN_IP_INLINE
for (i = 0; i < optlen_aligned/2; i++) {
chk_sum += ((u16_t*)p->payload)[i];
}
#endif /* CHECKSUM_GEN_IP_INLINE */
}
#endif /* IP_OPTIONS_SEND */
/* generate IP header */
if (pbuf_header(p, IP_HLEN)) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
IP_STATS_INC(ip.err);
snmp_inc_ipoutdiscards();
return ERR_BUF;
}
iphdr = (struct ip_hdr *)p->payload;
LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
(p->len >= sizeof(struct ip_hdr)));
IPH_TTL_SET(iphdr, ttl);
IPH_PROTO_SET(iphdr, proto);
#if CHECKSUM_GEN_IP_INLINE
chk_sum += LWIP_MAKE_U16(proto, ttl);
#endif /* CHECKSUM_GEN_IP_INLINE */
/* dest cannot be NULL here */
ip_addr_copy(iphdr->dest, *dest);
#if CHECKSUM_GEN_IP_INLINE
chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF;
chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
#endif /* CHECKSUM_GEN_IP_INLINE */
IPH_VHL_SET(iphdr, 4, ip_hlen / 4);
IPH_TOS_SET(iphdr, tos);
#if CHECKSUM_GEN_IP_INLINE
chk_sum += LWIP_MAKE_U16(tos, iphdr->_v_hl);
#endif /* CHECKSUM_GEN_IP_INLINE */
IPH_LEN_SET(iphdr, htons(p->tot_len));
#if CHECKSUM_GEN_IP_INLINE
chk_sum += iphdr->_len;
#endif /* CHECKSUM_GEN_IP_INLINE */
IPH_OFFSET_SET(iphdr, 0);
IPH_ID_SET(iphdr, htons(ip_id));
#if CHECKSUM_GEN_IP_INLINE
chk_sum += iphdr->_id;
#endif /* CHECKSUM_GEN_IP_INLINE */
++ip_id;
if (ip_addr_isany(src)) {
ip_addr_copy(iphdr->src, netif->ip_addr);
} else {
/* src cannot be NULL here */
ip_addr_copy(iphdr->src, *src);
}
#if CHECKSUM_GEN_IP_INLINE
chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF;
chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16;
chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF);
chk_sum = (chk_sum >> 16) + chk_sum;
chk_sum = ~chk_sum;
iphdr->_chksum = chk_sum; /* network order */
#else /* CHECKSUM_GEN_IP_INLINE */
IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
#endif
#endif /* CHECKSUM_GEN_IP_INLINE */
} else {
/* IP header already included in p */
iphdr = (struct ip_hdr *)p->payload;
ip_addr_copy(dest_addr, iphdr->dest);
dest = &dest_addr;
}
IP_STATS_INC(ip.xmit);
LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
ip_debug_print(p);
#if ENABLE_LOOPBACK
if (ip_addr_cmp(dest, &netif->ip_addr)) {
/* Packet to self, enqueue it for loopback */
LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
return netif_loop_output(netif, p, dest);
}
#if LWIP_IGMP
if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {
netif_loop_output(netif, p, dest);
}
#endif /* LWIP_IGMP */
#endif /* ENABLE_LOOPBACK */
#if IP_FRAG
/* don't fragment if interface has mtu set to 0 [loopif] */
if (netif->mtu && (p->tot_len > netif->mtu)) {
return ip_frag(p, netif, dest);
}
#endif /* IP_FRAG */
LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
return netif->output(netif, p, dest);
}
/**
* Simple interface to ip_output_if. It finds the outgoing network
* interface and calls upon ip_output_if to do the actual work.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an IP
header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
* IP address of the netif used to send is used as source address)
* @param dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header
* @param tos the TOS value to be set in the IP header
* @param proto the PROTOCOL to be set in the IP header
*
* @return ERR_RTE if no route is found
* see ip_output_if() for more return values
*/
err_t
ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto)
{
struct netif *netif;
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
gets altered as the packet is passed down the stack */
LWIP_ASSERT("p->ref == 1", p->ref == 1);
if ((netif = ip_route(dest)) == NULL) {
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
IP_STATS_INC(ip.rterr);
return ERR_RTE;
}
return ip_output_if(p, src, dest, ttl, tos, proto, netif);
}
#if LWIP_NETIF_HWADDRHINT
/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
* before calling ip_output_if.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an IP
header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
* IP address of the netif used to send is used as source address)
* @param dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header
* @param tos the TOS value to be set in the IP header
* @param proto the PROTOCOL to be set in the IP header
* @param addr_hint address hint pointer set to netif->addr_hint before
* calling ip_output_if()
*
* @return ERR_RTE if no route is found
* see ip_output_if() for more return values
*/
err_t
ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
{
struct netif *netif;
err_t err;
/* pbufs passed to IP must have a ref-count of 1 as their payload pointer
gets altered as the packet is passed down the stack */
LWIP_ASSERT("p->ref == 1", p->ref == 1);
if ((netif = ip_route(dest)) == NULL) {
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
IP_STATS_INC(ip.rterr);
return ERR_RTE;
}
NETIF_SET_HWADDRHINT(netif, addr_hint);
err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
NETIF_SET_HWADDRHINT(netif, NULL);
return err;
}
#endif /* LWIP_NETIF_HWADDRHINT*/
#if IP_DEBUG
/* Print an IP header by using LWIP_DEBUGF
* @param p an IP packet, p->payload pointing to the IP header
*/
void
ip_debug_print(struct pbuf *p)
{
struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n",
IPH_V(iphdr),
IPH_HL(iphdr),
IPH_TOS(iphdr),
ntohs(IPH_LEN(iphdr))));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n",
ntohs(IPH_ID(iphdr)),
ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n",
IPH_TTL(iphdr),
IPH_PROTO(iphdr),
ntohs(IPH_CHKSUM(iphdr))));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n",
ip4_addr1_16(&iphdr->src),
ip4_addr2_16(&iphdr->src),
ip4_addr3_16(&iphdr->src),
ip4_addr4_16(&iphdr->src)));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n",
ip4_addr1_16(&iphdr->dest),
ip4_addr2_16(&iphdr->dest),
ip4_addr3_16(&iphdr->dest),
ip4_addr4_16(&iphdr->dest)));
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
}
#endif /* IP_DEBUG */

View File

@ -1,312 +0,0 @@
/**
* @file
* This is the IPv4 address tools implementation.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
const ip_addr_t ip_addr_any = { IPADDR_ANY };
const ip_addr_t ip_addr_broadcast = { IPADDR_BROADCAST };
/**
* Determine if an address is a broadcast address on a network interface
*
* @param addr address to be checked
* @param netif the network interface against which the address is checked
* @return returns non-zero if the address is a broadcast address
*/
u8_t
ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
{
ip_addr_t ipaddr;
ip4_addr_set_u32(&ipaddr, addr);
/* all ones (broadcast) or all zeroes (old skool broadcast) */
if ((~addr == IPADDR_ANY) ||
(addr == IPADDR_ANY)) {
return 1;
/* no broadcast support on this network interface? */
} else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) {
/* the given address cannot be a broadcast address
* nor can we check against any broadcast addresses */
return 0;
/* address matches network interface address exactly? => no broadcast */
} else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {
return 0;
/* on the same (sub) network... */
} else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
/* ...and host identifier bits are all ones? =>... */
&& ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
(IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
/* => network broadcast address */
return 1;
} else {
return 0;
}
}
/** Checks if a netmask is valid (starting with ones, then only zeros)
*
* @param netmask the IPv4 netmask to check (in network byte order!)
* @return 1 if the netmask is valid, 0 if it is not
*/
u8_t
ip4_addr_netmask_valid(u32_t netmask)
{
u32_t mask;
u32_t nm_hostorder = lwip_htonl(netmask);
/* first, check for the first zero */
for (mask = 1UL << 31 ; mask != 0; mask >>= 1) {
if ((nm_hostorder & mask) == 0) {
break;
}
}
/* then check that there is no one */
for (; mask != 0; mask >>= 1) {
if ((nm_hostorder & mask) != 0) {
/* there is a one after the first zero -> invalid */
return 0;
}
}
/* no one after the first zero -> valid */
return 1;
}
/* Here for now until needed in other places in lwIP */
#ifndef isprint
#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
#define isprint(c) in_range(c, 0x20, 0x7f)
#define isdigit(c) in_range(c, '0', '9')
#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
#define islower(c) in_range(c, 'a', 'z')
#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
#endif
/**
* Ascii internet address interpretation routine.
* The value returned is in network order.
*
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
* @return ip address in network order
*/
u32_t
ipaddr_addr(const char *cp)
{
ip_addr_t val;
if (ipaddr_aton(cp, &val)) {
return ip4_addr_get_u32(&val);
}
return (IPADDR_NONE);
}
/**
* Check whether "cp" is a valid ascii representation
* of an Internet address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
* This replaces inet_addr, the return value from which
* cannot distinguish between failure and a local broadcast address.
*
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
* @param addr pointer to which to save the ip address in network order
* @return 1 if cp could be converted to addr, 0 on failure
*/
int
ipaddr_aton(const char *cp, ip_addr_t *addr)
{
u32_t val;
u8_t base;
char c;
u32_t parts[4];
u32_t *pp = parts;
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, 1-9=decimal.
*/
if (!isdigit(c))
return (0);
val = 0;
base = 10;
if (c == '0') {
c = *++cp;
if (c == 'x' || c == 'X') {
base = 16;
c = *++cp;
} else
base = 8;
}
for (;;) {
if (isdigit(c)) {
val = (val * base) + (int)(c - '0');
c = *++cp;
} else if (base == 16 && isxdigit(c)) {
val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
c = *++cp;
} else
break;
}
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3) {
return (0);
}
*pp++ = val;
c = *++cp;
} else
break;
}
/*
* Check for trailing characters.
*/
if (c != '\0' && !isspace(c)) {
return (0);
}
/*
* Concoct the address according to
* the number of parts specified.
*/
switch (pp - parts + 1) {
case 0:
return (0); /* initial nondigit */
case 1: /* a -- 32 bits */
break;
case 2: /* a.b -- 8.24 bits */
if (val > 0xffffffUL) {
return (0);
}
val |= parts[0] << 24;
break;
case 3: /* a.b.c -- 8.8.16 bits */
if (val > 0xffff) {
return (0);
}
val |= (parts[0] << 24) | (parts[1] << 16);
break;
case 4: /* a.b.c.d -- 8.8.8.8 bits */
if (val > 0xff) {
return (0);
}
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
break;
default:
LWIP_ASSERT("unhandled", 0);
break;
}
if (addr) {
ip4_addr_set_u32(addr, htonl(val));
}
return (1);
}
/**
* Convert numeric IP address into decimal dotted ASCII representation.
* returns ptr to static buffer; not reentrant!
*
* @param addr ip address in network order to convert
* @return pointer to a global static (!) buffer that holds the ASCII
* represenation of addr
*/
char *
ipaddr_ntoa(const ip_addr_t *addr)
{
static char str[16];
return ipaddr_ntoa_r(addr, str, 16);
}
/**
* Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
*
* @param addr ip address in network order to convert
* @param buf target buffer where the string is stored
* @param buflen length of buf
* @return either pointer to buf which now holds the ASCII
* representation of addr or NULL if buf was too small
*/
char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)
{
u32_t s_addr;
char inv[3];
char *rp;
u8_t *ap;
u8_t rem;
u8_t n;
u8_t i;
int len = 0;
s_addr = ip4_addr_get_u32(addr);
rp = buf;
ap = (u8_t *)&s_addr;
for(n = 0; n < 4; n++) {
i = 0;
do {
rem = *ap % (u8_t)10;
*ap /= (u8_t)10;
inv[i++] = '0' + rem;
} while(*ap);
while(i--) {
if (len++ >= buflen) {
return NULL;
}
*rp++ = inv[i];
}
if (len++ >= buflen) {
return NULL;
}
*rp++ = '.';
ap++;
}
*--rp = 0;
return buf;
}

View File

@ -1,863 +0,0 @@
/**
* @file
* This is the IPv4 packet segmentation and reassembly implementation.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Jani Monoses <jani@iv.ro>
* Simon Goldschmidt
* original reassembly code by Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/ip_frag.h"
#include "lwip/def.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/snmp.h"
#include "lwip/stats.h"
#include "lwip/icmp.h"
#include <string.h>
#if IP_REASSEMBLY
/**
* The IP reassembly code currently has the following limitations:
* - IP header options are not supported
* - fragments must not overlap (e.g. due to different routes),
* currently, overlapping or duplicate fragments are thrown away
* if IP_REASS_CHECK_OVERLAP=1 (the default)!
*
* @todo: work with IP header options
*/
/** Setting this to 0, you can turn off checking the fragments for overlapping
* regions. The code gets a little smaller. Only use this if you know that
* overlapping won't occur on your network! */
#ifndef IP_REASS_CHECK_OVERLAP
#define IP_REASS_CHECK_OVERLAP 1
#endif /* IP_REASS_CHECK_OVERLAP */
/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
* full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
* Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
* is set to 1, so one datagram can be reassembled at a time, only. */
#ifndef IP_REASS_FREE_OLDEST
#define IP_REASS_FREE_OLDEST 1
#endif /* IP_REASS_FREE_OLDEST */
#define IP_REASS_FLAG_LASTFRAG 0x01
/** This is a helper struct which holds the starting
* offset and the ending offset of this fragment to
* easily chain the fragments.
* It has the same packing requirements as the IP header, since it replaces
* the IP header in memory in incoming fragments (after copying it) to keep
* track of the various fragments. (-> If the IP header doesn't need packing,
* this struct doesn't need packing, too.)
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_reass_helper {
PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
PACK_STRUCT_FIELD(u16_t start);
PACK_STRUCT_FIELD(u16_t end);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
(ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
/* global variables */
static struct ip_reassdata *reassdatagrams;
static u16_t ip_reass_pbufcount;
/* function prototypes */
static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
/**
* Reassembly timer base function
* for both NO_SYS == 0 and 1 (!).
*
* Should be called every 1000 msec (defined by IP_TMR_INTERVAL).
*/
void
ip_reass_tmr(void)
{
struct ip_reassdata *r, *prev = NULL;
r = reassdatagrams;
while (r != NULL) {
/* Decrement the timer. Once it reaches 0,
* clean up the incomplete fragment assembly */
if (r->timer > 0) {
r->timer--;
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer));
prev = r;
r = r->next;
} else {
/* reassembly timed out */
struct ip_reassdata *tmp;
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n"));
tmp = r;
/* get the next pointer before freeing */
r = r->next;
/* free the helper struct and all enqueued pbufs */
ip_reass_free_complete_datagram(tmp, prev);
}
}
}
/**
* Free a datagram (struct ip_reassdata) and all its pbufs.
* Updates the total count of enqueued pbufs (ip_reass_pbufcount),
* SNMP counters and sends an ICMP time exceeded packet.
*
* @param ipr datagram to free
* @param prev the previous datagram in the linked list
* @return the number of pbufs freed
*/
static int
ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
{
u16_t pbufs_freed = 0;
u8_t clen;
struct pbuf *p;
struct ip_reass_helper *iprh;
LWIP_ASSERT("prev != ipr", prev != ipr);
if (prev != NULL) {
LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
}
snmp_inc_ipreasmfails();
#if LWIP_ICMP
iprh = (struct ip_reass_helper *)ipr->p->payload;
if (iprh->start == 0) {
/* The first fragment was received, send ICMP time exceeded. */
/* First, de-queue the first pbuf from r->p. */
p = ipr->p;
ipr->p = iprh->next_pbuf;
/* Then, copy the original header into it. */
SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
icmp_time_exceeded(p, ICMP_TE_FRAG);
clen = pbuf_clen(p);
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
pbufs_freed += clen;
pbuf_free(p);
}
#endif /* LWIP_ICMP */
/* First, free all received pbufs. The individual pbufs need to be released
separately as they have not yet been chained */
p = ipr->p;
while (p != NULL) {
struct pbuf *pcur;
iprh = (struct ip_reass_helper *)p->payload;
pcur = p;
/* get the next pointer before freeing */
p = iprh->next_pbuf;
clen = pbuf_clen(pcur);
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
pbufs_freed += clen;
pbuf_free(pcur);
}
/* Then, unchain the struct ip_reassdata from the list and free it. */
ip_reass_dequeue_datagram(ipr, prev);
LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);
ip_reass_pbufcount -= pbufs_freed;
return pbufs_freed;
}
#if IP_REASS_FREE_OLDEST
/**
* Free the oldest datagram to make room for enqueueing new fragments.
* The datagram 'fraghdr' belongs to is not freed!
*
* @param fraghdr IP header of the current fragment
* @param pbufs_needed number of pbufs needed to enqueue
* (used for freeing other datagrams if not enough space)
* @return the number of pbufs freed
*/
static int
ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
{
/* @todo Can't we simply remove the last datagram in the
* linked list behind reassdatagrams?
*/
struct ip_reassdata *r, *oldest, *prev;
int pbufs_freed = 0, pbufs_freed_current;
int other_datagrams;
/* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
* but don't free the datagram that 'fraghdr' belongs to! */
do {
oldest = NULL;
prev = NULL;
other_datagrams = 0;
r = reassdatagrams;
while (r != NULL) {
if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {
/* Not the same datagram as fraghdr */
other_datagrams++;
if (oldest == NULL) {
oldest = r;
} else if (r->timer <= oldest->timer) {
/* older than the previous oldest */
oldest = r;
}
}
if (r->next != NULL) {
prev = r;
}
r = r->next;
}
if (oldest != NULL) {
pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);
pbufs_freed += pbufs_freed_current;
}
} while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
return pbufs_freed;
}
#endif /* IP_REASS_FREE_OLDEST */
/**
* Enqueues a new fragment into the fragment queue
* @param fraghdr points to the new fragments IP hdr
* @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space)
* @return A pointer to the queue location into which the fragment was enqueued
*/
static struct ip_reassdata*
ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
{
struct ip_reassdata* ipr;
/* No matching previous fragment found, allocate a new reassdata struct */
ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
if (ipr == NULL) {
#if IP_REASS_FREE_OLDEST
if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);
}
if (ipr == NULL)
#endif /* IP_REASS_FREE_OLDEST */
{
IPFRAG_STATS_INC(ip_frag.memerr);
LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n"));
return NULL;
}
}
memset(ipr, 0, sizeof(struct ip_reassdata));
ipr->timer = IP_REASS_MAXAGE;
/* enqueue the new structure to the front of the list */
ipr->next = reassdatagrams;
reassdatagrams = ipr;
/* copy the ip header for later tests and input */
/* @todo: no ip options supported? */
SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);
return ipr;
}
/**
* Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs.
* @param ipr points to the queue entry to dequeue
*/
static void
ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
{
/* dequeue the reass struct */
if (reassdatagrams == ipr) {
/* it was the first in the list */
reassdatagrams = ipr->next;
} else {
/* it wasn't the first, so it must have a valid 'prev' */
LWIP_ASSERT("sanity check linked list", prev != NULL);
prev->next = ipr->next;
}
/* now we can free the ip_reass struct */
memp_free(MEMP_REASSDATA, ipr);
}
/**
* Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list
* will grow over time as new pbufs are rx.
* Also checks that the datagram passes basic continuity checks (if the last
* fragment was received at least once).
* @param root_p points to the 'root' pbuf for the current datagram being assembled.
* @param new_p points to the pbuf for the current fragment
* @return 0 if invalid, >0 otherwise
*/
static int
ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)
{
struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
struct pbuf *q;
u16_t offset,len;
struct ip_hdr *fraghdr;
int valid = 1;
/* Extract length and fragment offset from current fragment */
fraghdr = (struct ip_hdr*)new_p->payload;
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
/* overwrite the fragment's ip header from the pbuf with our helper struct,
* and setup the embedded helper structure. */
/* make sure the struct ip_reass_helper fits into the IP header */
LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",
sizeof(struct ip_reass_helper) <= IP_HLEN);
iprh = (struct ip_reass_helper*)new_p->payload;
iprh->next_pbuf = NULL;
iprh->start = offset;
iprh->end = offset + len;
/* Iterate through until we either get to the end of the list (append),
* or we find on with a larger offset (insert). */
for (q = ipr->p; q != NULL;) {
iprh_tmp = (struct ip_reass_helper*)q->payload;
if (iprh->start < iprh_tmp->start) {
/* the new pbuf should be inserted before this */
iprh->next_pbuf = q;
if (iprh_prev != NULL) {
/* not the fragment with the lowest offset */
#if IP_REASS_CHECK_OVERLAP
if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
/* fragment overlaps with previous or following, throw away */
goto freepbuf;
}
#endif /* IP_REASS_CHECK_OVERLAP */
iprh_prev->next_pbuf = new_p;
} else {
/* fragment with the lowest offset */
ipr->p = new_p;
}
break;
} else if(iprh->start == iprh_tmp->start) {
/* received the same datagram twice: no need to keep the datagram */
goto freepbuf;
#if IP_REASS_CHECK_OVERLAP
} else if(iprh->start < iprh_tmp->end) {
/* overlap: no need to keep the new datagram */
goto freepbuf;
#endif /* IP_REASS_CHECK_OVERLAP */
} else {
/* Check if the fragments received so far have no wholes. */
if (iprh_prev != NULL) {
if (iprh_prev->end != iprh_tmp->start) {
/* There is a fragment missing between the current
* and the previous fragment */
valid = 0;
}
}
}
q = iprh_tmp->next_pbuf;
iprh_prev = iprh_tmp;
}
/* If q is NULL, then we made it to the end of the list. Determine what to do now */
if (q == NULL) {
if (iprh_prev != NULL) {
/* this is (for now), the fragment with the highest offset:
* chain it to the last fragment */
#if IP_REASS_CHECK_OVERLAP
LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
#endif /* IP_REASS_CHECK_OVERLAP */
iprh_prev->next_pbuf = new_p;
if (iprh_prev->end != iprh->start) {
valid = 0;
}
} else {
#if IP_REASS_CHECK_OVERLAP
LWIP_ASSERT("no previous fragment, this must be the first fragment!",
ipr->p == NULL);
#endif /* IP_REASS_CHECK_OVERLAP */
/* this is the first fragment we ever received for this ip datagram */
ipr->p = new_p;
}
}
/* At this point, the validation part begins: */
/* If we already received the last fragment */
if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
/* and had no wholes so far */
if (valid) {
/* then check if the rest of the fragments is here */
/* Check if the queue starts with the first datagram */
if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {
valid = 0;
} else {
/* and check that there are no wholes after this datagram */
iprh_prev = iprh;
q = iprh->next_pbuf;
while (q != NULL) {
iprh = (struct ip_reass_helper*)q->payload;
if (iprh_prev->end != iprh->start) {
valid = 0;
break;
}
iprh_prev = iprh;
q = iprh->next_pbuf;
}
/* if still valid, all fragments are received
* (because to the MF==0 already arrived */
if (valid) {
LWIP_ASSERT("sanity check", ipr->p != NULL);
LWIP_ASSERT("sanity check",
((struct ip_reass_helper*)ipr->p->payload) != iprh);
LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",
iprh->next_pbuf == NULL);
LWIP_ASSERT("validate_datagram:datagram end!=datagram len",
iprh->end == ipr->datagram_len);
}
}
}
/* If valid is 0 here, there are some fragments missing in the middle
* (since MF == 0 has already arrived). Such datagrams simply time out if
* no more fragments are received... */
return valid;
}
/* If we come here, not all fragments were received, yet! */
return 0; /* not yet valid! */
#if IP_REASS_CHECK_OVERLAP
freepbuf:
ip_reass_pbufcount -= pbuf_clen(new_p);
pbuf_free(new_p);
return 0;
#endif /* IP_REASS_CHECK_OVERLAP */
}
/**
* Reassembles incoming IP fragments into an IP datagram.
*
* @param p points to a pbuf chain of the fragment
* @return NULL if reassembly is incomplete, ? otherwise
*/
struct pbuf *
ip_reass(struct pbuf *p)
{
struct pbuf *r;
struct ip_hdr *fraghdr;
struct ip_reassdata *ipr;
struct ip_reass_helper *iprh;
u16_t offset, len;
u8_t clen;
struct ip_reassdata *ipr_prev = NULL;
IPFRAG_STATS_INC(ip_frag.recv);
snmp_inc_ipreasmreqds();
fraghdr = (struct ip_hdr*)p->payload;
if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));
IPFRAG_STATS_INC(ip_frag.err);
goto nullreturn;
}
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
/* Check if we are allowed to enqueue more datagrams. */
clen = pbuf_clen(p);
if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
#if IP_REASS_FREE_OLDEST
if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
#endif /* IP_REASS_FREE_OLDEST */
{
/* No datagram could be freed and still too many pbufs enqueued */
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
IPFRAG_STATS_INC(ip_frag.memerr);
/* @todo: send ICMP time exceeded here? */
/* drop this pbuf */
goto nullreturn;
}
}
/* Look for the datagram the fragment belongs to in the current datagram queue,
* remembering the previous in the queue for later dequeueing. */
for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
/* Check if the incoming fragment matches the one currently present
in the reassembly buffer. If so, we proceed with copying the
fragment into the buffer. */
if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
ntohs(IPH_ID(fraghdr))));
IPFRAG_STATS_INC(ip_frag.cachehit);
break;
}
ipr_prev = ipr;
}
if (ipr == NULL) {
/* Enqueue a new datagram into the datagram queue */
ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
/* Bail if unable to enqueue */
if(ipr == NULL) {
goto nullreturn;
}
} else {
if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
/* ipr->iphdr is not the header from the first fragment, but fraghdr is
* -> copy fraghdr into ipr->iphdr since we want to have the header
* of the first fragment (for ICMP time exceeded and later, for copying
* all options, if supported)*/
SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
}
}
/* Track the current number of pbufs current 'in-flight', in order to limit
the number of fragments that may be enqueued at any one time */
ip_reass_pbufcount += clen;
/* At this point, we have either created a new entry or pointing
* to an existing one */
/* check for 'no more fragments', and update queue entry*/
if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
ipr->flags |= IP_REASS_FLAG_LASTFRAG;
ipr->datagram_len = offset + len;
LWIP_DEBUGF(IP_REASS_DEBUG,
("ip_reass: last fragment seen, total len %"S16_F"\n",
ipr->datagram_len));
}
/* find the right place to insert this pbuf */
/* @todo: trim pbufs if fragments are overlapping */
if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
/* the totally last fragment (flag more fragments = 0) was received at least
* once AND all fragments are received */
ipr->datagram_len += IP_HLEN;
/* save the second pbuf before copying the header over the pointer */
r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
/* copy the original ip header back to the first pbuf */
fraghdr = (struct ip_hdr*)(ipr->p->payload);
SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
IPH_OFFSET_SET(fraghdr, 0);
IPH_CHKSUM_SET(fraghdr, 0);
/* @todo: do we need to set calculate the correct checksum? */
IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
p = ipr->p;
/* chain together the pbufs contained within the reass_data list. */
while(r != NULL) {
iprh = (struct ip_reass_helper*)r->payload;
/* hide the ip header for every succeding fragment */
pbuf_header(r, -IP_HLEN);
pbuf_cat(p, r);
r = iprh->next_pbuf;
}
/* release the sources allocate for the fragment queue entry */
ip_reass_dequeue_datagram(ipr, ipr_prev);
/* and adjust the number of pbufs currently queued for reassembly. */
ip_reass_pbufcount -= pbuf_clen(p);
/* Return the pbuf chain */
return p;
}
/* the datagram is not (yet?) reassembled completely */
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));
return NULL;
nullreturn:
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));
IPFRAG_STATS_INC(ip_frag.drop);
pbuf_free(p);
return NULL;
}
#endif /* IP_REASSEMBLY */
#if IP_FRAG
#if IP_FRAG_USES_STATIC_BUF
static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
#else /* IP_FRAG_USES_STATIC_BUF */
#if !LWIP_NETIF_TX_SINGLE_PBUF
/** Allocate a new struct pbuf_custom_ref */
static struct pbuf_custom_ref*
ip_frag_alloc_pbuf_custom_ref(void)
{
return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
}
/** Free a struct pbuf_custom_ref */
static void
ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
{
LWIP_ASSERT("p != NULL", p != NULL);
memp_free(MEMP_FRAG_PBUF, p);
}
/** Free-callback function to free a 'struct pbuf_custom_ref', called by
* pbuf_free. */
static void
ipfrag_free_pbuf_custom(struct pbuf *p)
{
struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;
LWIP_ASSERT("pcr != NULL", pcr != NULL);
LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p);
if (pcr->original != NULL) {
pbuf_free(pcr->original);
}
ip_frag_free_pbuf_custom_ref(pcr);
}
#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */
#endif /* IP_FRAG_USES_STATIC_BUF */
/**
* Fragment an IP datagram if too large for the netif.
*
* Chop the datagram in MTU sized chunks and send them in order
* by using a fixed size static memory buffer (PBUF_REF) or
* point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
*
* @param p ip packet to send
* @param netif the netif on which to send
* @param dest destination ip address to which to send
*
* @return ERR_OK if sent successfully, err_t otherwise
*/
err_t
ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
{
struct pbuf *rambuf;
#if IP_FRAG_USES_STATIC_BUF
struct pbuf *header;
#else
#if !LWIP_NETIF_TX_SINGLE_PBUF
struct pbuf *newpbuf;
#endif
struct ip_hdr *original_iphdr;
#endif
struct ip_hdr *iphdr;
u16_t nfb;
u16_t left, cop;
u16_t mtu = netif->mtu;
u16_t ofo, omf;
u16_t last;
u16_t poff = IP_HLEN;
u16_t tmp;
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
u16_t newpbuflen = 0;
u16_t left_to_copy;
#endif
/* Get a RAM based MTU sized pbuf */
#if IP_FRAG_USES_STATIC_BUF
/* When using a static buffer, we use a PBUF_REF, which we will
* use to reference the packet (without link header).
* Layer and length is irrelevant.
*/
rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
if (rambuf == NULL) {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
return ERR_MEM;
}
rambuf->tot_len = rambuf->len = mtu;
rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
/* Copy the IP header in it */
iphdr = (struct ip_hdr *)rambuf->payload;
SMEMCPY(iphdr, p->payload, IP_HLEN);
#else /* IP_FRAG_USES_STATIC_BUF */
original_iphdr = (struct ip_hdr *)p->payload;
iphdr = original_iphdr;
#endif /* IP_FRAG_USES_STATIC_BUF */
/* Save original offset */
tmp = ntohs(IPH_OFFSET(iphdr));
ofo = tmp & IP_OFFMASK;
omf = tmp & IP_MF;
left = p->tot_len - IP_HLEN;
nfb = (mtu - IP_HLEN) / 8;
while (left) {
last = (left <= mtu - IP_HLEN);
/* Set new offset and MF flag */
tmp = omf | (IP_OFFMASK & (ofo));
if (!last) {
tmp = tmp | IP_MF;
}
/* Fill this fragment */
cop = last ? left : nfb * 8;
#if IP_FRAG_USES_STATIC_BUF
poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
#else /* IP_FRAG_USES_STATIC_BUF */
#if LWIP_NETIF_TX_SINGLE_PBUF
rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
if (rambuf == NULL) {
return ERR_MEM;
}
LWIP_ASSERT("this needs a pbuf in one piece!",
(rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
/* make room for the IP header */
if(pbuf_header(rambuf, IP_HLEN)) {
pbuf_free(rambuf);
return ERR_MEM;
}
/* fill in the IP header */
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
iphdr = rambuf->payload;
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
/* When not using a static buffer, create a chain of pbufs.
* The first will be a PBUF_RAM holding the link and IP header.
* The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
* but limited to the size of an mtu.
*/
rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
if (rambuf == NULL) {
return ERR_MEM;
}
LWIP_ASSERT("this needs a pbuf in one piece!",
(p->len >= (IP_HLEN)));
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
iphdr = (struct ip_hdr *)rambuf->payload;
/* Can just adjust p directly for needed offset. */
p->payload = (u8_t *)p->payload + poff;
p->len -= poff;
left_to_copy = cop;
while (left_to_copy) {
struct pbuf_custom_ref *pcr;
newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
/* Is this pbuf already empty? */
if (!newpbuflen) {
p = p->next;
continue;
}
pcr = ip_frag_alloc_pbuf_custom_ref();
if (pcr == NULL) {
pbuf_free(rambuf);
return ERR_MEM;
}
/* Mirror this pbuf, although we might not need all of it. */
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
if (newpbuf == NULL) {
ip_frag_free_pbuf_custom_ref(pcr);
pbuf_free(rambuf);
return ERR_MEM;
}
pbuf_ref(p);
pcr->original = p;
pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;
/* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
* so that it is removed when pbuf_dechain is later called on rambuf.
*/
pbuf_cat(rambuf, newpbuf);
left_to_copy -= newpbuflen;
if (left_to_copy) {
p = p->next;
}
}
poff = newpbuflen;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
#endif /* IP_FRAG_USES_STATIC_BUF */
/* Correct header */
IPH_OFFSET_SET(iphdr, htons(tmp));
IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
IPH_CHKSUM_SET(iphdr, 0);
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
#if IP_FRAG_USES_STATIC_BUF
if (last) {
pbuf_realloc(rambuf, left + IP_HLEN);
}
/* This part is ugly: we alloc a RAM based pbuf for
* the link level header for each chunk and then
* free it.A PBUF_ROM style pbuf for which pbuf_header
* worked would make things simpler.
*/
header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
if (header != NULL) {
pbuf_chain(header, rambuf);
netif->output(netif, header, dest);
IPFRAG_STATS_INC(ip_frag.xmit);
snmp_inc_ipfragcreates();
pbuf_free(header);
} else {
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
pbuf_free(rambuf);
return ERR_MEM;
}
#else /* IP_FRAG_USES_STATIC_BUF */
/* No need for separate header pbuf - we allowed room for it in rambuf
* when allocated.
*/
netif->output(netif, rambuf, dest);
IPFRAG_STATS_INC(ip_frag.xmit);
/* Unfortunately we can't reuse rambuf - the hardware may still be
* using the buffer. Instead we free it (and the ensuing chain) and
* recreate it next time round the loop. If we're lucky the hardware
* will have already sent the packet, the free will really free, and
* there will be zero memory penalty.
*/
pbuf_free(rambuf);
#endif /* IP_FRAG_USES_STATIC_BUF */
left -= cop;
ofo += nfb;
}
#if IP_FRAG_USES_STATIC_BUF
pbuf_free(rambuf);
#endif /* IP_FRAG_USES_STATIC_BUF */
snmp_inc_ipfragoks();
return ERR_OK;
}
#endif /* IP_FRAG */

View File

@ -1,660 +0,0 @@
/**
* @file
* Dynamic memory manager
*
* This is a lightweight replacement for the standard C library malloc().
*
* If you want to use the standard C library malloc() instead, define
* MEM_LIBC_MALLOC to 1 in your lwipopts.h
*
* To let mem_malloc() use pools (prevents fragmentation and is much faster than
* a heap but might waste some memory), define MEM_USE_POOLS to 1, define
* MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
* of pools like this (more pools can be added between _START and _END):
*
* Define three pools with sizes 256, 512, and 1512 bytes
* LWIP_MALLOC_MEMPOOL_START
* LWIP_MALLOC_MEMPOOL(20, 256)
* LWIP_MALLOC_MEMPOOL(10, 512)
* LWIP_MALLOC_MEMPOOL(5, 1512)
* LWIP_MALLOC_MEMPOOL_END
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
* Simon Goldschmidt
*
*/
#include "lwip/opt.h"
#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
#include "lwip/err.h"
#include <string.h>
#if MEM_USE_POOLS
/* lwIP head implemented with different sized pools */
/**
* Allocate memory: determine the smallest pool that is big enough
* to contain an element of 'size' and get an element from that pool.
*
* @param size the size in bytes of the memory needed
* @return a pointer to the allocated memory or NULL if the pool is empty
*/
void *
mem_malloc(mem_size_t size)
{
void *ret;
struct memp_malloc_helper *element;
memp_t poolnr;
mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {
#if MEM_USE_POOLS_TRY_BIGGER_POOL
again:
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
/* is this pool big enough to hold an element of the required size
plus a struct memp_malloc_helper that saves the pool this element came from? */
if (required_size <= memp_sizes[poolnr]) {
break;
}
}
if (poolnr > MEMP_POOL_LAST) {
LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
return NULL;
}
element = (struct memp_malloc_helper*)memp_malloc(poolnr);
if (element == NULL) {
/* No need to DEBUGF or ASSERT: This error is already
taken care of in memp.c */
#if MEM_USE_POOLS_TRY_BIGGER_POOL
/** Try a bigger pool if this one is empty! */
if (poolnr < MEMP_POOL_LAST) {
poolnr++;
goto again;
}
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
return NULL;
}
/* save the pool number this element came from */
element->poolnr = poolnr;
/* and return a pointer to the memory directly after the struct memp_malloc_helper */
ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
return ret;
}
/**
* Free memory previously allocated by mem_malloc. Loads the pool number
* and calls memp_free with that pool number to put the element back into
* its pool
*
* @param rmem the memory element to free
*/
void
mem_free(void *rmem)
{
struct memp_malloc_helper *hmem;
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
/* get the original struct memp_malloc_helper */
hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)));
LWIP_ASSERT("hmem != NULL", (hmem != NULL));
LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));
/* and put it in the pool we saved earlier */
memp_free(hmem->poolnr, hmem);
}
#else /* MEM_USE_POOLS */
/* lwIP replacement for your libc malloc() */
/**
* The heap is made up as a list of structs of this type.
* This does not have to be aligned since for getting its size,
* we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.
*/
struct mem {
/** index (-> ram[next]) of the next struct */
mem_size_t next;
/** index (-> ram[prev]) of the previous struct */
mem_size_t prev;
/** 1: this area is used; 0: this area is unused */
u8_t used;
};
/** All allocated blocks will be MIN_SIZE bytes big, at least!
* MIN_SIZE can be overridden to suit your needs. Smaller values save space,
* larger values could prevent too small blocks to fragment the RAM too much. */
#ifndef MIN_SIZE
#define MIN_SIZE 12
#endif /* MIN_SIZE */
/* some alignment macros: we define them here for better source code layout */
#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE)
#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
/** If you want to relocate the heap to external memory, simply define
* LWIP_RAM_HEAP_POINTER as a void-pointer to that location.
* If so, make sure the memory at that location is big enough (see below on
* how that space is calculated). */
#ifndef LWIP_RAM_HEAP_POINTER
/** the heap. we need one struct mem at the end and some room for alignment */
__attribute__ ((section(".data.$RAM4")))
u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
#define LWIP_RAM_HEAP_POINTER ram_heap
#endif /* LWIP_RAM_HEAP_POINTER */
/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */
static u8_t *ram;
/** the last entry, always unused! */
static struct mem *ram_end;
/** pointer to the lowest free block, this is used for faster search */
static struct mem *lfree;
/** concurrent access protection */
#if !NO_SYS
static sys_mutex_t mem_mutex;
#endif
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
static volatile u8_t mem_free_count;
/* Allow mem_free from other (e.g. interrupt) context */
#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free)
#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free)
#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free)
#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc)
#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc)
#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
/* Protect the heap only by using a semaphore */
#define LWIP_MEM_FREE_DECL_PROTECT()
#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex)
#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex)
/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */
#define LWIP_MEM_ALLOC_DECL_PROTECT()
#define LWIP_MEM_ALLOC_PROTECT()
#define LWIP_MEM_ALLOC_UNPROTECT()
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
/**
* "Plug holes" by combining adjacent empty struct mems.
* After this function is through, there should not exist
* one empty struct mem pointing to another empty struct mem.
*
* @param mem this points to a struct mem which just has been freed
* @internal this function is only called by mem_free() and mem_trim()
*
* This assumes access to the heap is protected by the calling function
* already.
*/
static void
plug_holes(struct mem *mem)
{
struct mem *nmem;
struct mem *pmem;
LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
/* plug hole forward */
LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
nmem = (struct mem *)(void *)&ram[mem->next];
if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
/* if mem->next is unused and not end of ram, combine mem and mem->next */
if (lfree == nmem) {
lfree = mem;
}
mem->next = nmem->next;
((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram);
}
/* plug hole backward */
pmem = (struct mem *)(void *)&ram[mem->prev];
if (pmem != mem && pmem->used == 0) {
/* if mem->prev is unused, combine mem and mem->prev */
if (lfree == mem) {
lfree = pmem;
}
pmem->next = mem->next;
((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram);
}
}
/**
* Zero the heap and initialize start, end and lowest-free
*/
void
mem_init(void)
{
struct mem *mem;
LWIP_ASSERT("Sanity check alignment",
(SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);
/* align the heap */
ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER);
/* initialize the start of the heap */
mem = (struct mem *)(void *)ram;
mem->next = MEM_SIZE_ALIGNED;
mem->prev = 0;
mem->used = 0;
/* initialize the end of the heap */
ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED];
ram_end->used = 1;
ram_end->next = MEM_SIZE_ALIGNED;
ram_end->prev = MEM_SIZE_ALIGNED;
/* initialize the lowest-free pointer to the start of the heap */
lfree = (struct mem *)(void *)ram;
MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
if(sys_mutex_new(&mem_mutex) != ERR_OK) {
LWIP_ASSERT("failed to create mem_mutex", 0);
}
}
/**
* Put a struct mem back on the heap
*
* @param rmem is the data portion of a struct mem as returned by a previous
* call to mem_malloc()
*/
void
mem_free(void *rmem)
{
struct mem *mem;
LWIP_MEM_FREE_DECL_PROTECT();
if (rmem == NULL) {
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
return;
}
LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
(u8_t *)rmem < (u8_t *)ram_end);
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
SYS_ARCH_DECL_PROTECT(lev);
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
/* protect mem stats from concurrent access */
SYS_ARCH_PROTECT(lev);
MEM_STATS_INC(illegal);
SYS_ARCH_UNPROTECT(lev);
return;
}
/* protect the heap from concurrent access */
LWIP_MEM_FREE_PROTECT();
/* Get the corresponding struct mem ... */
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
/* ... which has to be in a used state ... */
LWIP_ASSERT("mem_free: mem->used", mem->used);
/* ... and is now unused. */
mem->used = 0;
if (mem < lfree) {
/* the newly freed struct is now the lowest */
lfree = mem;
}
MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram)));
/* finally, see if prev or next are free also */
plug_holes(mem);
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 1;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
LWIP_MEM_FREE_UNPROTECT();
}
/**
* Shrink memory returned by mem_malloc().
*
* @param rmem pointer to memory allocated by mem_malloc the is to be shrinked
* @param newsize required size after shrinking (needs to be smaller than or
* equal to the previous size)
* @return for compatibility reasons: is always == rmem, at the moment
* or NULL if newsize is > old size, in which case rmem is NOT touched
* or freed!
*/
void *
mem_trim(void *rmem, mem_size_t newsize)
{
mem_size_t size;
mem_size_t ptr, ptr2;
struct mem *mem, *mem2;
/* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
LWIP_MEM_FREE_DECL_PROTECT();
/* Expand the size of the allocated memory region so that we can
adjust for alignment. */
newsize = LWIP_MEM_ALIGN_SIZE(newsize);
if(newsize < MIN_SIZE_ALIGNED) {
/* every data block must be at least MIN_SIZE_ALIGNED long */
newsize = MIN_SIZE_ALIGNED;
}
if (newsize > MEM_SIZE_ALIGNED) {
return NULL;
}
LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
(u8_t *)rmem < (u8_t *)ram_end);
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
SYS_ARCH_DECL_PROTECT(lev);
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n"));
/* protect mem stats from concurrent access */
SYS_ARCH_PROTECT(lev);
MEM_STATS_INC(illegal);
SYS_ARCH_UNPROTECT(lev);
return rmem;
}
/* Get the corresponding struct mem ... */
mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
/* ... and its offset pointer */
ptr = (mem_size_t)((u8_t *)mem - ram);
size = mem->next - ptr - SIZEOF_STRUCT_MEM;
LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size);
if (newsize > size) {
/* not supported */
return NULL;
}
if (newsize == size) {
/* No change in size, simply return */
return rmem;
}
/* protect the heap from concurrent access */
LWIP_MEM_FREE_PROTECT();
mem2 = (struct mem *)(void *)&ram[mem->next];
if(mem2->used == 0) {
/* The next struct is unused, we can simply move it at little */
mem_size_t next;
/* remember the old next pointer */
next = mem2->next;
/* create new struct mem which is moved directly after the shrinked mem */
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
if (lfree == mem2) {
lfree = (struct mem *)(void *)&ram[ptr2];
}
mem2 = (struct mem *)(void *)&ram[ptr2];
mem2->used = 0;
/* restore the next pointer */
mem2->next = next;
/* link it back to mem */
mem2->prev = ptr;
/* link mem to it */
mem->next = ptr2;
/* last thing to restore linked list: as we have moved mem2,
* let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not
* the end of the heap */
if (mem2->next != MEM_SIZE_ALIGNED) {
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
}
MEM_STATS_DEC_USED(used, (size - newsize));
/* no need to plug holes, we've already done that */
} else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {
/* Next struct is used but there's room for another struct mem with
* at least MIN_SIZE_ALIGNED of data.
* Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem
* ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED').
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
* region that couldn't hold data, but when mem->next gets freed,
* the 2 regions would be combined, resulting in more free memory */
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
mem2 = (struct mem *)(void *)&ram[ptr2];
if (mem2 < lfree) {
lfree = mem2;
}
mem2->used = 0;
mem2->next = mem->next;
mem2->prev = ptr;
mem->next = ptr2;
if (mem2->next != MEM_SIZE_ALIGNED) {
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
}
MEM_STATS_DEC_USED(used, (size - newsize));
/* the original mem->next is used, so no need to plug holes! */
}
/* else {
next struct mem is used but size between mem and mem2 is not big enough
to create another struct mem
-> don't do anyhting.
-> the remaining space stays unused since it is too small
} */
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 1;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
LWIP_MEM_FREE_UNPROTECT();
return rmem;
}
/**
* Adam's mem_malloc() plus solution for bug #17922
* Allocate a block of memory with a minimum of 'size' bytes.
*
* @param size is the minimum size of the requested block in bytes.
* @return pointer to allocated memory or NULL if no free memory was found.
*
* Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).
*/
void *
mem_malloc(mem_size_t size)
{
mem_size_t ptr, ptr2;
struct mem *mem, *mem2;
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
u8_t local_mem_free_count = 0;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
LWIP_MEM_ALLOC_DECL_PROTECT();
if (size == 0) {
return NULL;
}
/* Expand the size of the allocated memory region so that we can
adjust for alignment. */
size = LWIP_MEM_ALIGN_SIZE(size);
if(size < MIN_SIZE_ALIGNED) {
/* every data block must be at least MIN_SIZE_ALIGNED long */
size = MIN_SIZE_ALIGNED;
}
if (size > MEM_SIZE_ALIGNED) {
return NULL;
}
/* protect the heap from concurrent access */
sys_mutex_lock(&mem_mutex);
LWIP_MEM_ALLOC_PROTECT();
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
/* run as long as a mem_free disturbed mem_malloc or mem_trim */
do {
local_mem_free_count = 0;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
/* Scan through the heap searching for a free block that is big enough,
* beginning with the lowest free block.
*/
for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size;
ptr = ((struct mem *)(void *)&ram[ptr])->next) {
mem = (struct mem *)(void *)&ram[ptr];
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 0;
LWIP_MEM_ALLOC_UNPROTECT();
/* allow mem_free or mem_trim to run */
LWIP_MEM_ALLOC_PROTECT();
if (mem_free_count != 0) {
/* If mem_free or mem_trim have run, we have to restart since they
could have altered our current struct mem. */
local_mem_free_count = 1;
break;
}
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
if ((!mem->used) &&
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
/* mem is not used and at least perfect fit is possible:
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
* -> split large block, create empty remainder,
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
* struct mem would fit in but no data between mem2 and mem2->next
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
* region that couldn't hold data, but when mem->next gets freed,
* the 2 regions would be combined, resulting in more free memory
*/
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
/* create mem2 struct */
mem2 = (struct mem *)(void *)&ram[ptr2];
mem2->used = 0;
mem2->next = mem->next;
mem2->prev = ptr;
/* and insert it between mem and mem->next */
mem->next = ptr2;
mem->used = 1;
if (mem2->next != MEM_SIZE_ALIGNED) {
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
}
MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
} else {
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
* take care of this).
* -> near fit or excact fit: do not split, no mem2 creation
* also can't move mem->next directly behind mem, since mem->next
* will always be used at this point!
*/
mem->used = 1;
MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));
}
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_malloc_adjust_lfree:
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
if (mem == lfree) {
struct mem *cur = lfree;
/* Find next free block after mem and update lowest free pointer */
while (cur->used && cur != ram_end) {
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 0;
LWIP_MEM_ALLOC_UNPROTECT();
/* prevent high interrupt latency... */
LWIP_MEM_ALLOC_PROTECT();
if (mem_free_count != 0) {
/* If mem_free or mem_trim have run, we have to restart since they
could have altered our current struct mem or lfree. */
goto mem_malloc_adjust_lfree;
}
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
cur = (struct mem *)(void *)&ram[cur->next];
}
lfree = cur;
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
}
LWIP_MEM_ALLOC_UNPROTECT();
sys_mutex_unlock(&mem_mutex);
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
LWIP_ASSERT("mem_malloc: sanity check alignment",
(((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
}
}
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
/* if we got interrupted by a mem_free, try again */
} while(local_mem_free_count != 0);
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
MEM_STATS_INC(err);
LWIP_MEM_ALLOC_UNPROTECT();
sys_mutex_unlock(&mem_mutex);
return NULL;
}
#endif /* MEM_USE_POOLS */
/**
* Contiguously allocates enough space for count objects that are size bytes
* of memory each and returns a pointer to the allocated memory.
*
* The allocated memory is filled with bytes of value zero.
*
* @param count number of objects to allocate
* @param size size of the objects to allocate
* @return pointer to allocated memory / NULL pointer if there is an error
*/
void *mem_calloc(mem_size_t count, mem_size_t size)
{
void *p;
/* allocate 'count' objects of size 'size' */
p = mem_malloc(count * size);
if (p) {
/* zero the memory */
memset(p, 0, count * size);
}
return p;
}
#endif /* !MEM_LIBC_MALLOC */

View File

@ -1,470 +0,0 @@
/**
* @file
* Dynamic pool memory manager
*
* lwIP has dedicated pools for many structures (netconn, protocol control blocks,
* packet buffers, ...). All these pools are managed here.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/memp.h"
#include "lwip/pbuf.h"
#include "lwip/udp.h"
#include "lwip/raw.h"
#include "lwip/tcp_impl.h"
#include "lwip/igmp.h"
#include "lwip/api.h"
#include "lwip/api_msg.h"
#include "lwip/tcpip.h"
#include "lwip/sys.h"
#include "lwip/timers.h"
#include "lwip/stats.h"
#include "netif/etharp.h"
#include "lwip/ip_frag.h"
#include "lwip/snmp_structs.h"
#include "lwip/snmp_msg.h"
#include "lwip/dns.h"
#include "netif/ppp_oe.h"
#include <string.h>
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
struct memp {
struct memp *next;
#if MEMP_OVERFLOW_CHECK
const char *file;
int line;
#endif /* MEMP_OVERFLOW_CHECK */
};
#if MEMP_OVERFLOW_CHECK
/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
* and at the end of each element, initialize them as 0xcd and check
* them later. */
/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
* every single element in each pool is checked!
* This is VERY SLOW but also very helpful. */
/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
* lwipopts.h to change the amount reserved for checking. */
#ifndef MEMP_SANITY_REGION_BEFORE
#define MEMP_SANITY_REGION_BEFORE 16
#endif /* MEMP_SANITY_REGION_BEFORE*/
#if MEMP_SANITY_REGION_BEFORE > 0
#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
#else
#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0
#endif /* MEMP_SANITY_REGION_BEFORE*/
#ifndef MEMP_SANITY_REGION_AFTER
#define MEMP_SANITY_REGION_AFTER 16
#endif /* MEMP_SANITY_REGION_AFTER*/
#if MEMP_SANITY_REGION_AFTER > 0
#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
#else
#define MEMP_SANITY_REGION_AFTER_ALIGNED 0
#endif /* MEMP_SANITY_REGION_AFTER*/
/* MEMP_SIZE: save space for struct memp and for sanity check */
#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
#else /* MEMP_OVERFLOW_CHECK */
/* No sanity checks
* We don't need to preserve the struct memp while not allocated, so we
* can save a little space and set MEMP_SIZE to 0.
*/
#define MEMP_SIZE 0
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
#endif /* MEMP_OVERFLOW_CHECK */
/** This array holds the first free element of each pool.
* Elements form a linked list. */
static struct memp *memp_tab[MEMP_MAX];
#else /* MEMP_MEM_MALLOC */
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
#endif /* MEMP_MEM_MALLOC */
/** This array holds the element sizes of each pool. */
#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
static
#endif
const u16_t memp_sizes[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size),
#include "lwip/memp_std.h"
};
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
/** This array holds the number of elements in each pool. */
static const u16_t memp_num[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) (num),
#include "lwip/memp_std.h"
};
/** This array holds a textual description of each pool. */
#ifdef LWIP_DEBUG
static const char *memp_desc[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) (desc),
#include "lwip/memp_std.h"
};
#endif /* LWIP_DEBUG */
#if MEMP_SEPARATE_POOLS
/** This creates each memory pool. These are named memp_memory_XXX_base (where
* XXX is the name of the pool defined in memp_std.h).
* To relocate a pool, declare it as extern in cc.h. Example for GCC:
* extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[];
*/
#define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \
[((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))];
#include "lwip/memp_std.h"
/** This array holds the base of each memory pool. */
static u8_t *const memp_bases[] = {
#define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base,
#include "lwip/memp_std.h"
};
#else /* MEMP_SEPARATE_POOLS */
/** This is the actual memory used by the pools (all pools in one big block). */
static u8_t memp_memory[MEM_ALIGNMENT - 1
#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
#include "lwip/memp_std.h"
];
#endif /* MEMP_SEPARATE_POOLS */
#if MEMP_SANITY_CHECK
/**
* Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm".
*/
static int
memp_sanity(void)
{
s16_t i;
struct memp *t, *h;
for (i = 0; i < MEMP_MAX; i++) {
t = memp_tab[i];
if(t != NULL) {
for (h = t->next; (t != NULL) && (h != NULL); t = t->next,
h = (((h->next != NULL) && (h->next->next != NULL)) ? h->next->next : NULL)) {
if (t == h) {
return 0;
}
}
}
}
return 1;
}
#endif /* MEMP_SANITY_CHECK*/
#if MEMP_OVERFLOW_CHECK
#if defined(LWIP_DEBUG) && MEMP_STATS
static const char * memp_overflow_names[] = {
#define LWIP_MEMPOOL(name,num,size,desc) "/"desc,
#include "lwip/memp_std.h"
};
#endif
/**
* Check if a memp element was victim of an overflow
* (e.g. the restricted area after it has been altered)
*
* @param p the memp element to check
* @param memp_type the pool p comes from
*/
static void
memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)
{
u16_t k;
u8_t *m;
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type];
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
if (m[k] != 0xcd) {
char errstr[128] = "detected memp overflow in pool ";
char digit[] = "0";
if(memp_type >= 10) {
digit[0] = '0' + (memp_type/10);
strcat(errstr, digit);
}
digit[0] = '0' + (memp_type%10);
strcat(errstr, digit);
#if defined(LWIP_DEBUG) && MEMP_STATS
strcat(errstr, memp_overflow_names[memp_type]);
#endif
LWIP_ASSERT(errstr, 0);
}
}
#endif
}
/**
* Check if a memp element was victim of an underflow
* (e.g. the restricted area before it has been altered)
*
* @param p the memp element to check
* @param memp_type the pool p comes from
*/
static void
memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)
{
u16_t k;
u8_t *m;
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
if (m[k] != 0xcd) {
char errstr[128] = "detected memp underflow in pool ";
char digit[] = "0";
if(memp_type >= 10) {
digit[0] = '0' + (memp_type/10);
strcat(errstr, digit);
}
digit[0] = '0' + (memp_type%10);
strcat(errstr, digit);
#if defined(LWIP_DEBUG) && MEMP_STATS
strcat(errstr, memp_overflow_names[memp_type]);
#endif
LWIP_ASSERT(errstr, 0);
}
}
#endif
}
/**
* Do an overflow check for all elements in every pool.
*
* @see memp_overflow_check_element for a description of the check
*/
static void
memp_overflow_check_all(void)
{
u16_t i, j;
struct memp *p;
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
for (i = 0; i < MEMP_MAX; ++i) {
p = p;
for (j = 0; j < memp_num[i]; ++j) {
memp_overflow_check_element_overflow(p, i);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
}
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
for (i = 0; i < MEMP_MAX; ++i) {
p = p;
for (j = 0; j < memp_num[i]; ++j) {
memp_overflow_check_element_underflow(p, i);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
}
}
/**
* Initialize the restricted areas of all memp elements in every pool.
*/
static void
memp_overflow_init(void)
{
u16_t i, j;
struct memp *p;
u8_t *m;
p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
for (i = 0; i < MEMP_MAX; ++i) {
p = p;
for (j = 0; j < memp_num[i]; ++j) {
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
#endif
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE + memp_sizes[i];
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
#endif
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
}
}
#endif /* MEMP_OVERFLOW_CHECK */
/**
* Initialize this module.
*
* Carves out memp_memory into linked lists for each pool-type.
*/
void
memp_init(void)
{
struct memp *memp;
u16_t i, j;
for (i = 0; i < MEMP_MAX; ++i) {
MEMP_STATS_AVAIL(used, i, 0);
MEMP_STATS_AVAIL(max, i, 0);
MEMP_STATS_AVAIL(err, i, 0);
MEMP_STATS_AVAIL(avail, i, memp_num[i]);
}
#if !MEMP_SEPARATE_POOLS
memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory);
#endif /* !MEMP_SEPARATE_POOLS */
/* for every pool: */
for (i = 0; i < MEMP_MAX; ++i) {
memp_tab[i] = NULL;
#if MEMP_SEPARATE_POOLS
memp = (struct memp*)memp_bases[i];
#endif /* MEMP_SEPARATE_POOLS */
/* create a linked list of memp elements */
for (j = 0; j < memp_num[i]; ++j) {
memp->next = memp_tab[i];
memp_tab[i] = memp;
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
#if MEMP_OVERFLOW_CHECK
+ MEMP_SANITY_REGION_AFTER_ALIGNED
#endif
);
}
}
#if MEMP_OVERFLOW_CHECK
memp_overflow_init();
/* check everything a first time to see if it worked */
memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK */
}
/**
* Get an element from a specific pool.
*
* @param type the pool to get an element from
*
* the debug version has two more parameters:
* @param file file name calling this function
* @param line number of line where this function is called
*
* @return a pointer to the allocated memory or a NULL pointer on error
*/
void *
#if !MEMP_OVERFLOW_CHECK
memp_malloc(memp_t type)
#else
memp_malloc_fn(memp_t type, const char* file, const int line)
#endif
{
struct memp *memp;
SYS_ARCH_DECL_PROTECT(old_level);
LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
SYS_ARCH_PROTECT(old_level);
#if MEMP_OVERFLOW_CHECK >= 2
memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
memp = memp_tab[type];
if (memp != NULL) {
memp_tab[type] = memp->next;
#if MEMP_OVERFLOW_CHECK
memp->next = NULL;
memp->file = file;
memp->line = line;
#endif /* MEMP_OVERFLOW_CHECK */
MEMP_STATS_INC_USED(used, type);
LWIP_ASSERT("memp_malloc: memp properly aligned",
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);
} else {
LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
MEMP_STATS_INC(err, type);
}
SYS_ARCH_UNPROTECT(old_level);
return memp;
}
/**
* Put an element back into its pool.
*
* @param type the pool where to put mem
* @param mem the memp element to free
*/
void
memp_free(memp_t type, void *mem)
{
struct memp *memp;
SYS_ARCH_DECL_PROTECT(old_level);
if (mem == NULL) {
return;
}
LWIP_ASSERT("memp_free: mem properly aligned",
((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);
SYS_ARCH_PROTECT(old_level);
#if MEMP_OVERFLOW_CHECK
#if MEMP_OVERFLOW_CHECK >= 2
memp_overflow_check_all();
#else
memp_overflow_check_element_overflow(memp, type);
memp_overflow_check_element_underflow(memp, type);
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
#endif /* MEMP_OVERFLOW_CHECK */
MEMP_STATS_DEC(used, type);
memp->next = memp_tab[type];
memp_tab[type] = memp;
#if MEMP_SANITY_CHECK
LWIP_ASSERT("memp sanity", memp_sanity());
#endif /* MEMP_SANITY_CHECK */
SYS_ARCH_UNPROTECT(old_level);
}
#endif /* MEMP_MEM_MALLOC */

View File

@ -1,774 +0,0 @@
/**
* @file
* lwIP network interface abstraction
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/tcp_impl.h"
#include "lwip/snmp.h"
#include "lwip/igmp.h"
#include "netif/etharp.h"
#include "lwip/stats.h"
#if ENABLE_LOOPBACK
#include "lwip/sys.h"
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
#include "lwip/tcpip.h"
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */
#if LWIP_AUTOIP
#include "lwip/autoip.h"
#endif /* LWIP_AUTOIP */
#if LWIP_DHCP
#include "lwip/dhcp.h"
#endif /* LWIP_DHCP */
#if LWIP_NETIF_STATUS_CALLBACK
#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
#else
#define NETIF_STATUS_CALLBACK(n)
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0)
#else
#define NETIF_LINK_CALLBACK(n)
#endif /* LWIP_NETIF_LINK_CALLBACK */
struct netif *netif_list;
struct netif *netif_default;
static u8_t netif_num;
#if LWIP_HAVE_LOOPIF
static struct netif loop_netif;
/**
* Initialize a lwip network interface structure for a loopback interface
*
* @param netif the lwip network interface structure for this loopif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
*/
static err_t
netif_loopif_init(struct netif *netif)
{
/* initialize the snmp variables and counters inside the struct netif
* ifSpeed: no assumption can be made!
*/
NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0);
netif->name[0] = 'l';
netif->name[1] = 'o';
netif->output = netif_loop_output;
return ERR_OK;
}
#endif /* LWIP_HAVE_LOOPIF */
void
netif_init(void)
{
#if LWIP_HAVE_LOOPIF
ip_addr_t loop_ipaddr, loop_netmask, loop_gw;
IP4_ADDR(&loop_gw, 127,0,0,1);
IP4_ADDR(&loop_ipaddr, 127,0,0,1);
IP4_ADDR(&loop_netmask, 255,0,0,0);
#if NO_SYS
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input);
#else /* NO_SYS */
netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input);
#endif /* NO_SYS */
netif_set_up(&loop_netif);
#endif /* LWIP_HAVE_LOOPIF */
}
/**
* Add a network interface to the list of lwIP netifs.
*
* @param netif a pre-allocated netif structure
* @param ipaddr IP address for the new netif
* @param netmask network mask for the new netif
* @param gw default gateway IP address for the new netif
* @param state opaque data passed to the new netif
* @param init callback function that initializes the interface
* @param input callback function that is called to pass
* ingress packets up in the protocol layer stack.
*
* @return netif, or NULL if failed.
*/
struct netif *
netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
{
LWIP_ASSERT("No init function given", init != NULL);
/* reset new interface configuration state */
ip_addr_set_zero(&netif->ip_addr);
ip_addr_set_zero(&netif->netmask);
ip_addr_set_zero(&netif->gw);
netif->flags = 0;
#if LWIP_DHCP
/* netif not under DHCP control by default */
netif->dhcp = NULL;
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/* netif not under AutoIP control by default */
netif->autoip = NULL;
#endif /* LWIP_AUTOIP */
#if LWIP_NETIF_STATUS_CALLBACK
netif->status_callback = NULL;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
netif->link_callback = NULL;
#endif /* LWIP_NETIF_LINK_CALLBACK */
#if LWIP_IGMP
netif->igmp_mac_filter = NULL;
#endif /* LWIP_IGMP */
#if ENABLE_LOOPBACK
netif->loop_first = NULL;
netif->loop_last = NULL;
#endif /* ENABLE_LOOPBACK */
/* remember netif specific state information data */
netif->state = state;
netif->num = netif_num++;
netif->input = input;
NETIF_SET_HWADDRHINT(netif, NULL);
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
netif->loop_cnt_current = 0;
#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
netif_set_addr(netif, ipaddr, netmask, gw);
/* call user specified initialization function for netif */
if (init(netif) != ERR_OK) {
return NULL;
}
/* add this netif to the list */
netif->next = netif_list;
netif_list = netif;
snmp_inc_iflist();
#if LWIP_IGMP
/* start IGMP processing */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_start(netif);
}
#endif /* LWIP_IGMP */
LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",
netif->name[0], netif->name[1]));
ip_addr_debug_print(NETIF_DEBUG, ipaddr);
LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
ip_addr_debug_print(NETIF_DEBUG, netmask);
LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
ip_addr_debug_print(NETIF_DEBUG, gw);
LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
return netif;
}
/**
* Change IP address configuration for a network interface (including netmask
* and default gateway).
*
* @param netif the network interface to change
* @param ipaddr the new IP address
* @param netmask the new netmask
* @param gw the new default gateway
*/
void
netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw)
{
netif_set_ipaddr(netif, ipaddr);
netif_set_netmask(netif, netmask);
netif_set_gw(netif, gw);
}
/**
* Remove a network interface from the list of lwIP netifs.
*
* @param netif the network interface to remove
*/
void
netif_remove(struct netif *netif)
{
if (netif == NULL) {
return;
}
#if LWIP_IGMP
/* stop IGMP processing */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_stop(netif);
}
#endif /* LWIP_IGMP */
if (netif_is_up(netif)) {
/* set netif down before removing (call callback function) */
netif_set_down(netif);
}
snmp_delete_ipaddridx_tree(netif);
/* is it the first netif? */
if (netif_list == netif) {
netif_list = netif->next;
} else {
/* look for netif further down the list */
struct netif * tmpNetif;
for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {
if (tmpNetif->next == netif) {
tmpNetif->next = netif->next;
break;
}
}
if (tmpNetif == NULL)
return; /* we didn't find any netif today */
}
snmp_dec_iflist();
/* this netif is default? */
if (netif_default == netif) {
/* reset default netif */
netif_set_default(NULL);
}
#if LWIP_NETIF_REMOVE_CALLBACK
if (netif->remove_callback) {
netif->remove_callback(netif);
}
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
}
/**
* Find a network interface by searching for its name
*
* @param name the name of the netif (like netif->name) plus concatenated number
* in ascii representation (e.g. 'en0')
*/
struct netif *
netif_find(char *name)
{
struct netif *netif;
u8_t num;
if (name == NULL) {
return NULL;
}
num = name[2] - '0';
for(netif = netif_list; netif != NULL; netif = netif->next) {
if (num == netif->num &&
name[0] == netif->name[0] &&
name[1] == netif->name[1]) {
LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));
return netif;
}
}
LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));
return NULL;
}
/**
* Change the IP address of a network interface
*
* @param netif the network interface to change
* @param ipaddr the new IP address
*
* @note call netif_set_addr() if you also want to change netmask and
* default gateway
*/
void
netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
{
/* TODO: Handling of obsolete pcbs */
/* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
#if LWIP_TCP
struct tcp_pcb *pcb;
struct tcp_pcb_listen *lpcb;
/* address is actually being changed? */
if (ipaddr && (ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
/* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
pcb = tcp_active_pcbs;
while (pcb != NULL) {
/* PCB bound to current local interface address? */
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))
#if LWIP_AUTOIP
/* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
&& !ip_addr_islinklocal(&(pcb->local_ip))
#endif /* LWIP_AUTOIP */
) {
/* this connection must be aborted */
struct tcp_pcb *next = pcb->next;
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
tcp_abort(pcb);
pcb = next;
} else {
pcb = pcb->next;
}
}
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
/* PCB bound to current local interface address? */
if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
(ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
/* The PCB is listening to the old ipaddr and
* is set to listen to the new one instead */
ip_addr_set(&(lpcb->local_ip), ipaddr);
}
}
}
#endif
snmp_delete_ipaddridx_tree(netif);
snmp_delete_iprteidx_tree(0,netif);
/* set new IP address to netif */
ip_addr_set(&(netif->ip_addr), ipaddr);
snmp_insert_ipaddridx_tree(netif);
snmp_insert_iprteidx_tree(0,netif);
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
netif->name[0], netif->name[1],
ip4_addr1_16(&netif->ip_addr),
ip4_addr2_16(&netif->ip_addr),
ip4_addr3_16(&netif->ip_addr),
ip4_addr4_16(&netif->ip_addr)));
}
/**
* Change the default gateway for a network interface
*
* @param netif the network interface to change
* @param gw the new default gateway
*
* @note call netif_set_addr() if you also want to change ip address and netmask
*/
void
netif_set_gw(struct netif *netif, ip_addr_t *gw)
{
ip_addr_set(&(netif->gw), gw);
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
netif->name[0], netif->name[1],
ip4_addr1_16(&netif->gw),
ip4_addr2_16(&netif->gw),
ip4_addr3_16(&netif->gw),
ip4_addr4_16(&netif->gw)));
}
/**
* Change the netmask of a network interface
*
* @param netif the network interface to change
* @param netmask the new netmask
*
* @note call netif_set_addr() if you also want to change ip address and
* default gateway
*/
void
netif_set_netmask(struct netif *netif, ip_addr_t *netmask)
{
snmp_delete_iprteidx_tree(0, netif);
/* set new netmask to netif */
ip_addr_set(&(netif->netmask), netmask);
snmp_insert_iprteidx_tree(0, netif);
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
netif->name[0], netif->name[1],
ip4_addr1_16(&netif->netmask),
ip4_addr2_16(&netif->netmask),
ip4_addr3_16(&netif->netmask),
ip4_addr4_16(&netif->netmask)));
}
/**
* Set a network interface as the default network interface
* (used to output all packets for which no specific route is found)
*
* @param netif the default network interface
*/
void
netif_set_default(struct netif *netif)
{
if (netif == NULL) {
/* remove default route */
snmp_delete_iprteidx_tree(1, netif);
} else {
/* install default route */
snmp_insert_iprteidx_tree(1, netif);
}
netif_default = netif;
LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",
netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
}
/**
* Bring an interface up, available for processing
* traffic.
*
* @note: Enabling DHCP on a down interface will make it come
* up once configured.
*
* @see dhcp_start()
*/
void netif_set_up(struct netif *netif)
{
if (!(netif->flags & NETIF_FLAG_UP)) {
netif->flags |= NETIF_FLAG_UP;
#if LWIP_SNMP
snmp_get_sysuptime(&netif->ts);
#endif /* LWIP_SNMP */
NETIF_STATUS_CALLBACK(netif);
if (netif->flags & NETIF_FLAG_LINK_UP) {
#if LWIP_ARP
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
if (netif->flags & (NETIF_FLAG_ETHARP)) {
etharp_gratuitous(netif);
}
#endif /* LWIP_ARP */
#if LWIP_IGMP
/* resend IGMP memberships */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_report_groups( netif);
}
#endif /* LWIP_IGMP */
}
}
}
/**
* Bring an interface down, disabling any traffic processing.
*
* @note: Enabling DHCP on a down interface will make it come
* up once configured.
*
* @see dhcp_start()
*/
void netif_set_down(struct netif *netif)
{
if (netif->flags & NETIF_FLAG_UP) {
netif->flags &= ~NETIF_FLAG_UP;
#if LWIP_SNMP
snmp_get_sysuptime(&netif->ts);
#endif
#if LWIP_ARP
if (netif->flags & NETIF_FLAG_ETHARP) {
etharp_cleanup_netif(netif);
}
#endif /* LWIP_ARP */
NETIF_STATUS_CALLBACK(netif);
}
}
#if LWIP_NETIF_STATUS_CALLBACK
/**
* Set callback to be called when interface is brought up/down
*/
void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)
{
if (netif) {
netif->status_callback = status_callback;
}
}
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_REMOVE_CALLBACK
/**
* Set callback to be called when the interface has been removed
*/
void
netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback)
{
if (netif) {
netif->remove_callback = remove_callback;
}
}
#endif /* LWIP_NETIF_REMOVE_CALLBACK */
/**
* Called by a driver when its link goes up
*/
void netif_set_link_up(struct netif *netif )
{
if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
netif->flags |= NETIF_FLAG_LINK_UP;
#if LWIP_DHCP
if (netif->dhcp) {
dhcp_network_changed(netif);
}
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
if (netif->autoip) {
autoip_network_changed(netif);
}
#endif /* LWIP_AUTOIP */
if (netif->flags & NETIF_FLAG_UP) {
#if LWIP_ARP
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
if (netif->flags & NETIF_FLAG_ETHARP) {
etharp_gratuitous(netif);
}
#endif /* LWIP_ARP */
#if LWIP_IGMP
/* resend IGMP memberships */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_report_groups( netif);
}
#endif /* LWIP_IGMP */
}
NETIF_LINK_CALLBACK(netif);
}
}
/**
* Called by a driver when its link goes down
*/
void netif_set_link_down(struct netif *netif )
{
if (netif->flags & NETIF_FLAG_LINK_UP) {
netif->flags &= ~NETIF_FLAG_LINK_UP;
NETIF_LINK_CALLBACK(netif);
}
}
#if LWIP_NETIF_LINK_CALLBACK
/**
* Set callback to be called when link is brought up/down
*/
void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)
{
if (netif) {
netif->link_callback = link_callback;
}
}
#endif /* LWIP_NETIF_LINK_CALLBACK */
#if ENABLE_LOOPBACK
/**
* Send an IP packet to be received on the same netif (loopif-like).
* The pbuf is simply copied and handed back to netif->input.
* In multithreaded mode, this is done directly since netif->input must put
* the packet on a queue.
* In callback mode, the packet is put on an internal queue and is fed to
* netif->input by netif_poll().
*
* @param netif the lwip network interface structure
* @param p the (IP) packet to 'send'
* @param ipaddr the ip address to send the packet to (not used)
* @return ERR_OK if the packet has been sent
* ERR_MEM if the pbuf used to copy the packet couldn't be allocated
*/
err_t
netif_loop_output(struct netif *netif, struct pbuf *p,
ip_addr_t *ipaddr)
{
struct pbuf *r;
err_t err;
struct pbuf *last;
#if LWIP_LOOPBACK_MAX_PBUFS
u8_t clen = 0;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
/* If we have a loopif, SNMP counters are adjusted for it,
* if not they are adjusted for 'netif'. */
#if LWIP_SNMP
#if LWIP_HAVE_LOOPIF
struct netif *stats_if = &loop_netif;
#else /* LWIP_HAVE_LOOPIF */
struct netif *stats_if = netif;
#endif /* LWIP_HAVE_LOOPIF */
#endif /* LWIP_SNMP */
SYS_ARCH_DECL_PROTECT(lev);
LWIP_UNUSED_ARG(ipaddr);
/* Allocate a new pbuf */
r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
if (r == NULL) {
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
snmp_inc_ifoutdiscards(stats_if);
return ERR_MEM;
}
#if LWIP_LOOPBACK_MAX_PBUFS
clen = pbuf_clen(r);
/* check for overflow or too many pbuf on queue */
if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
pbuf_free(r);
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
snmp_inc_ifoutdiscards(stats_if);
return ERR_MEM;
}
netif->loop_cnt_current += clen;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
/* Copy the whole pbuf queue p into the single pbuf r */
if ((err = pbuf_copy(r, p)) != ERR_OK) {
pbuf_free(r);
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
snmp_inc_ifoutdiscards(stats_if);
return err;
}
/* Put the packet on a linked list which gets emptied through calling
netif_poll(). */
/* let last point to the last pbuf in chain r */
for (last = r; last->next != NULL; last = last->next);
SYS_ARCH_PROTECT(lev);
if(netif->loop_first != NULL) {
LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
netif->loop_last->next = r;
netif->loop_last = last;
} else {
netif->loop_first = r;
netif->loop_last = last;
}
SYS_ARCH_UNPROTECT(lev);
LINK_STATS_INC(link.xmit);
snmp_add_ifoutoctets(stats_if, p->tot_len);
snmp_inc_ifoutucastpkts(stats_if);
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
/* For multithreading environment, schedule a call to netif_poll */
tcpip_callback((tcpip_callback_fn)netif_poll, netif);
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
return ERR_OK;
}
/**
* Call netif_poll() in the main loop of your application. This is to prevent
* reentering non-reentrant functions like tcp_input(). Packets passed to
* netif_loop_output() are put on a list that is passed to netif->input() by
* netif_poll().
*/
void
netif_poll(struct netif *netif)
{
struct pbuf *in;
/* If we have a loopif, SNMP counters are adjusted for it,
* if not they are adjusted for 'netif'. */
#if LWIP_SNMP
#if LWIP_HAVE_LOOPIF
struct netif *stats_if = &loop_netif;
#else /* LWIP_HAVE_LOOPIF */
struct netif *stats_if = netif;
#endif /* LWIP_HAVE_LOOPIF */
#endif /* LWIP_SNMP */
SYS_ARCH_DECL_PROTECT(lev);
do {
/* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
SYS_ARCH_PROTECT(lev);
in = netif->loop_first;
if (in != NULL) {
struct pbuf *in_end = in;
#if LWIP_LOOPBACK_MAX_PBUFS
u8_t clen = pbuf_clen(in);
/* adjust the number of pbufs on queue */
LWIP_ASSERT("netif->loop_cnt_current underflow",
((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
netif->loop_cnt_current -= clen;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
while (in_end->len != in_end->tot_len) {
LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
in_end = in_end->next;
}
/* 'in_end' now points to the last pbuf from 'in' */
if (in_end == netif->loop_last) {
/* this was the last pbuf in the list */
netif->loop_first = netif->loop_last = NULL;
} else {
/* pop the pbuf off the list */
netif->loop_first = in_end->next;
LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
}
/* De-queue the pbuf from its successors on the 'loop_' list. */
in_end->next = NULL;
}
SYS_ARCH_UNPROTECT(lev);
if (in != NULL) {
LINK_STATS_INC(link.recv);
snmp_add_ifinoctets(stats_if, in->tot_len);
snmp_inc_ifinucastpkts(stats_if);
/* loopback packets are always IP packets! */
if (ip_input(in, netif) != ERR_OK) {
pbuf_free(in);
}
/* Don't reference the packet any more! */
in = NULL;
}
/* go on while there is a packet on the list */
} while (netif->loop_first != NULL);
}
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
/**
* Calls netif_poll() for every netif on the netif_list.
*/
void
netif_poll_all(void)
{
struct netif *netif = netif_list;
/* loop through netifs */
while (netif != NULL) {
netif_poll(netif);
/* proceed to next network interface */
netif = netif->next;
}
}
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */

File diff suppressed because it is too large Load Diff

View File

@ -1,350 +0,0 @@
/**
* @file
* Implementation of raw protocol PCBs for low-level handling of
* different types of protocols besides (or overriding) those
* already available in lwIP.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/raw.h"
#include "lwip/stats.h"
#include "arch/perf.h"
#include <string.h>
/** The list of RAW PCBs */
static struct raw_pcb *raw_pcbs;
/**
* Determine if in incoming IP packet is covered by a RAW PCB
* and if so, pass it to a user-provided receive callback function.
*
* Given an incoming IP datagram (as a chain of pbufs) this function
* finds a corresponding RAW PCB and calls the corresponding receive
* callback function.
*
* @param p pbuf to be demultiplexed to a RAW PCB.
* @param inp network interface on which the datagram was received.
* @return - 1 if the packet has been eaten by a RAW PCB receive
* callback function. The caller MAY NOT not reference the
* packet any longer, and MAY NOT call pbuf_free().
* @return - 0 if packet is not eaten (pbuf is still referenced by the
* caller).
*
*/
u8_t
raw_input(struct pbuf *p, struct netif *inp)
{
struct raw_pcb *pcb, *prev;
struct ip_hdr *iphdr;
s16_t proto;
u8_t eaten = 0;
LWIP_UNUSED_ARG(inp);
iphdr = (struct ip_hdr *)p->payload;
proto = IPH_PROTO(iphdr);
prev = NULL;
pcb = raw_pcbs;
/* loop through all raw pcbs until the packet is eaten by one */
/* this allows multiple pcbs to match against the packet by design */
while ((eaten == 0) && (pcb != NULL)) {
if ((pcb->protocol == proto) &&
(ip_addr_isany(&pcb->local_ip) ||
ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest))) {
#if IP_SOF_BROADCAST_RECV
/* broadcast filter? */
if (ip_get_option(pcb, SOF_BROADCAST) || !ip_addr_isbroadcast(&current_iphdr_dest, inp))
#endif /* IP_SOF_BROADCAST_RECV */
{
/* receive callback function available? */
if (pcb->recv != NULL) {
/* the receive callback function did not eat the packet? */
if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) {
/* receive function ate the packet */
p = NULL;
eaten = 1;
if (prev != NULL) {
/* move the pcb to the front of raw_pcbs so that is
found faster next time */
prev->next = pcb->next;
pcb->next = raw_pcbs;
raw_pcbs = pcb;
}
}
}
/* no receive callback function was set for this raw PCB */
}
/* drop the packet */
}
prev = pcb;
pcb = pcb->next;
}
return eaten;
}
/**
* Bind a RAW PCB.
*
* @param pcb RAW PCB to be bound with a local address ipaddr.
* @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
* bind to all local interfaces.
*
* @return lwIP error code.
* - ERR_OK. Successful. No error occured.
* - ERR_USE. The specified IP address is already bound to by
* another RAW PCB.
*
* @see raw_disconnect()
*/
err_t
raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
{
ip_addr_set(&pcb->local_ip, ipaddr);
return ERR_OK;
}
/**
* Connect an RAW PCB. This function is required by upper layers
* of lwip. Using the raw api you could use raw_sendto() instead
*
* This will associate the RAW PCB with the remote address.
*
* @param pcb RAW PCB to be connected with remote address ipaddr and port.
* @param ipaddr remote IP address to connect with.
*
* @return lwIP error code
*
* @see raw_disconnect() and raw_sendto()
*/
err_t
raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
{
ip_addr_set(&pcb->remote_ip, ipaddr);
return ERR_OK;
}
/**
* Set the callback function for received packets that match the
* raw PCB's protocol and binding.
*
* The callback function MUST either
* - eat the packet by calling pbuf_free() and returning non-zero. The
* packet will not be passed to other raw PCBs or other protocol layers.
* - not free the packet, and return zero. The packet will be matched
* against further PCBs and/or forwarded to another protocol layers.
*
* @return non-zero if the packet was free()d, zero if the packet remains
* available for others.
*/
void
raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
{
/* remember recv() callback and user data */
pcb->recv = recv;
pcb->recv_arg = recv_arg;
}
/**
* Send the raw IP packet to the given address. Note that actually you cannot
* modify the IP headers (this is inconsistent with the receive callback where
* you actually get the IP headers), you can only specify the IP payload here.
* It requires some more changes in lwIP. (there will be a raw_send() function
* then.)
*
* @param pcb the raw pcb which to send
* @param p the IP payload to send
* @param ipaddr the destination address of the IP packet
*
*/
err_t
raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
{
err_t err;
struct netif *netif;
ip_addr_t *src_ip;
struct pbuf *q; /* q will be sent down the stack */
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
/* not enough space to add an IP header to first pbuf in given p chain? */
if (pbuf_header(p, IP_HLEN)) {
/* allocate header in new pbuf */
q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
/* new header pbuf could not be allocated? */
if (q == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
return ERR_MEM;
}
if (p->tot_len != 0) {
/* chain header q in front of given pbuf p */
pbuf_chain(q, p);
}
/* { first pbuf q points to header pbuf } */
LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
} else {
/* first pbuf q equals given pbuf */
q = p;
if(pbuf_header(q, -IP_HLEN)) {
LWIP_ASSERT("Can't restore header we just removed!", 0);
return ERR_MEM;
}
}
if ((netif = ip_route(ipaddr)) == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
pbuf_free(q);
}
return ERR_RTE;
}
#if IP_SOF_BROADCAST
/* broadcast filter? */
if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
pbuf_free(q);
}
return ERR_VAL;
}
#endif /* IP_SOF_BROADCAST */
if (ip_addr_isany(&pcb->local_ip)) {
/* use outgoing network interface IP address as source address */
src_ip = &(netif->ip_addr);
} else {
/* use RAW PCB local IP address as source address */
src_ip = &(pcb->local_ip);
}
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
NETIF_SET_HWADDRHINT(netif, NULL);
/* did we chain a header earlier? */
if (q != p) {
/* free the header */
pbuf_free(q);
}
return err;
}
/**
* Send the raw IP packet to the address given by raw_connect()
*
* @param pcb the raw pcb which to send
* @param p the IP payload to send
*
*/
err_t
raw_send(struct raw_pcb *pcb, struct pbuf *p)
{
return raw_sendto(pcb, p, &pcb->remote_ip);
}
/**
* Remove an RAW PCB.
*
* @param pcb RAW PCB to be removed. The PCB is removed from the list of
* RAW PCB's and the data structure is freed from memory.
*
* @see raw_new()
*/
void
raw_remove(struct raw_pcb *pcb)
{
struct raw_pcb *pcb2;
/* pcb to be removed is first in list? */
if (raw_pcbs == pcb) {
/* make list start at 2nd pcb */
raw_pcbs = raw_pcbs->next;
/* pcb not 1st in list */
} else {
for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
/* find pcb in raw_pcbs list */
if (pcb2->next != NULL && pcb2->next == pcb) {
/* remove pcb from list */
pcb2->next = pcb->next;
}
}
}
memp_free(MEMP_RAW_PCB, pcb);
}
/**
* Create a RAW PCB.
*
* @return The RAW PCB which was created. NULL if the PCB data structure
* could not be allocated.
*
* @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
*
* @see raw_remove()
*/
struct raw_pcb *
raw_new(u8_t proto)
{
struct raw_pcb *pcb;
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
/* could allocate RAW PCB? */
if (pcb != NULL) {
/* initialize PCB to all zeroes */
memset(pcb, 0, sizeof(struct raw_pcb));
pcb->protocol = proto;
pcb->ttl = RAW_TTL;
pcb->next = raw_pcbs;
raw_pcbs = pcb;
}
return pcb;
}
#endif /* LWIP_RAW */

View File

@ -1,657 +0,0 @@
/**
* @file
* Abstract Syntax Notation One (ISO 8824, 8825) decoding
*
* @todo not optimised (yet), favor correctness over speed, favor speed over size
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/opt.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/snmp_asn1.h"
/**
* Retrieves type field from incoming pbuf chain.
*
* @param p points to a pbuf holding an ASN1 coded type field
* @param ofs points to the offset within the pbuf chain of the ASN1 coded type field
* @param type return ASN1 type
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
*type = *msg_ptr;
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Decodes length field from incoming pbuf chain into host length.
*
* @param p points to a pbuf holding an ASN1 coded length
* @param ofs points to the offset within the pbuf chain of the ASN1 coded length
* @param octets_used returns number of octets used by the length code
* @param length return host order length, upto 64k
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (*msg_ptr < 0x80)
{
/* primitive definite length format */
*octets_used = 1;
*length = *msg_ptr;
return ERR_OK;
}
else if (*msg_ptr == 0x80)
{
/* constructed indefinite length format, termination with two zero octets */
u8_t zeros;
u8_t i;
*length = 0;
zeros = 0;
while (zeros != 2)
{
i = 2;
while (i > 0)
{
i--;
(*length) += 1;
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
if (*msg_ptr == 0)
{
zeros++;
if (zeros == 2)
{
/* stop while (i > 0) */
i = 0;
}
}
else
{
zeros = 0;
}
}
}
*octets_used = 1;
return ERR_OK;
}
else if (*msg_ptr == 0x81)
{
/* constructed definite length format, one octet */
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
*length = *msg_ptr;
*octets_used = 2;
return ERR_OK;
}
else if (*msg_ptr == 0x82)
{
u8_t i;
/* constructed definite length format, two octets */
i = 2;
while (i > 0)
{
i--;
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
if (i == 0)
{
/* least significant length octet */
*length |= *msg_ptr;
}
else
{
/* most significant length octet */
*length = (*msg_ptr) << 8;
}
}
*octets_used = 3;
return ERR_OK;
}
else
{
/* constructed definite length format 3..127 octets, this is too big (>64k) */
/** @todo: do we need to accept inefficient codings with many leading zero's? */
*octets_used = 1 + ((*msg_ptr) & 0x7f);
return ERR_ARG;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Decodes positive integer (counter, gauge, timeticks) into u32_t.
*
* @param p points to a pbuf holding an ASN1 coded integer
* @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
err_t
snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if ((len > 0) && (len < 6))
{
/* start from zero */
*value = 0;
if (*msg_ptr & 0x80)
{
/* negative, expecting zero sign bit! */
return ERR_ARG;
}
else
{
/* positive */
if ((len > 1) && (*msg_ptr == 0))
{
/* skip leading "sign byte" octet 0x00 */
len--;
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
}
/* OR octets with value */
while (len > 1)
{
len--;
*value |= *msg_ptr;
*value <<= 8;
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
*value |= *msg_ptr;
return ERR_OK;
}
else
{
return ERR_ARG;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Decodes integer into s32_t.
*
* @param p points to a pbuf holding an ASN1 coded integer
* @param ofs points to the offset within the pbuf chain of the ASN1 coded integer
* @param len length of the coded integer field
* @param value return host order integer
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
*
* @note ASN coded integers are _always_ signed!
*/
err_t
snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)
{
u16_t plen, base;
u8_t *msg_ptr;
#if BYTE_ORDER == LITTLE_ENDIAN
u8_t *lsb_ptr = (u8_t*)value;
#endif
#if BYTE_ORDER == BIG_ENDIAN
u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;
#endif
u8_t sign;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if ((len > 0) && (len < 5))
{
if (*msg_ptr & 0x80)
{
/* negative, start from -1 */
*value = -1;
sign = 1;
}
else
{
/* positive, start from 0 */
*value = 0;
sign = 0;
}
/* OR/AND octets with value */
while (len > 1)
{
len--;
if (sign)
{
*lsb_ptr &= *msg_ptr;
*value <<= 8;
*lsb_ptr |= 255;
}
else
{
*lsb_ptr |= *msg_ptr;
*value <<= 8;
}
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
if (sign)
{
*lsb_ptr &= *msg_ptr;
}
else
{
*lsb_ptr |= *msg_ptr;
}
return ERR_OK;
}
else
{
return ERR_ARG;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Decodes object identifier from incoming message into array of s32_t.
*
* @param p points to a pbuf holding an ASN1 coded object identifier
* @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier
* @param len length of the coded object identifier
* @param oid return object identifier struct
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)
{
u16_t plen, base;
u8_t *msg_ptr;
s32_t *oid_ptr;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
oid->len = 0;
oid_ptr = &oid->id[0];
if (len > 0)
{
/* first compressed octet */
if (*msg_ptr == 0x2B)
{
/* (most) common case 1.3 (iso.org) */
*oid_ptr = 1;
oid_ptr++;
*oid_ptr = 3;
oid_ptr++;
}
else if (*msg_ptr < 40)
{
*oid_ptr = 0;
oid_ptr++;
*oid_ptr = *msg_ptr;
oid_ptr++;
}
else if (*msg_ptr < 80)
{
*oid_ptr = 1;
oid_ptr++;
*oid_ptr = (*msg_ptr) - 40;
oid_ptr++;
}
else
{
*oid_ptr = 2;
oid_ptr++;
*oid_ptr = (*msg_ptr) - 80;
oid_ptr++;
}
oid->len = 2;
}
else
{
/* accepting zero length identifiers e.g. for
getnext operation. uncommon but valid */
return ERR_OK;
}
len--;
if (len > 0)
{
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))
{
/* sub-identifier uses multiple octets */
if (*msg_ptr & 0x80)
{
s32_t sub_id = 0;
while ((*msg_ptr & 0x80) && (len > 1))
{
len--;
sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
if (!(*msg_ptr & 0x80) && (len > 0))
{
/* last octet sub-identifier */
len--;
sub_id = (sub_id << 7) + *msg_ptr;
*oid_ptr = sub_id;
}
}
else
{
/* !(*msg_ptr & 0x80) sub-identifier uses single octet */
len--;
*oid_ptr = *msg_ptr;
}
if (len > 0)
{
/* remaining oid bytes available ... */
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
oid_ptr++;
oid->len++;
}
if (len == 0)
{
/* len == 0, end of oid */
return ERR_OK;
}
else
{
/* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */
return ERR_ARG;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)
* from incoming message into array.
*
* @param p points to a pbuf holding an ASN1 coded raw data
* @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data
* @param len length of the coded raw data (zero is valid, e.g. empty string!)
* @param raw_len length of the raw return value
* @param raw return raw bytes
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode
*/
err_t
snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)
{
u16_t plen, base;
u8_t *msg_ptr;
if (len > 0)
{
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (raw_len >= len)
{
while (len > 1)
{
/* copy len - 1 octets */
len--;
*raw = *msg_ptr;
raw++;
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
/* copy last octet */
*raw = *msg_ptr;
return ERR_OK;
}
else
{
/* raw_len < len, not enough dst space */
return ERR_ARG;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
else
{
/* len == 0, empty string */
return ERR_OK;
}
}
#endif /* LWIP_SNMP */

View File

@ -1,611 +0,0 @@
/**
* @file
* Abstract Syntax Notation One (ISO 8824, 8825) encoding
*
* @todo not optimised (yet), favor correctness over speed, favor speed over size
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/opt.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/snmp_asn1.h"
/**
* Returns octet count for length.
*
* @param length
* @param octets_needed points to the return value
*/
void
snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)
{
if (length < 0x80U)
{
*octets_needed = 1;
}
else if (length < 0x100U)
{
*octets_needed = 2;
}
else
{
*octets_needed = 3;
}
}
/**
* Returns octet count for an u32_t.
*
* @param value
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded
* as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value
* of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!
*/
void
snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)
{
if (value < 0x80UL)
{
*octets_needed = 1;
}
else if (value < 0x8000UL)
{
*octets_needed = 2;
}
else if (value < 0x800000UL)
{
*octets_needed = 3;
}
else if (value < 0x80000000UL)
{
*octets_needed = 4;
}
else
{
*octets_needed = 5;
}
}
/**
* Returns octet count for an s32_t.
*
* @param value
* @param octets_needed points to the return value
*
* @note ASN coded integers are _always_ signed.
*/
void
snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)
{
if (value < 0)
{
value = ~value;
}
if (value < 0x80L)
{
*octets_needed = 1;
}
else if (value < 0x8000L)
{
*octets_needed = 2;
}
else if (value < 0x800000L)
{
*octets_needed = 3;
}
else
{
*octets_needed = 4;
}
}
/**
* Returns octet count for an object identifier.
*
* @param ident_len object identifier array length
* @param ident points to object identifier array
* @param octets_needed points to the return value
*/
void
snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed)
{
s32_t sub_id;
u8_t cnt;
cnt = 0;
if (ident_len > 1)
{
/* compressed prefix in one octet */
cnt++;
ident_len -= 2;
ident += 2;
}
while(ident_len > 0)
{
ident_len--;
sub_id = *ident;
sub_id >>= 7;
cnt++;
while(sub_id > 0)
{
sub_id >>= 7;
cnt++;
}
ident++;
}
*octets_needed = cnt;
}
/**
* Encodes ASN type field into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode value into
* @param ofs points to the offset within the pbuf chain
* @param type input ASN1 type
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
*msg_ptr = type;
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Encodes host order length field into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode length into
* @param ofs points to the offset within the pbuf chain
* @param length is the host order length to be encoded
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (length < 0x80)
{
*msg_ptr = (u8_t)length;
return ERR_OK;
}
else if (length < 0x100)
{
*msg_ptr = 0x81;
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
*msg_ptr = (u8_t)length;
return ERR_OK;
}
else
{
u8_t i;
/* length >= 0x100 && length <= 0xFFFF */
*msg_ptr = 0x82;
i = 2;
while (i > 0)
{
i--;
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
if (i == 0)
{
/* least significant length octet */
*msg_ptr = (u8_t)length;
}
else
{
/* most significant length octet */
*msg_ptr = (u8_t)(length >> 8);
}
}
return ERR_OK;
}
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode value into
* @param ofs points to the offset within the pbuf chain
* @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())
* @param value is the host order u32_t value to be encoded
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_u32t_cnt()
*/
err_t
snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (octets_needed == 5)
{
/* not enough bits in 'value' add leading 0x00 */
octets_needed--;
*msg_ptr = 0x00;
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
while (octets_needed > 1)
{
octets_needed--;
*msg_ptr = (u8_t)(value >> (octets_needed << 3));
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
/* (only) one least significant octet */
*msg_ptr = (u8_t)value;
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Encodes s32_t integer into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode value into
* @param ofs points to the offset within the pbuf chain
* @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())
* @param value is the host order s32_t value to be encoded
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
*
* @see snmp_asn1_enc_s32t_cnt()
*/
err_t
snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
while (octets_needed > 1)
{
octets_needed--;
*msg_ptr = (u8_t)(value >> (octets_needed << 3));
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
/* (only) one least significant octet */
*msg_ptr = (u8_t)value;
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Encodes object identifier into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode oid into
* @param ofs points to the offset within the pbuf chain
* @param ident_len object identifier array length
* @param ident points to object identifier array
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
if (ident_len > 1)
{
if ((ident[0] == 1) && (ident[1] == 3))
{
/* compressed (most common) prefix .iso.org */
*msg_ptr = 0x2b;
}
else
{
/* calculate prefix */
*msg_ptr = (u8_t)((ident[0] * 40) + ident[1]);
}
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
ident_len -= 2;
ident += 2;
}
else
{
/* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */
/* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */
return ERR_ARG;
}
while (ident_len > 0)
{
s32_t sub_id;
u8_t shift, tail;
ident_len--;
sub_id = *ident;
tail = 0;
shift = 28;
while(shift > 0)
{
u8_t code;
code = (u8_t)(sub_id >> shift);
if ((code != 0) || (tail != 0))
{
tail = 1;
*msg_ptr = code | 0x80;
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
shift -= 7;
}
*msg_ptr = (u8_t)sub_id & 0x7F;
if (ident_len > 0)
{
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
/* proceed to next sub-identifier */
ident++;
}
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
/**
* Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.
*
* @param p points to output pbuf to encode raw data into
* @param ofs points to the offset within the pbuf chain
* @param raw_len raw data length
* @param raw points raw data
* @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode
*/
err_t
snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw)
{
u16_t plen, base;
u8_t *msg_ptr;
plen = 0;
while (p != NULL)
{
base = plen;
plen += p->len;
if (ofs < plen)
{
msg_ptr = (u8_t*)p->payload;
msg_ptr += ofs - base;
while (raw_len > 1)
{
/* copy raw_len - 1 octets */
raw_len--;
*msg_ptr = *raw;
raw++;
ofs += 1;
if (ofs >= plen)
{
/* next octet in next pbuf */
p = p->next;
if (p == NULL) { return ERR_ARG; }
msg_ptr = (u8_t*)p->payload;
plen += p->len;
}
else
{
/* next octet in same pbuf */
msg_ptr++;
}
}
if (raw_len > 0)
{
/* copy last or single octet */
*msg_ptr = *raw;
}
return ERR_OK;
}
p = p->next;
}
/* p == NULL, ofs >= plen */
return ERR_ARG;
}
#endif /* LWIP_SNMP */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,674 +0,0 @@
/**
* @file
* SNMP output message processing (RFC1157).
*
* Output responses and traps are build in two passes:
*
* Pass 0: iterate over the output message backwards to determine encoding lengths
* Pass 1: the actual forward encoding of internal form into ASN1
*
* The single-pass encoding method described by Comer & Stevens
* requires extra buffer space and copying for reversal of the packet.
* The buffer requirement can be prohibitively large for big payloads
* (>= 484) therefore we use the two encoding passes.
*/
/*
* Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Christiaan Simons <christiaan.simons@axon.tv>
*/
#include "lwip/opt.h"
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/udp.h"
#include "lwip/netif.h"
#include "lwip/snmp.h"
#include "lwip/snmp_asn1.h"
#include "lwip/snmp_msg.h"
struct snmp_trap_dst
{
/* destination IP address in network order */
ip_addr_t dip;
/* set to 0 when disabled, >0 when enabled */
u8_t enable;
};
struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];
/** TRAP message structure */
struct snmp_msg_trap trap_msg;
static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len);
static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len);
static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root);
static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p);
static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p);
static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs);
/**
* Sets enable switch for this trap destination.
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
* @param enable switch if 0 destination is disabled >0 enabled.
*/
void
snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)
{
if (dst_idx < SNMP_TRAP_DESTINATIONS)
{
trap_dst[dst_idx].enable = enable;
}
}
/**
* Sets IPv4 address for this trap destination.
* @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1
* @param dst IPv4 address in host order.
*/
void
snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst)
{
if (dst_idx < SNMP_TRAP_DESTINATIONS)
{
ip_addr_set(&trap_dst[dst_idx].dip, dst);
}
}
/**
* Sends a 'getresponse' message to the request originator.
*
* @param m_stat points to the current message request state source
* @return ERR_OK when success, ERR_MEM if we're out of memory
*
* @note the caller is responsible for filling in outvb in the m_stat
* and provide error-status and index (except for tooBig errors) ...
*/
err_t
snmp_send_response(struct snmp_msg_pstat *m_stat)
{
struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0};
struct pbuf *p;
u16_t tot_len;
err_t err;
/* pass 0, calculate length fields */
tot_len = snmp_varbind_list_sum(&m_stat->outvb);
tot_len = snmp_resp_header_sum(m_stat, tot_len);
/* try allocating pbuf(s) for complete response */
p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
if (p == NULL)
{
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n"));
/* can't construct reply, return error-status tooBig */
m_stat->error_status = SNMP_ES_TOOBIG;
m_stat->error_index = 0;
/* pass 0, recalculate lengths, for empty varbind-list */
tot_len = snmp_varbind_list_sum(&emptyvb);
tot_len = snmp_resp_header_sum(m_stat, tot_len);
/* retry allocation once for header and empty varbind-list */
p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
}
if (p != NULL)
{
/* first pbuf alloc try or retry alloc success */
u16_t ofs;
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n"));
/* pass 1, size error, encode packet ino the pbuf(s) */
ofs = snmp_resp_header_enc(m_stat, p);
snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
switch (m_stat->error_status)
{
case SNMP_ES_TOOBIG:
snmp_inc_snmpouttoobigs();
break;
case SNMP_ES_NOSUCHNAME:
snmp_inc_snmpoutnosuchnames();
break;
case SNMP_ES_BADVALUE:
snmp_inc_snmpoutbadvalues();
break;
case SNMP_ES_GENERROR:
snmp_inc_snmpoutgenerrs();
break;
}
snmp_inc_snmpoutgetresponses();
snmp_inc_snmpoutpkts();
/** @todo do we need separate rx and tx pcbs for threaded case? */
/** connect to the originating source */
udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp);
err = udp_send(m_stat->pcb, p);
if (err == ERR_MEM)
{
/** @todo release some memory, retry and return tooBig? tooMuchHassle? */
err = ERR_MEM;
}
else
{
err = ERR_OK;
}
/** disassociate remote address and port with this pcb */
udp_disconnect(m_stat->pcb);
pbuf_free(p);
LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n"));
return err;
}
else
{
/* first pbuf alloc try or retry alloc failed
very low on memory, couldn't return tooBig */
return ERR_MEM;
}
}
/**
* Sends an generic or enterprise specific trap message.
*
* @param generic_trap is the trap code
* @param eoid points to enterprise object identifier
* @param specific_trap used for enterprise traps when generic_trap == 6
* @return ERR_OK when success, ERR_MEM if we're out of memory
*
* @note the caller is responsible for filling in outvb in the trap_msg
* @note the use of the enterpise identifier field
* is per RFC1215.
* Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps
* and .iso.org.dod.internet.private.enterprises.yourenterprise
* (sysObjectID) for specific traps.
*/
err_t
snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
{
struct snmp_trap_dst *td;
struct netif *dst_if;
ip_addr_t dst_ip;
struct pbuf *p;
u16_t i,tot_len;
for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)
{
if ((td->enable != 0) && !ip_addr_isany(&td->dip))
{
/* network order trap destination */
ip_addr_copy(trap_msg.dip, td->dip);
/* lookup current source address for this dst */
dst_if = ip_route(&td->dip);
ip_addr_copy(dst_ip, dst_if->ip_addr);
/* @todo: what about IPv6? */
trap_msg.sip_raw[0] = ip4_addr1(&dst_ip);
trap_msg.sip_raw[1] = ip4_addr2(&dst_ip);
trap_msg.sip_raw[2] = ip4_addr3(&dst_ip);
trap_msg.sip_raw[3] = ip4_addr4(&dst_ip);
trap_msg.gen_trap = generic_trap;
trap_msg.spc_trap = specific_trap;
if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)
{
/* enterprise-Specific trap */
trap_msg.enterprise = eoid;
}
else
{
/* generic (MIB-II) trap */
snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);
}
snmp_get_sysuptime(&trap_msg.ts);
/* pass 0, calculate length fields */
tot_len = snmp_varbind_list_sum(&trap_msg.outvb);
tot_len = snmp_trap_header_sum(&trap_msg, tot_len);
/* allocate pbuf(s) */
p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
if (p != NULL)
{
u16_t ofs;
/* pass 1, encode packet ino the pbuf(s) */
ofs = snmp_trap_header_enc(&trap_msg, p);
snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);
snmp_inc_snmpouttraps();
snmp_inc_snmpoutpkts();
/** send to the TRAP destination */
udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT);
pbuf_free(p);
}
else
{
return ERR_MEM;
}
}
}
return ERR_OK;
}
void
snmp_coldstart_trap(void)
{
trap_msg.outvb.head = NULL;
trap_msg.outvb.tail = NULL;
trap_msg.outvb.count = 0;
snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0);
}
void
snmp_authfail_trap(void)
{
u8_t enable;
snmp_get_snmpenableauthentraps(&enable);
if (enable == 1)
{
trap_msg.outvb.head = NULL;
trap_msg.outvb.tail = NULL;
trap_msg.outvb.count = 0;
snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0);
}
}
/**
* Sums response header field lengths from tail to head and
* returns resp_header_lengths for second encoding pass.
*
* @param vb_len varbind-list length
* @param rhl points to returned header lengths
* @return the required lenght for encoding the response header
*/
static u16_t
snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len)
{
u16_t tot_len;
struct snmp_resp_header_lengths *rhl;
rhl = &m_stat->rhl;
tot_len = vb_len;
snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen);
snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen);
tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen;
snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen);
snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen);
tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen;
snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen);
snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen);
tot_len += 1 + rhl->ridlenlen + rhl->ridlen;
rhl->pdulen = tot_len;
snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen);
tot_len += 1 + rhl->pdulenlen;
rhl->comlen = m_stat->com_strlen;
snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen);
tot_len += 1 + rhl->comlenlen + rhl->comlen;
snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen);
snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen);
tot_len += 1 + rhl->verlen + rhl->verlenlen;
rhl->seqlen = tot_len;
snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen);
tot_len += 1 + rhl->seqlenlen;
return tot_len;
}
/**
* Sums trap header field lengths from tail to head and
* returns trap_header_lengths for second encoding pass.
*
* @param vb_len varbind-list length
* @param thl points to returned header lengths
* @return the required lenght for encoding the trap header
*/
static u16_t
snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len)
{
u16_t tot_len;
struct snmp_trap_header_lengths *thl;
thl = &m_trap->thl;
tot_len = vb_len;
snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen);
snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen);
tot_len += 1 + thl->tslen + thl->tslenlen;
snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen);
snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen);
tot_len += 1 + thl->strplen + thl->strplenlen;
snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen);
snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen);
tot_len += 1 + thl->gtrplen + thl->gtrplenlen;
thl->aaddrlen = 4;
snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen);
tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen;
snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen);
snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen);
tot_len += 1 + thl->eidlen + thl->eidlenlen;
thl->pdulen = tot_len;
snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen);
tot_len += 1 + thl->pdulenlen;
thl->comlen = sizeof(snmp_publiccommunity) - 1;
snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen);
tot_len += 1 + thl->comlenlen + thl->comlen;
snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen);
snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen);
tot_len += 1 + thl->verlen + thl->verlenlen;
thl->seqlen = tot_len;
snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen);
tot_len += 1 + thl->seqlenlen;
return tot_len;
}
/**
* Sums varbind lengths from tail to head and
* annotates lengths in varbind for second encoding pass.
*
* @param root points to the root of the variable binding list
* @return the required lenght for encoding the variable bindings
*/
static u16_t
snmp_varbind_list_sum(struct snmp_varbind_root *root)
{
struct snmp_varbind *vb;
u32_t *uint_ptr;
s32_t *sint_ptr;
u16_t tot_len;
tot_len = 0;
vb = root->tail;
while ( vb != NULL )
{
/* encoded value lenght depends on type */
switch (vb->value_type)
{
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);
break;
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
uint_ptr = (u32_t*)vb->value;
snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
vb->vlen = vb->value_len;
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);
break;
default:
/* unsupported type */
vb->vlen = 0;
break;
};
/* encoding length of value length field */
snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen);
snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen);
snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen);
vb->seqlen = 1 + vb->vlenlen + vb->vlen;
vb->seqlen += 1 + vb->olenlen + vb->olen;
snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen);
/* varbind seq */
tot_len += 1 + vb->seqlenlen + vb->seqlen;
vb = vb->prev;
}
/* varbind-list seq */
root->seqlen = tot_len;
snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen);
tot_len += 1 + root->seqlenlen;
return tot_len;
}
/**
* Encodes response header from head to tail.
*/
static u16_t
snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p)
{
u16_t ofs;
ofs = 0;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen);
ofs += m_stat->rhl.seqlenlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen);
ofs += m_stat->rhl.verlenlen;
snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version);
ofs += m_stat->rhl.verlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen);
ofs += m_stat->rhl.comlenlen;
snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community);
ofs += m_stat->rhl.comlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen);
ofs += m_stat->rhl.pdulenlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen);
ofs += m_stat->rhl.ridlenlen;
snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid);
ofs += m_stat->rhl.ridlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen);
ofs += m_stat->rhl.errstatlenlen;
snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status);
ofs += m_stat->rhl.errstatlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen);
ofs += m_stat->rhl.erridxlenlen;
snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index);
ofs += m_stat->rhl.erridxlen;
return ofs;
}
/**
* Encodes trap header from head to tail.
*/
static u16_t
snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p)
{
u16_t ofs;
ofs = 0;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen);
ofs += m_trap->thl.seqlenlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen);
ofs += m_trap->thl.verlenlen;
snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version);
ofs += m_trap->thl.verlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen);
ofs += m_trap->thl.comlenlen;
snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]);
ofs += m_trap->thl.comlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen);
ofs += m_trap->thl.pdulenlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen);
ofs += m_trap->thl.eidlenlen;
snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]);
ofs += m_trap->thl.eidlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen);
ofs += m_trap->thl.aaddrlenlen;
snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]);
ofs += m_trap->thl.aaddrlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen);
ofs += m_trap->thl.gtrplenlen;
snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap);
ofs += m_trap->thl.gtrplen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen);
ofs += m_trap->thl.strplenlen;
snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap);
ofs += m_trap->thl.strplen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS));
ofs += 1;
snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen);
ofs += m_trap->thl.tslenlen;
snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts);
ofs += m_trap->thl.tslen;
return ofs;
}
/**
* Encodes varbind list from head to tail.
*/
static u16_t
snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)
{
struct snmp_varbind *vb;
s32_t *sint_ptr;
u32_t *uint_ptr;
u8_t *raw_ptr;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
ofs += 1;
snmp_asn1_enc_length(p, ofs, root->seqlen);
ofs += root->seqlenlen;
vb = root->head;
while ( vb != NULL )
{
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));
ofs += 1;
snmp_asn1_enc_length(p, ofs, vb->seqlen);
ofs += vb->seqlenlen;
snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));
ofs += 1;
snmp_asn1_enc_length(p, ofs, vb->olen);
ofs += vb->olenlen;
snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]);
ofs += vb->olen;
snmp_asn1_enc_type(p, ofs, vb->value_type);
ofs += 1;
snmp_asn1_enc_length(p, ofs, vb->vlen);
ofs += vb->vlenlen;
switch (vb->value_type)
{
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);
break;
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
uint_ptr = (u32_t*)vb->value;
snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
raw_ptr = (u8_t*)vb->value;
snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
break;
case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
sint_ptr = (s32_t*)vb->value;
snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);
break;
default:
/* unsupported type */
break;
};
ofs += vb->vlen;
vb = vb->next;
}
return ofs;
}
#endif /* LWIP_SNMP */

View File

@ -1,176 +0,0 @@
/**
* @file
* Statistics module
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */
#include "lwip/def.h"
#include "lwip/stats.h"
#include "lwip/mem.h"
#include <string.h>
struct stats_ lwip_stats;
void stats_init(void)
{
#ifdef LWIP_DEBUG
#if MEMP_STATS
const char * memp_names[] = {
#define LWIP_MEMPOOL(name,num,size,desc) desc,
#include "lwip/memp_std.h"
};
int i;
for (i = 0; i < MEMP_MAX; i++) {
lwip_stats.memp[i].name = memp_names[i];
}
#endif /* MEMP_STATS */
#if MEM_STATS
lwip_stats.mem.name = "MEM";
#endif /* MEM_STATS */
#endif /* LWIP_DEBUG */
}
#if LWIP_STATS_DISPLAY
void
stats_display_proto(struct stats_proto *proto, const char *name)
{
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));
LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv));
LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));
LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop));
LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr));
LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr));
LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr));
LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr));
LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr));
LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr));
LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err));
LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit));
}
#if IGMP_STATS
void
stats_display_igmp(struct stats_igmp *igmp)
{
LWIP_PLATFORM_DIAG(("\nIGMP\n\t"));
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit));
LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv));
LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop));
LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr));
LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));
LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr));
LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr));
LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1));
LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n", igmp->rx_group));
LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n", igmp->rx_general));
LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report));
LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join));
LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave));
LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report));
}
#endif /* IGMP_STATS */
#if MEM_STATS || MEMP_STATS
void
stats_display_mem(struct stats_mem *mem, const char *name)
{
LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name));
LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail));
LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used));
LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max));
LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err));
}
#if MEMP_STATS
void
stats_display_memp(struct stats_mem *mem, int index)
{
char * memp_names[] = {
#define LWIP_MEMPOOL(name,num,size,desc) desc,
#include "lwip/memp_std.h"
};
if(index < MEMP_MAX) {
stats_display_mem(mem, memp_names[index]);
}
}
#endif /* MEMP_STATS */
#endif /* MEM_STATS || MEMP_STATS */
#if SYS_STATS
void
stats_display_sys(struct stats_sys *sys)
{
LWIP_PLATFORM_DIAG(("\nSYS\n\t"));
LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used));
LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max));
LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err));
LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used));
LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max));
LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err));
LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used));
LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max));
LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err));
}
#endif /* SYS_STATS */
void
stats_display(void)
{
s16_t i;
LINK_STATS_DISPLAY();
ETHARP_STATS_DISPLAY();
IPFRAG_STATS_DISPLAY();
IP_STATS_DISPLAY();
IGMP_STATS_DISPLAY();
ICMP_STATS_DISPLAY();
UDP_STATS_DISPLAY();
TCP_STATS_DISPLAY();
MEM_STATS_DISPLAY();
for (i = 0; i < MEMP_MAX; i++) {
MEMP_STATS_DISPLAY(i);
}
SYS_STATS_DISPLAY();
}
#endif /* LWIP_STATS_DISPLAY */
#endif /* LWIP_STATS */

View File

@ -1,68 +0,0 @@
/**
* @file
* lwIP Operating System abstraction
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/sys.h"
/* Most of the functions defined in sys.h must be implemented in the
* architecture-dependent file sys_arch.c */
#if !NO_SYS
#ifndef sys_msleep
/**
* Sleep for some ms. Timeouts are NOT processed while sleeping.
*
* @param ms number of milliseconds to sleep
*/
void
sys_msleep(u32_t ms)
{
if (ms > 0) {
sys_sem_t delaysem;
err_t err = sys_sem_new(&delaysem, 0);
if (err == ERR_OK) {
sys_arch_sem_wait(&delaysem, ms);
sys_sem_free(&delaysem);
}
}
}
#endif /* sys_msleep */
#endif /* !NO_SYS */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,487 +0,0 @@
/**
* @file
* Stack-internal timers implementation.
* This file includes timer callbacks for stack-internal timers as well as
* functions to set up or stop timers and check for expired timers.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
* Simon Goldschmidt
*
*/
#include "lwip/opt.h"
#include "lwip/timers.h"
#include "lwip/tcp_impl.h"
#if LWIP_TIMERS
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/tcpip.h"
#include "lwip/ip_frag.h"
#include "netif/etharp.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
#include "lwip/sys.h"
#include "lwip/pbuf.h"
/** The one and only timeout list */
static struct sys_timeo *next_timeout;
#if NO_SYS
static u32_t timeouts_last_time;
#endif /* NO_SYS */
#if LWIP_TCP
/** global variable that shows if the tcp timer is currently scheduled or not */
static int tcpip_tcp_timer_active;
/**
* Timer callback function that calls tcp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
tcpip_tcp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
/* call TCP timer handler */
tcp_tmr();
/* timer still needed? */
if (tcp_active_pcbs || tcp_tw_pcbs) {
/* restart timer */
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
} else {
/* disable timer */
tcpip_tcp_timer_active = 0;
}
}
/**
* Called from TCP_REG when registering a new PCB:
* the reason is to have the TCP timer only running when
* there are active (or time-wait) PCBs.
*/
void
tcp_timer_needed(void)
{
/* timer is off but needed again? */
if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
/* enable and start timer */
tcpip_tcp_timer_active = 1;
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
}
}
#endif /* LWIP_TCP */
#if IP_REASSEMBLY
/**
* Timer callback function that calls ip_reass_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
ip_reass_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n"));
ip_reass_tmr();
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
}
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
/**
* Timer callback function that calls etharp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
arp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n"));
etharp_tmr();
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
}
#endif /* LWIP_ARP */
#if LWIP_DHCP
/**
* Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_coarse(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
dhcp_coarse_tmr();
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
}
/**
* Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_fine(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
dhcp_fine_tmr();
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
}
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/**
* Timer callback function that calls autoip_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
autoip_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n"));
autoip_tmr();
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
}
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
/**
* Timer callback function that calls igmp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
igmp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n"));
igmp_tmr();
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
}
#endif /* LWIP_IGMP */
#if LWIP_DNS
/**
* Timer callback function that calls dns_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dns_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n"));
dns_tmr();
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
}
#endif /* LWIP_DNS */
/** Initialize this module */
void sys_timeouts_init(void)
{
#if IP_REASSEMBLY
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
#endif /* LWIP_ARP */
#if LWIP_DHCP
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
#endif /* LWIP_IGMP */
#if LWIP_DNS
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
#endif /* LWIP_DNS */
#if NO_SYS
/* Initialise timestamp for sys_check_timeouts */
timeouts_last_time = sys_now();
#endif
}
/**
* Create a one-shot timer (aka timeout). Timeouts are processed in the
* following cases:
* - while waiting for a message using sys_timeouts_mbox_fetch()
* - by calling sys_check_timeouts() (NO_SYS==1 only)
*
* @param msecs time in milliseconds after that the timer should expire
* @param handler callback function to call when msecs have elapsed
* @param arg argument to pass to the callback function
*/
#if LWIP_DEBUG_TIMERNAMES
void
sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)
#else /* LWIP_DEBUG_TIMERNAMES */
void
sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
#endif /* LWIP_DEBUG_TIMERNAMES */
{
struct sys_timeo *timeout, *t;
timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);
if (timeout == NULL) {
LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL);
return;
}
timeout->next = NULL;
timeout->h = handler;
timeout->arg = arg;
timeout->time = msecs;
#if LWIP_DEBUG_TIMERNAMES
timeout->handler_name = handler_name;
LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n",
(void *)timeout, msecs, handler_name, (void *)arg));
#endif /* LWIP_DEBUG_TIMERNAMES */
if (next_timeout == NULL) {
next_timeout = timeout;
return;
}
if (next_timeout->time > msecs) {
next_timeout->time -= msecs;
timeout->next = next_timeout;
next_timeout = timeout;
} else {
for(t = next_timeout; t != NULL; t = t->next) {
timeout->time -= t->time;
if (t->next == NULL || t->next->time > timeout->time) {
if (t->next != NULL) {
t->next->time -= timeout->time;
}
timeout->next = t->next;
t->next = timeout;
break;
}
}
}
}
/**
* Go through timeout list (for this task only) and remove the first matching
* entry, even though the timeout has not triggered yet.
*
* @note This function only works as expected if there is only one timeout
* calling 'handler' in the list of timeouts.
*
* @param handler callback function that would be called by the timeout
* @param arg callback argument that would be passed to handler
*/
void
sys_untimeout(sys_timeout_handler handler, void *arg)
{
struct sys_timeo *prev_t, *t;
if (next_timeout == NULL) {
return;
}
for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
if ((t->h == handler) && (t->arg == arg)) {
/* We have a match */
/* Unlink from previous in list */
if (prev_t == NULL) {
next_timeout = t->next;
} else {
prev_t->next = t->next;
}
/* If not the last one, add time of this one back to next */
if (t->next != NULL) {
t->next->time += t->time;
}
memp_free(MEMP_SYS_TIMEOUT, t);
return;
}
}
return;
}
#if NO_SYS
/** Handle timeouts for NO_SYS==1 (i.e. without using
* tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
* handler functions when timeouts expire.
*
* Must be called periodically from your main loop.
*/
void
sys_check_timeouts(void)
{
if (next_timeout) {
struct sys_timeo *tmptimeout;
u32_t diff;
sys_timeout_handler handler;
void *arg;
u8_t had_one;
u32_t now;
now = sys_now();
/* this cares for wraparounds */
diff = now - timeouts_last_time;
do
{
#if PBUF_POOL_FREE_OOSEQ
PBUF_CHECK_FREE_OOSEQ();
#endif /* PBUF_POOL_FREE_OOSEQ */
had_one = 0;
tmptimeout = next_timeout;
if (tmptimeout && (tmptimeout->time <= diff)) {
/* timeout has expired */
had_one = 1;
timeouts_last_time = now;
diff -= tmptimeout->time;
next_timeout = tmptimeout->next;
handler = tmptimeout->h;
arg = tmptimeout->arg;
#if LWIP_DEBUG_TIMERNAMES
if (handler != NULL) {
LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
tmptimeout->handler_name, arg));
}
#endif /* LWIP_DEBUG_TIMERNAMES */
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (handler != NULL) {
handler(arg);
}
}
/* repeat until all expired timers have been called */
}while(had_one);
}
}
/** Set back the timestamp of the last call to sys_check_timeouts()
* This is necessary if sys_check_timeouts() hasn't been called for a long
* time (e.g. while saving energy) to prevent all timer functions of that
* period being called.
*/
void
sys_restart_timeouts(void)
{
timeouts_last_time = sys_now();
}
#else /* NO_SYS */
/**
* Wait (forever) for a message to arrive in an mbox.
* While waiting, timeouts are processed.
*
* @param mbox the mbox to fetch the message from
* @param msg the place to store the message
*/
void
sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
{
u32_t time_needed;
struct sys_timeo *tmptimeout;
sys_timeout_handler handler;
void *arg;
again:
if (!next_timeout) {
time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
} else {
if (next_timeout->time > 0) {
time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);
} else {
time_needed = SYS_ARCH_TIMEOUT;
}
if (time_needed == SYS_ARCH_TIMEOUT) {
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
could be fetched. We should now call the timeout handler and
deallocate the memory allocated for the timeout. */
tmptimeout = next_timeout;
next_timeout = tmptimeout->next;
handler = tmptimeout->h;
arg = tmptimeout->arg;
#if LWIP_DEBUG_TIMERNAMES
if (handler != NULL) {
LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n",
tmptimeout->handler_name, arg));
}
#endif /* LWIP_DEBUG_TIMERNAMES */
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (handler != NULL) {
/* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
timeout handler function. */
LOCK_TCPIP_CORE();
handler(arg);
UNLOCK_TCPIP_CORE();
}
LWIP_TCPIP_THREAD_ALIVE();
/* We try again to fetch a message from the mbox. */
goto again;
} else {
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
occured. The time variable is set to the number of
milliseconds we waited for the message. */
if (time_needed < next_timeout->time) {
next_timeout->time -= time_needed;
} else {
next_timeout->time = 0;
}
}
}
}
#endif /* NO_SYS */
#else /* LWIP_TIMERS */
/* Satisfy the TCP code which calls this function */
void
tcp_timer_needed(void)
{
}
#endif /* LWIP_TIMERS */

File diff suppressed because it is too large Load Diff

View File

@ -1,118 +0,0 @@
/**
* @file
*
* AutoIP Automatic LinkLocal IP Configuration
*/
/*
*
* Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* Author: Dominik Spies <kontakt@dspies.de>
*
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
* with RFC 3927.
*
*
* Please coordinate changes and requests with Dominik Spies
* <kontakt@dspies.de>
*/
#ifndef __LWIP_AUTOIP_H__
#define __LWIP_AUTOIP_H__
#include "lwip/opt.h"
#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
#include "lwip/netif.h"
#include "lwip/udp.h"
#include "netif/etharp.h"
#ifdef __cplusplus
extern "C" {
#endif
/* AutoIP Timing */
#define AUTOIP_TMR_INTERVAL 100
#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL)
/* RFC 3927 Constants */
#define PROBE_WAIT 1 /* second (initial random delay) */
#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */
#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */
#define PROBE_NUM 3 /* (number of probe packets) */
#define ANNOUNCE_NUM 2 /* (number of announcement packets) */
#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */
#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */
#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */
#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */
#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */
/* AutoIP client states */
#define AUTOIP_STATE_OFF 0
#define AUTOIP_STATE_PROBING 1
#define AUTOIP_STATE_ANNOUNCING 2
#define AUTOIP_STATE_BOUND 3
struct autoip
{
ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */
u8_t state; /* current AutoIP state machine state */
u8_t sent_num; /* sent number of probes or announces, dependent on state */
u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */
u8_t lastconflict; /* ticks until a conflict can be solved by defending */
u8_t tried_llipaddr; /* total number of probed/used Link Local IP-Addresses */
};
#define autoip_init() /* Compatibility define, no init needed. */
/** Set a struct autoip allocated by the application to work with */
void autoip_set_struct(struct netif *netif, struct autoip *autoip);
/** Start AutoIP client */
err_t autoip_start(struct netif *netif);
/** Stop AutoIP client */
err_t autoip_stop(struct netif *netif);
/** Handles every incoming ARP Packet, called by etharp_arp_input */
void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr);
/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */
void autoip_tmr(void);
/** Handle a possible change in the network configuration */
void autoip_network_changed(struct netif *netif);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_AUTOIP */
#endif /* __LWIP_AUTOIP_H__ */

View File

@ -1,111 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_ICMP_H__
#define __LWIP_ICMP_H__
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ICMP_ER 0 /* echo reply */
#define ICMP_DUR 3 /* destination unreachable */
#define ICMP_SQ 4 /* source quench */
#define ICMP_RD 5 /* redirect */
#define ICMP_ECHO 8 /* echo */
#define ICMP_TE 11 /* time exceeded */
#define ICMP_PP 12 /* parameter problem */
#define ICMP_TS 13 /* timestamp */
#define ICMP_TSR 14 /* timestamp reply */
#define ICMP_IRQ 15 /* information request */
#define ICMP_IR 16 /* information reply */
enum icmp_dur_type {
ICMP_DUR_NET = 0, /* net unreachable */
ICMP_DUR_HOST = 1, /* host unreachable */
ICMP_DUR_PROTO = 2, /* protocol unreachable */
ICMP_DUR_PORT = 3, /* port unreachable */
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
ICMP_DUR_SR = 5 /* source route failed */
};
enum icmp_te_type {
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
};
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
/** This is the standard ICMP header only that the u32_t data
* is splitted to two u16_t like ICMP echo needs it.
* This header is also used for other ICMP types that do not
* use the data part.
*/
PACK_STRUCT_BEGIN
struct icmp_echo_hdr {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u16_t seqno);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define ICMPH_TYPE(hdr) ((hdr)->type)
#define ICMPH_CODE(hdr) ((hdr)->code)
/** Combines type and code to an u16_t */
#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t))
#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c))
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
void icmp_input(struct pbuf *p, struct netif *inp);
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
#endif /* LWIP_ICMP */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_ICMP_H__ */

View File

@ -1,106 +0,0 @@
/*
* Copyright (c) 2002 CITEL Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is a contribution to the lwIP TCP/IP stack.
* The Swedish Institute of Computer Science and Adam Dunkels
* are specifically granted permission to redistribute this
* source code.
*/
#ifndef __LWIP_IGMP_H__
#define __LWIP_IGMP_H__
#include "lwip/opt.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/pbuf.h"
#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
#ifdef __cplusplus
extern "C" {
#endif
/* IGMP timer */
#define IGMP_TMR_INTERVAL 100 /* Milliseconds */
#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL)
#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL)
/* MAC Filter Actions, these are passed to a netif's
* igmp_mac_filter callback function. */
#define IGMP_DEL_MAC_FILTER 0
#define IGMP_ADD_MAC_FILTER 1
/**
* igmp group structure - there is
* a list of groups for each interface
* these should really be linked from the interface, but
* if we keep them separate we will not affect the lwip original code
* too much
*
* There will be a group for the all systems group address but this
* will not run the state machine as it is used to kick off reports
* from all the other groups
*/
struct igmp_group {
/** next link */
struct igmp_group *next;
/** interface on which the group is active */
struct netif *netif;
/** multicast address */
ip_addr_t group_address;
/** signifies we were the last person to report */
u8_t last_reporter_flag;
/** current state of the group */
u8_t group_state;
/** timer for reporting, negative is OFF */
u16_t timer;
/** counter of simultaneous uses */
u8_t use;
};
/* Prototypes */
void igmp_init(void);
err_t igmp_start(struct netif *netif);
err_t igmp_stop(struct netif *netif);
void igmp_report_groups(struct netif *netif);
struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr);
void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest);
err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
void igmp_tmr(void);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IGMP */
#endif /* __LWIP_IGMP_H__ */

View File

@ -1,107 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_INET_H__
#define __LWIP_INET_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#ifdef __cplusplus
extern "C" {
#endif
/** For compatibility with BSD code */
struct in_addr {
u32_t s_addr;
};
/** 255.255.255.255 */
#define INADDR_NONE IPADDR_NONE
/** 127.0.0.1 */
#define INADDR_LOOPBACK IPADDR_LOOPBACK
/** 0.0.0.0 */
#define INADDR_ANY IPADDR_ANY
/** 255.255.255.255 */
#define INADDR_BROADCAST IPADDR_BROADCAST
/* Definitions of the bits in an Internet address integer.
On subnets, host and network parts are found according to
the subnet mask, not these masks. */
#define IN_CLASSA(a) IP_CLASSA(a)
#define IN_CLASSA_NET IP_CLASSA_NET
#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT
#define IN_CLASSA_HOST IP_CLASSA_HOST
#define IN_CLASSA_MAX IP_CLASSA_MAX
#define IN_CLASSB(b) IP_CLASSB(b)
#define IN_CLASSB_NET IP_CLASSB_NET
#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT
#define IN_CLASSB_HOST IP_CLASSB_HOST
#define IN_CLASSB_MAX IP_CLASSB_MAX
#define IN_CLASSC(c) IP_CLASSC(c)
#define IN_CLASSC_NET IP_CLASSC_NET
#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT
#define IN_CLASSC_HOST IP_CLASSC_HOST
#define IN_CLASSC_MAX IP_CLASSC_MAX
#define IN_CLASSD(d) IP_CLASSD(d)
#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */
#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */
#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */
#define IN_CLASSD_MAX IP_CLASSD_MAX
#define IN_MULTICAST(a) IP_MULTICAST(a)
#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a)
#define IN_BADCLASS(a) IP_BADCLASS(a)
#define IN_LOOPBACKNET IP_LOOPBACKNET
#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr))
#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr))
/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */
#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr))
/* directly map this to the lwip internal functions */
#define inet_addr(cp) ipaddr_addr(cp)
#define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr)
#define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr))
#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen)
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_INET_H__ */

View File

@ -1,90 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_INET_CHKSUM_H__
#define __LWIP_INET_CHKSUM_H__
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
/** Swap the bytes in an u16_t: much like htons() for little-endian */
#ifndef SWAP_BYTES_IN_WORD
#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
/* little endian and PLATFORM_BYTESWAP defined */
#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */
/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8)
#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/
#endif /* SWAP_BYTES_IN_WORD */
/** Split an u32_t in two u16_ts and add them up */
#ifndef FOLD_U32T
#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL))
#endif
#if LWIP_CHECKSUM_ON_COPY
/** Function-like macro: same as MEMCPY but returns the checksum of copied data
as u16_t */
#ifndef LWIP_CHKSUM_COPY
#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len)
#ifndef LWIP_CHKSUM_COPY_ALGORITHM
#define LWIP_CHKSUM_COPY_ALGORITHM 1
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
#endif /* LWIP_CHKSUM_COPY */
#else /* LWIP_CHECKSUM_ON_COPY */
#define LWIP_CHKSUM_COPY_ALGORITHM 0
#endif /* LWIP_CHECKSUM_ON_COPY */
#ifdef __cplusplus
extern "C" {
#endif
u16_t inet_chksum(void *dataptr, u16_t len);
u16_t inet_chksum_pbuf(struct pbuf *p);
u16_t inet_chksum_pseudo(struct pbuf *p,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len);
u16_t inet_chksum_pseudo_partial(struct pbuf *p,
ip_addr_t *src, ip_addr_t *dest,
u8_t proto, u16_t proto_len, u16_t chksum_len);
#if LWIP_CHKSUM_COPY_ALGORITHM
u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len);
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_INET_H__ */

View File

@ -1,223 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_H__
#define __LWIP_IP_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Currently, the function ip_output_if_opt() is only used with IGMP */
#define IP_OPTIONS_SEND LWIP_IGMP
#define IP_HLEN 20
#define IP_PROTO_ICMP 1
#define IP_PROTO_IGMP 2
#define IP_PROTO_UDP 17
#define IP_PROTO_UDPLITE 136
#define IP_PROTO_TCP 6
/* This is passed as the destination address to ip_output_if (not
to ip_output), meaning that an IP header already is constructed
in the pbuf. This is used when TCP retransmits. */
#ifdef IP_HDRINCL
#undef IP_HDRINCL
#endif /* IP_HDRINCL */
#define IP_HDRINCL NULL
#if LWIP_NETIF_HWADDRHINT
#define IP_PCB_ADDRHINT ;u8_t addr_hint
#else
#define IP_PCB_ADDRHINT
#endif /* LWIP_NETIF_HWADDRHINT */
/* This is the common part of all PCB types. It needs to be at the
beginning of a PCB type definition. It is located here so that
changes to this common part are made in one location instead of
having to change all PCB structs. */
#define IP_PCB \
/* ip addresses in network byte order */ \
ip_addr_t local_ip; \
ip_addr_t remote_ip; \
/* Socket options */ \
u8_t so_options; \
/* Type Of Service */ \
u8_t tos; \
/* Time To Live */ \
u8_t ttl \
/* link layer address resolution hint */ \
IP_PCB_ADDRHINT
struct ip_pcb {
/* Common members of all PCB types */
IP_PCB;
};
/*
* Option flags per-socket. These are the same like SO_XXX.
*/
/*#define SOF_DEBUG 0x01U Unimplemented: turn on debugging info recording */
#define SOF_ACCEPTCONN 0x02U /* socket has had listen() */
#define SOF_REUSEADDR 0x04U /* allow local address reuse */
#define SOF_KEEPALIVE 0x08U /* keep connections alive */
/*#define SOF_DONTROUTE 0x10U Unimplemented: just use interface addresses */
#define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
/*#define SOF_USELOOPBACK 0x40U Unimplemented: bypass hardware when possible */
#define SOF_LINGER 0x80U /* linger on close if data present */
/*#define SOF_OOBINLINE 0x0100U Unimplemented: leave received OOB data in line */
/*#define SOF_REUSEPORT 0x0200U Unimplemented: allow local address & port reuse */
/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */
#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_hdr {
/* version / header length */
PACK_STRUCT_FIELD(u8_t _v_hl);
/* type of service */
PACK_STRUCT_FIELD(u8_t _tos);
/* total length */
PACK_STRUCT_FIELD(u16_t _len);
/* identification */
PACK_STRUCT_FIELD(u16_t _id);
/* fragment offset field */
PACK_STRUCT_FIELD(u16_t _offset);
#define IP_RF 0x8000U /* reserved fragment flag */
#define IP_DF 0x4000U /* dont fragment flag */
#define IP_MF 0x2000U /* more fragments flag */
#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */
/* time to live */
PACK_STRUCT_FIELD(u8_t _ttl);
/* protocol*/
PACK_STRUCT_FIELD(u8_t _proto);
/* checksum */
PACK_STRUCT_FIELD(u16_t _chksum);
/* source and destination IP addresses */
PACK_STRUCT_FIELD(ip_addr_p_t src);
PACK_STRUCT_FIELD(ip_addr_p_t dest);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define IPH_V(hdr) ((hdr)->_v_hl >> 4)
#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f)
#define IPH_TOS(hdr) ((hdr)->_tos)
#define IPH_LEN(hdr) ((hdr)->_len)
#define IPH_ID(hdr) ((hdr)->_id)
#define IPH_OFFSET(hdr) ((hdr)->_offset)
#define IPH_TTL(hdr) ((hdr)->_ttl)
#define IPH_PROTO(hdr) ((hdr)->_proto)
#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (((v) << 4) | (hl))
#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos)
#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl)
#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto)
#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
/** The interface that provided the packet for the current callback invocation. */
extern struct netif *current_netif;
/** Header of the input packet currently being processed. */
extern const struct ip_hdr *current_header;
/** Source IP address of current_header */
extern ip_addr_t current_iphdr_src;
/** Destination IP address of current_header */
extern ip_addr_t current_iphdr_dest;
#define ip_init() /* Compatibility define, not init needed. */
struct netif *ip_route(ip_addr_t *dest);
err_t ip_input(struct pbuf *p, struct netif *inp);
err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto);
err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto,
struct netif *netif);
#if LWIP_NETIF_HWADDRHINT
err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT */
#if IP_OPTIONS_SEND
err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
u16_t optlen);
#endif /* IP_OPTIONS_SEND */
/** Get the interface that received the current packet.
* This function must only be called from a receive callback (udp_recv,
* raw_recv, tcp_accept). It will return NULL otherwise. */
#define ip_current_netif() (current_netif)
/** Get the IP header of the current packet.
* This function must only be called from a receive callback (udp_recv,
* raw_recv, tcp_accept). It will return NULL otherwise. */
#define ip_current_header() (current_header)
/** Source IP address of current_header */
#define ip_current_src_addr() (&current_iphdr_src)
/** Destination IP address of current_header */
#define ip_current_dest_addr() (&current_iphdr_dest)
/** Gets an IP pcb option (SOF_* flags) */
#define ip_get_option(pcb, opt) ((pcb)->so_options & (opt))
/** Sets an IP pcb option (SOF_* flags) */
#define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt))
/** Resets an IP pcb option (SOF_* flags) */
#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt))
#if IP_DEBUG
void ip_debug_print(struct pbuf *p);
#else
#define ip_debug_print(p)
#endif /* IP_DEBUG */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP_H__ */

View File

@ -1,244 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_ADDR_H__
#define __LWIP_IP_ADDR_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#ifdef __cplusplus
extern "C" {
#endif
/* This is the aligned version of ip_addr_t,
used as local variable, on the stack, etc. */
struct ip_addr {
u32_t addr;
};
/* This is the packed version of ip_addr_t,
used in network headers that are itself packed */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr_packed {
PACK_STRUCT_FIELD(u32_t addr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** ip_addr_t uses a struct for convenience only, so that the same defines can
* operate both on ip_addr_t as well as on ip_addr_p_t. */
typedef struct ip_addr ip_addr_t;
typedef struct ip_addr_packed ip_addr_p_t;
/*
* struct ipaddr2 is used in the definition of the ARP packet format in
* order to support compilers that don't have structure packing.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr2 {
PACK_STRUCT_FIELD(u16_t addrw[2]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* Forward declaration to not include netif.h */
struct netif;
extern const ip_addr_t ip_addr_any;
extern const ip_addr_t ip_addr_broadcast;
/** IP_ADDR_ can be used as a fixed IP address
* for the wildcard and the broadcast address
*/
#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any)
#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast)
/** 255.255.255.255 */
#define IPADDR_NONE ((u32_t)0xffffffffUL)
/** 127.0.0.1 */
#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL)
/** 0.0.0.0 */
#define IPADDR_ANY ((u32_t)0x00000000UL)
/** 255.255.255.255 */
#define IPADDR_BROADCAST ((u32_t)0xffffffffUL)
/* Definitions of the bits in an Internet address integer.
On subnets, host and network parts are found according to
the subnet mask, not these masks. */
#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
#define IP_CLASSA_NET 0xff000000
#define IP_CLASSA_NSHIFT 24
#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET)
#define IP_CLASSA_MAX 128
#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
#define IP_CLASSB_NET 0xffff0000
#define IP_CLASSB_NSHIFT 16
#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET)
#define IP_CLASSB_MAX 65536
#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
#define IP_CLASSC_NET 0xffffff00
#define IP_CLASSC_NSHIFT 8
#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET)
#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */
#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */
#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */
#define IP_MULTICAST(a) IP_CLASSD(a)
#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IP_LOOPBACKNET 127 /* official! */
#if BYTE_ORDER == BIG_ENDIAN
/** Set an IP address given by the four byte-parts */
#define IP4_ADDR(ipaddr, a,b,c,d) \
(ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \
((u32_t)((b) & 0xff) << 16) | \
((u32_t)((c) & 0xff) << 8) | \
(u32_t)((d) & 0xff)
#else
/** Set an IP address given by the four byte-parts.
Little-endian version that prevents the use of htonl. */
#define IP4_ADDR(ipaddr, a,b,c,d) \
(ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \
((u32_t)((c) & 0xff) << 16) | \
((u32_t)((b) & 0xff) << 8) | \
(u32_t)((a) & 0xff)
#endif
/** MEMCPY-like copying of IP addresses where addresses are known to be
* 16-bit-aligned if the port is correctly configured (so a port could define
* this to copying 2 u16_t's) - no NULL-pointer-checking needed. */
#ifndef IPADDR2_COPY
#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t))
#endif
/** Copy IP address - faster than ip_addr_set: no NULL check */
#define ip_addr_copy(dest, src) ((dest).addr = (src).addr)
/** Safely copy one IP address to another (src may be NULL) */
#define ip_addr_set(dest, src) ((dest)->addr = \
((src) == NULL ? 0 : \
(src)->addr))
/** Set complete address to zero */
#define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0)
/** Set address to IPADDR_ANY (no need for htonl()) */
#define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY)
/** Set address to loopback address */
#define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK))
/** Safely copy one IP address to another and change byte order
* from host- to network-order. */
#define ip_addr_set_hton(dest, src) ((dest)->addr = \
((src) == NULL ? 0:\
htonl((src)->addr)))
/** IPv4 only: set the IP address given as an u32_t */
#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32))
/** IPv4 only: get the IP address as an u32_t */
#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)
/** Get the network address by combining host address with netmask */
#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr))
/**
* Determine if two address are on the same network.
*
* @arg addr1 IP address 1
* @arg addr2 IP address 2
* @arg mask network identifier mask
* @return !0 if the network identifiers of both address match
*/
#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
(mask)->addr) == \
((addr2)->addr & \
(mask)->addr))
#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY)
#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif))
u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif);
#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr)
u8_t ip4_addr_netmask_valid(u32_t netmask);
#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL))
#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL))
#define ip_addr_debug_print(debug, ipaddr) \
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \
ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \
ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \
ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0))
/* Get one byte from the 4-byte address */
#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])
#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])
#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])
#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])
/* These are cast to u16_t, with the intent that they are often arguments
* to printf using the U16_F format from cc.h. */
#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))
#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))
#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))
#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))
/** For backwards compatibility */
#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr)
u32_t ipaddr_addr(const char *cp);
int ipaddr_aton(const char *cp, ip_addr_t *addr);
/** returns ptr to static buffer; not reentrant! */
char *ipaddr_ntoa(const ip_addr_t *addr);
char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen);
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP_ADDR_H__ */

View File

@ -1,88 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Jani Monoses <jani@iv.ro>
*
*/
#ifndef __LWIP_IP_FRAG_H__
#define __LWIP_IP_FRAG_H__
#include "lwip/opt.h"
#include "lwip/err.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/ip_addr.h"
#include "lwip/ip.h"
#ifdef __cplusplus
extern "C" {
#endif
#if IP_REASSEMBLY
/* The IP reassembly timer interval in milliseconds. */
#define IP_TMR_INTERVAL 1000
/* IP reassembly helper struct.
* This is exported because memp needs to know the size.
*/
struct ip_reassdata {
struct ip_reassdata *next;
struct pbuf *p;
struct ip_hdr iphdr;
u16_t datagram_len;
u8_t flags;
u8_t timer;
};
void ip_reass_init(void);
void ip_reass_tmr(void);
struct pbuf * ip_reass(struct pbuf *p);
#endif /* IP_REASSEMBLY */
#if IP_FRAG
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
/** A custom pbuf that holds a reference to another pbuf, which is freed
* when this custom pbuf is freed. This is used to create a custom PBUF_REF
* that points into the original pbuf. */
struct pbuf_custom_ref {
/** 'base class' */
struct pbuf_custom pc;
/** pointer to the original pbuf that is referenced */
struct pbuf *original;
};
#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest);
#endif /* IP_FRAG */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP_FRAG_H__ */

View File

@ -1,297 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_API_H__
#define __LWIP_API_H__
#include "lwip/opt.h"
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
#include <stddef.h> /* for size_t */
#include "lwip/netbuf.h"
#include "lwip/sys.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Throughout this file, IP addresses and port numbers are expected to be in
* the same byte order as in the corresponding pcb.
*/
/* Flags for netconn_write (u8_t) */
#define NETCONN_NOFLAG 0x00
#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */
#define NETCONN_COPY 0x01
#define NETCONN_MORE 0x02
#define NETCONN_DONTBLOCK 0x04
/* Flags for struct netconn.flags (u8_t) */
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores whether to wake up the original application task
if data couldn't be sent in the first try. */
#define NETCONN_FLAG_WRITE_DELAYED 0x01
/** Should this netconn avoid blocking? */
#define NETCONN_FLAG_NON_BLOCKING 0x02
/** Was the last connect action a non-blocking one? */
#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04
/** If this is set, a TCP netconn must call netconn_recved() to update
the TCP receive window (done automatically if not set). */
#define NETCONN_FLAG_NO_AUTO_RECVED 0x08
/** If a nonblocking write has been rejected before, poll_tcp needs to
check if the netconn is writable again */
#define NETCONN_FLAG_CHECK_WRITESPACE 0x10
/* Helpers to process several netconn_types by the same code */
#define NETCONNTYPE_GROUP(t) (t&0xF0)
#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)
/** Protocol family and type of the netconn */
enum netconn_type {
NETCONN_INVALID = 0,
/* NETCONN_TCP Group */
NETCONN_TCP = 0x10,
/* NETCONN_UDP Group */
NETCONN_UDP = 0x20,
NETCONN_UDPLITE = 0x21,
NETCONN_UDPNOCHKSUM= 0x22,
/* NETCONN_RAW Group */
NETCONN_RAW = 0x40
};
/** Current state of the netconn. Non-TCP netconns are always
* in state NETCONN_NONE! */
enum netconn_state {
NETCONN_NONE,
NETCONN_WRITE,
NETCONN_LISTEN,
NETCONN_CONNECT,
NETCONN_CLOSE
};
/** Use to inform the callback function about changes */
enum netconn_evt {
NETCONN_EVT_RCVPLUS,
NETCONN_EVT_RCVMINUS,
NETCONN_EVT_SENDPLUS,
NETCONN_EVT_SENDMINUS,
NETCONN_EVT_ERROR
};
#if LWIP_IGMP
/** Used for netconn_join_leave_group() */
enum netconn_igmp {
NETCONN_JOIN,
NETCONN_LEAVE
};
#endif /* LWIP_IGMP */
/* forward-declare some structs to avoid to include their headers */
struct ip_pcb;
struct tcp_pcb;
struct udp_pcb;
struct raw_pcb;
struct netconn;
struct api_msg_msg;
/** A callback prototype to inform about events for a netconn */
typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len);
/** A netconn descriptor */
struct netconn {
/** type of the netconn (TCP, UDP or RAW) */
enum netconn_type type;
/** current state of the netconn */
enum netconn_state state;
/** the lwIP internal protocol control block */
union {
struct ip_pcb *ip;
struct tcp_pcb *tcp;
struct udp_pcb *udp;
struct raw_pcb *raw;
} pcb;
/** the last error this netconn had */
err_t last_err;
/** sem that is used to synchroneously execute functions in the core context */
sys_sem_t op_completed;
/** mbox where received packets are stored until they are fetched
by the netconn application thread (can grow quite big) */
sys_mbox_t recvmbox;
#if LWIP_TCP
/** mbox where new connections are stored until processed
by the application thread */
sys_mbox_t acceptmbox;
#endif /* LWIP_TCP */
/** only used for socket layer */
#if LWIP_SOCKET
int socket;
#endif /* LWIP_SOCKET */
#if LWIP_SO_SNDTIMEO
/** timeout to wait for sending data (which means enqueueing data for sending
in internal buffers) */
s32_t send_timeout;
#endif /* LWIP_SO_RCVTIMEO */
#if LWIP_SO_RCVTIMEO
/** timeout to wait for new data to be received
(or connections to arrive for listening netconns) */
int recv_timeout;
#endif /* LWIP_SO_RCVTIMEO */
#if LWIP_SO_RCVBUF
/** maximum amount of bytes queued in recvmbox
not used for TCP: adjust TCP_WND instead! */
int recv_bufsize;
/** number of bytes currently in recvmbox to be received,
tested against recv_bufsize to limit bytes on recvmbox
for UDP and RAW, used for FIONREAD */
s16_t recv_avail;
#endif /* LWIP_SO_RCVBUF */
/** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */
u8_t flags;
#if LWIP_TCP
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores how much is already sent. */
size_t write_offset;
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores the message.
Also used during connect and close. */
struct api_msg_msg *current_msg;
#endif /* LWIP_TCP */
/** A callback function that is informed about events for this netconn */
netconn_callback callback;
};
/** Register an Network connection event */
#define API_EVENT(c,e,l) if (c->callback) { \
(*c->callback)(c, e, l); \
}
/** Set conn->last_err to err but don't overwrite fatal errors */
#define NETCONN_SET_SAFE_ERR(conn, err) do { \
SYS_ARCH_DECL_PROTECT(lev); \
SYS_ARCH_PROTECT(lev); \
if (!ERR_IS_FATAL((conn)->last_err)) { \
(conn)->last_err = err; \
} \
SYS_ARCH_UNPROTECT(lev); \
} while(0);
/* Network connection functions: */
#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL)
#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)
struct
netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
netconn_callback callback);
err_t netconn_delete(struct netconn *conn);
/** Get the type of a netconn (as enum netconn_type). */
#define netconn_type(conn) (conn->type)
err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr,
u16_t *port, u8_t local);
#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0)
#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1)
err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port);
err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port);
err_t netconn_disconnect (struct netconn *conn);
err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)
err_t netconn_accept(struct netconn *conn, struct netconn **new_conn);
err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf);
err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf);
void netconn_recved(struct netconn *conn, u32_t length);
err_t netconn_sendto(struct netconn *conn, struct netbuf *buf,
ip_addr_t *addr, u16_t port);
err_t netconn_send(struct netconn *conn, struct netbuf *buf);
err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
u8_t apiflags, size_t *bytes_written);
#define netconn_write(conn, dataptr, size, apiflags) \
netconn_write_partly(conn, dataptr, size, apiflags, NULL)
err_t netconn_close(struct netconn *conn);
err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx);
#if LWIP_IGMP
err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr,
ip_addr_t *netif_addr, enum netconn_igmp join_or_leave);
#endif /* LWIP_IGMP */
#if LWIP_DNS
err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
#endif /* LWIP_DNS */
#define netconn_err(conn) ((conn)->last_err)
#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
/** Set the blocking status of netconn calls (@todo: write/send is missing) */
#define netconn_set_nonblocking(conn, val) do { if(val) { \
(conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \
} else { \
(conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0)
/** Get the blocking status of netconn calls (@todo: write/send is missing) */
#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0)
/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
#define netconn_set_noautorecved(conn, val) do { if(val) { \
(conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \
} else { \
(conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0)
/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0)
#if LWIP_SO_SNDTIMEO
/** Set the send timeout in milliseconds */
#define netconn_set_sendtimeout(conn, timeout) ((conn)->send_timeout = (timeout))
/** Get the send timeout in milliseconds */
#define netconn_get_sendtimeout(conn) ((conn)->send_timeout)
#endif /* LWIP_SO_SNDTIMEO */
#if LWIP_SO_RCVTIMEO
/** Set the receive timeout in milliseconds */
#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout))
/** Get the receive timeout in milliseconds */
#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout)
#endif /* LWIP_SO_RCVTIMEO */
#if LWIP_SO_RCVBUF
/** Set the receive buffer in bytes */
#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize))
/** Get the receive buffer in bytes */
#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize)
#endif /* LWIP_SO_RCVBUF*/
#ifdef __cplusplus
}
#endif
#endif /* LWIP_NETCONN */
#endif /* __LWIP_API_H__ */

View File

@ -1,177 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_API_MSG_H__
#define __LWIP_API_MSG_H__
#include "lwip/opt.h"
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
#include <stddef.h> /* for size_t */
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/igmp.h"
#include "lwip/api.h"
#ifdef __cplusplus
extern "C" {
#endif
/* For the netconn API, these values are use as a bitmask! */
#define NETCONN_SHUT_RD 1
#define NETCONN_SHUT_WR 2
#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR)
/* IP addresses and port numbers are expected to be in
* the same byte order as in the corresponding pcb.
*/
/** This struct includes everything that is necessary to execute a function
for a netconn in another thread context (mainly used to process netconns
in the tcpip_thread context to be thread safe). */
struct api_msg_msg {
/** The netconn which to process - always needed: it includes the semaphore
which is used to block the application thread until the function finished. */
struct netconn *conn;
/** The return value of the function executed in tcpip_thread. */
err_t err;
/** Depending on the executed function, one of these union members is used */
union {
/** used for do_send */
struct netbuf *b;
/** used for do_newconn */
struct {
u8_t proto;
} n;
/** used for do_bind and do_connect */
struct {
ip_addr_t *ipaddr;
u16_t port;
} bc;
/** used for do_getaddr */
struct {
ip_addr_t *ipaddr;
u16_t *port;
u8_t local;
} ad;
/** used for do_write */
struct {
const void *dataptr;
size_t len;
u8_t apiflags;
#if LWIP_SO_SNDTIMEO
u32_t time_started;
#endif /* LWIP_SO_SNDTIMEO */
} w;
/** used for do_recv */
struct {
u32_t len;
} r;
/** used for do_close (/shutdown) */
struct {
u8_t shut;
} sd;
#if LWIP_IGMP
/** used for do_join_leave_group */
struct {
ip_addr_t *multiaddr;
ip_addr_t *netif_addr;
enum netconn_igmp join_or_leave;
} jl;
#endif /* LWIP_IGMP */
#if TCP_LISTEN_BACKLOG
struct {
u8_t backlog;
} lb;
#endif /* TCP_LISTEN_BACKLOG */
} msg;
};
/** This struct contains a function to execute in another thread context and
a struct api_msg_msg that serves as an argument for this function.
This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */
struct api_msg {
/** function to execute in tcpip_thread context */
void (* function)(struct api_msg_msg *msg);
/** arguments for this function */
struct api_msg_msg msg;
};
#if LWIP_DNS
/** As do_gethostbyname requires more arguments but doesn't require a netconn,
it has its own struct (to avoid struct api_msg getting bigger than necessary).
do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg
(see netconn_gethostbyname). */
struct dns_api_msg {
/** Hostname to query or dotted IP address string */
const char *name;
/** Rhe resolved address is stored here */
ip_addr_t *addr;
/** This semaphore is posted when the name is resolved, the application thread
should wait on it. */
sys_sem_t *sem;
/** Errors are given back here */
err_t *err;
};
#endif /* LWIP_DNS */
void do_newconn ( struct api_msg_msg *msg);
void do_delconn ( struct api_msg_msg *msg);
void do_bind ( struct api_msg_msg *msg);
void do_connect ( struct api_msg_msg *msg);
void do_disconnect ( struct api_msg_msg *msg);
void do_listen ( struct api_msg_msg *msg);
void do_send ( struct api_msg_msg *msg);
void do_recv ( struct api_msg_msg *msg);
void do_write ( struct api_msg_msg *msg);
void do_getaddr ( struct api_msg_msg *msg);
void do_close ( struct api_msg_msg *msg);
void do_shutdown ( struct api_msg_msg *msg);
#if LWIP_IGMP
void do_join_leave_group( struct api_msg_msg *msg);
#endif /* LWIP_IGMP */
#if LWIP_DNS
void do_gethostbyname(void *arg);
#endif /* LWIP_DNS */
struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback);
void netconn_free(struct netconn *conn);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_NETCONN */
#endif /* __LWIP_API_MSG_H__ */

View File

@ -1,217 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_ARCH_H__
#define __LWIP_ARCH_H__
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN 1234
#endif
#ifndef BIG_ENDIAN
#define BIG_ENDIAN 4321
#endif
#include "arch/cc.h"
/** Temporary: define format string for size_t if not defined in cc.h */
#ifndef SZT_F
#define SZT_F U32_F
#endif /* SZT_F */
/** Temporary upgrade helper: define format string for u8_t as hex if not
defined in cc.h */
#ifndef X8_F
#define X8_F "02x"
#endif /* X8_F */
#ifdef __cplusplus
extern "C" {
#endif
#ifndef PACK_STRUCT_BEGIN
#define PACK_STRUCT_BEGIN
#endif /* PACK_STRUCT_BEGIN */
#ifndef PACK_STRUCT_END
#define PACK_STRUCT_END
#endif /* PACK_STRUCT_END */
#ifndef PACK_STRUCT_FIELD
#define PACK_STRUCT_FIELD(x) x
#endif /* PACK_STRUCT_FIELD */
#ifndef LWIP_UNUSED_ARG
#define LWIP_UNUSED_ARG(x) (void)x
#endif /* LWIP_UNUSED_ARG */
#ifdef LWIP_PROVIDE_ERRNO
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Arg list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#ifndef errno
extern int errno;
#endif
#endif /* LWIP_PROVIDE_ERRNO */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_ARCH_H__ */

View File

@ -1,99 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_DEBUG_H__
#define __LWIP_DEBUG_H__
#include "lwip/arch.h"
#include "lwip/opt.h"
/** lower two bits indicate debug level
* - 0 all
* - 1 warning
* - 2 serious
* - 3 severe
*/
#define LWIP_DBG_LEVEL_ALL 0x00
#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */
#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */
#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */
#define LWIP_DBG_LEVEL_SEVERE 0x03
#define LWIP_DBG_MASK_LEVEL 0x03
/** flag for LWIP_DEBUGF to enable that debug message */
#define LWIP_DBG_ON 0x80U
/** flag for LWIP_DEBUGF to disable that debug message */
#define LWIP_DBG_OFF 0x00U
/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */
#define LWIP_DBG_TRACE 0x40U
/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */
#define LWIP_DBG_STATE 0x20U
/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */
#define LWIP_DBG_FRESH 0x10U
/** flag for LWIP_DEBUGF to halt after printing this debug message */
#define LWIP_DBG_HALT 0x08U
#ifndef LWIP_NOASSERT
#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \
LWIP_PLATFORM_ASSERT(message); } while(0)
#else /* LWIP_NOASSERT */
#define LWIP_ASSERT(message, assertion)
#endif /* LWIP_NOASSERT */
/** if "expression" isn't true, then print "message" and execute "handler" expression */
#ifndef LWIP_ERROR
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
LWIP_PLATFORM_ASSERT(message); handler;}} while(0)
#endif /* LWIP_ERROR */
#ifdef LWIP_DEBUG
/** print debug message only if debug message type is enabled...
* AND is of correct type AND is at least LWIP_DBG_LEVEL
*/
#define LWIP_DEBUGF(debug, message) do { \
if ( \
((debug) & LWIP_DBG_ON) && \
((debug) & LWIP_DBG_TYPES_ON) && \
((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
LWIP_PLATFORM_DIAG(message); \
if ((debug) & LWIP_DBG_HALT) { \
while(1); \
} \
} \
} while(0)
#else /* LWIP_DEBUG */
#define LWIP_DEBUGF(debug, message)
#endif /* LWIP_DEBUG */
#endif /* __LWIP_DEBUG_H__ */

View File

@ -1,123 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_DEF_H__
#define __LWIP_DEF_H__
/* arch.h might define NULL already */
#include "lwip/arch.h"
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y))
#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y))
#ifndef NULL
#define NULL ((void *)0)
#endif
/* Endianess-optimized shifting of two u8_t to create one u16_t */
#if BYTE_ORDER == LITTLE_ENDIAN
#define LWIP_MAKE_U16(a, b) ((a << 8) | b)
#else
#define LWIP_MAKE_U16(a, b) ((b << 8) | a)
#endif
#ifndef LWIP_PLATFORM_BYTESWAP
#define LWIP_PLATFORM_BYTESWAP 0
#endif
#ifndef LWIP_PREFIX_BYTEORDER_FUNCS
/* workaround for naming collisions on some platforms */
#ifdef htons
#undef htons
#endif /* htons */
#ifdef htonl
#undef htonl
#endif /* htonl */
#ifdef ntohs
#undef ntohs
#endif /* ntohs */
#ifdef ntohl
#undef ntohl
#endif /* ntohl */
#define htons(x) lwip_htons(x)
#define ntohs(x) lwip_ntohs(x)
#define htonl(x) lwip_htonl(x)
#define ntohl(x) lwip_ntohl(x)
#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */
#if BYTE_ORDER == BIG_ENDIAN
#define lwip_htons(x) (x)
#define lwip_ntohs(x) (x)
#define lwip_htonl(x) (x)
#define lwip_ntohl(x) (x)
#define PP_HTONS(x) (x)
#define PP_NTOHS(x) (x)
#define PP_HTONL(x) (x)
#define PP_NTOHL(x) (x)
#else /* BYTE_ORDER != BIG_ENDIAN */
#if LWIP_PLATFORM_BYTESWAP
#define lwip_htons(x) LWIP_PLATFORM_HTONS(x)
#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x)
#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x)
#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x)
#else /* LWIP_PLATFORM_BYTESWAP */
u16_t lwip_htons(u16_t x);
u16_t lwip_ntohs(u16_t x);
u32_t lwip_htonl(u32_t x);
u32_t lwip_ntohl(u32_t x);
#endif /* LWIP_PLATFORM_BYTESWAP */
/* These macros should be calculated by the preprocessor and are used
with compile-time constants only (so that there is no little-endian
overhead at runtime). */
#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
#define PP_NTOHS(x) PP_HTONS(x)
#define PP_HTONL(x) ((((x) & 0xff) << 24) | \
(((x) & 0xff00) << 8) | \
(((x) & 0xff0000UL) >> 8) | \
(((x) & 0xff000000UL) >> 24))
#define PP_NTOHL(x) PP_HTONL(x)
#endif /* BYTE_ORDER == BIG_ENDIAN */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_DEF_H__ */

View File

@ -1,242 +0,0 @@
/** @file
*/
#ifndef __LWIP_DHCP_H__
#define __LWIP_DHCP_H__
#include "lwip/opt.h"
#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */
#include "lwip/netif.h"
#include "lwip/udp.h"
#ifdef __cplusplus
extern "C" {
#endif
/** period (in seconds) of the application calling dhcp_coarse_tmr() */
#define DHCP_COARSE_TIMER_SECS 60
/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */
#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL)
/** period (in milliseconds) of the application calling dhcp_fine_tmr() */
#define DHCP_FINE_TIMER_MSECS 500
#define DHCP_CHADDR_LEN 16U
#define DHCP_SNAME_LEN 64U
#define DHCP_FILE_LEN 128U
struct dhcp
{
/** transaction identifier of last sent request */
u32_t xid;
/** our connection to the DHCP server */
struct udp_pcb *pcb;
/** incoming msg */
struct dhcp_msg *msg_in;
/** current DHCP state machine state */
u8_t state;
/** retries of current request */
u8_t tries;
#if LWIP_DHCP_AUTOIP_COOP
u8_t autoip_coop_state;
#endif
u8_t subnet_mask_given;
struct pbuf *p_out; /* pbuf of outcoming msg */
struct dhcp_msg *msg_out; /* outgoing msg */
u16_t options_out_len; /* outgoing msg options length */
u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */
u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */
u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */
ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */
ip_addr_t offered_ip_addr;
ip_addr_t offered_sn_mask;
ip_addr_t offered_gw_addr;
u32_t offered_t0_lease; /* lease period (in seconds) */
u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */
u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */
/* @todo: LWIP_DHCP_BOOTP_FILE configuration option?
integrate with possible TFTP-client for booting? */
#if LWIP_DHCP_BOOTP_FILE
ip_addr_t offered_si_addr;
char boot_file_name[DHCP_FILE_LEN];
#endif /* LWIP_DHCP_BOOTPFILE */
};
/* MUST be compiled with "pack structs" or equivalent! */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** minimum set of fields of any DHCP message */
struct dhcp_msg
{
PACK_STRUCT_FIELD(u8_t op);
PACK_STRUCT_FIELD(u8_t htype);
PACK_STRUCT_FIELD(u8_t hlen);
PACK_STRUCT_FIELD(u8_t hops);
PACK_STRUCT_FIELD(u32_t xid);
PACK_STRUCT_FIELD(u16_t secs);
PACK_STRUCT_FIELD(u16_t flags);
PACK_STRUCT_FIELD(ip_addr_p_t ciaddr);
PACK_STRUCT_FIELD(ip_addr_p_t yiaddr);
PACK_STRUCT_FIELD(ip_addr_p_t siaddr);
PACK_STRUCT_FIELD(ip_addr_p_t giaddr);
PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);
PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
PACK_STRUCT_FIELD(u32_t cookie);
#define DHCP_MIN_OPTIONS_LEN 68U
/** make sure user does not configure this too small */
#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))
# undef DHCP_OPTIONS_LEN
#endif
/** allow this to be configured in lwipopts.h, but not too small */
#if (!defined(DHCP_OPTIONS_LEN))
/** set this to be sufficient for your options in outgoing DHCP msgs */
# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN
#endif
PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp);
/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */
#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0)
void dhcp_cleanup(struct netif *netif);
/** start DHCP configuration */
err_t dhcp_start(struct netif *netif);
/** enforce early lease renewal (not needed normally)*/
err_t dhcp_renew(struct netif *netif);
/** release the DHCP lease, usually called before dhcp_stop()*/
err_t dhcp_release(struct netif *netif);
/** stop DHCP configuration */
void dhcp_stop(struct netif *netif);
/** inform server of our manual IP address */
void dhcp_inform(struct netif *netif);
/** Handle a possible change in the network configuration */
void dhcp_network_changed(struct netif *netif);
/** if enabled, check whether the offered IP address is not in use, using ARP */
#if DHCP_DOES_ARP_CHECK
void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr);
#endif
/** to be called every minute */
void dhcp_coarse_tmr(void);
/** to be called every half second */
void dhcp_fine_tmr(void);
/** DHCP message item offsets and length */
#define DHCP_OP_OFS 0
#define DHCP_HTYPE_OFS 1
#define DHCP_HLEN_OFS 2
#define DHCP_HOPS_OFS 3
#define DHCP_XID_OFS 4
#define DHCP_SECS_OFS 8
#define DHCP_FLAGS_OFS 10
#define DHCP_CIADDR_OFS 12
#define DHCP_YIADDR_OFS 16
#define DHCP_SIADDR_OFS 20
#define DHCP_GIADDR_OFS 24
#define DHCP_CHADDR_OFS 28
#define DHCP_SNAME_OFS 44
#define DHCP_FILE_OFS 108
#define DHCP_MSG_LEN 236
#define DHCP_COOKIE_OFS DHCP_MSG_LEN
#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4)
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_PORT 67
/** DHCP client states */
#define DHCP_OFF 0
#define DHCP_REQUESTING 1
#define DHCP_INIT 2
#define DHCP_REBOOTING 3
#define DHCP_REBINDING 4
#define DHCP_RENEWING 5
#define DHCP_SELECTING 6
#define DHCP_INFORMING 7
#define DHCP_CHECKING 8
#define DHCP_PERMANENT 9
#define DHCP_BOUND 10
/** not yet implemented #define DHCP_RELEASING 11 */
#define DHCP_BACKING_OFF 12
/** AUTOIP cooperatation flags */
#define DHCP_AUTOIP_COOP_STATE_OFF 0
#define DHCP_AUTOIP_COOP_STATE_ON 1
#define DHCP_BOOTREQUEST 1
#define DHCP_BOOTREPLY 2
/** DHCP message types */
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NAK 6
#define DHCP_RELEASE 7
#define DHCP_INFORM 8
/** DHCP hardware type, currently only ethernet is supported */
#define DHCP_HTYPE_ETH 1
#define DHCP_MAGIC_COOKIE 0x63825363UL
/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */
/** BootP options */
#define DHCP_OPTION_PAD 0
#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */
#define DHCP_OPTION_ROUTER 3
#define DHCP_OPTION_DNS_SERVER 6
#define DHCP_OPTION_HOSTNAME 12
#define DHCP_OPTION_IP_TTL 23
#define DHCP_OPTION_MTU 26
#define DHCP_OPTION_BROADCAST 28
#define DHCP_OPTION_TCP_TTL 37
#define DHCP_OPTION_END 255
/** DHCP options */
#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */
#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */
#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */
#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
#define DHCP_OPTION_MESSAGE_TYPE_LEN 1
#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */
#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */
#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */
#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2
#define DHCP_OPTION_T1 58 /* T1 renewal time */
#define DHCP_OPTION_T2 59 /* T2 rebinding time */
#define DHCP_OPTION_US 60
#define DHCP_OPTION_CLIENT_ID 61
#define DHCP_OPTION_TFTP_SERVERNAME 66
#define DHCP_OPTION_BOOTFILE 67
/** possible combinations of overloading the file and sname fields with options */
#define DHCP_OVERLOAD_NONE 0
#define DHCP_OVERLOAD_FILE 1
#define DHCP_OVERLOAD_SNAME 2
#define DHCP_OVERLOAD_SNAME_FILE 3
#ifdef __cplusplus
}
#endif
#endif /* LWIP_DHCP */
#endif /*__LWIP_DHCP_H__*/

View File

@ -1,124 +0,0 @@
/**
* lwip DNS resolver header file.
* Author: Jim Pettinato
* April 2007
* ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __LWIP_DNS_H__
#define __LWIP_DNS_H__
#include "lwip/opt.h"
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#ifdef __cplusplus
extern "C" {
#endif
/** DNS timer period */
#define DNS_TMR_INTERVAL 1000
/** DNS field TYPE used for "Resource Records" */
#define DNS_RRTYPE_A 1 /* a host address */
#define DNS_RRTYPE_NS 2 /* an authoritative name server */
#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */
#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */
#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */
#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */
#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */
#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */
#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */
#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */
#define DNS_RRTYPE_WKS 11 /* a well known service description */
#define DNS_RRTYPE_PTR 12 /* a domain name pointer */
#define DNS_RRTYPE_HINFO 13 /* host information */
#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */
#define DNS_RRTYPE_MX 15 /* mail exchange */
#define DNS_RRTYPE_TXT 16 /* text strings */
/** DNS field CLASS used for "Resource Records" */
#define DNS_RRCLASS_IN 1 /* the Internet */
#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
#define DNS_RRCLASS_CH 3 /* the CHAOS class */
#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */
#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */
/* The size used for the next line is rather a hack, but it prevents including socket.h in all files
that include memp.h, and that would possibly break portability (since socket.h defines some types
and constants possibly already define by the OS).
Calculation rule:
sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */
#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1)
#if DNS_LOCAL_HOSTLIST
/** struct used for local host-list */
struct local_hostlist_entry {
/** static hostname */
const char *name;
/** static host address in network byteorder */
ip_addr_t addr;
struct local_hostlist_entry *next;
};
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN
#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH
#endif
#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1))
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#endif /* DNS_LOCAL_HOSTLIST */
/** Callback which is invoked when a hostname is found.
* A function of this type must be implemented by the application using the DNS resolver.
* @param name pointer to the name that was looked up.
* @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname,
* or NULL if the name could not be found (or on any other error).
* @param callback_arg a user-specified callback argument passed to dns_gethostbyname
*/
typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);
void dns_init(void);
void dns_tmr(void);
void dns_setserver(u8_t numdns, ip_addr_t *dnsserver);
ip_addr_t dns_getserver(u8_t numdns);
err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr,
dns_found_callback found, void *callback_arg);
#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
int dns_local_removehost(const char *hostname, const ip_addr_t *addr);
err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr);
#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_DNS */
#endif /* __LWIP_DNS_H__ */

View File

@ -1,85 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_ERR_H__
#define __LWIP_ERR_H__
#include "lwip/opt.h"
#include "lwip/arch.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Define LWIP_ERR_T in cc.h if you want to use
* a different type for your platform (must be signed). */
#ifdef LWIP_ERR_T
typedef LWIP_ERR_T err_t;
#else /* LWIP_ERR_T */
typedef s8_t err_t;
#endif /* LWIP_ERR_T*/
/* Definitions for error constants. */
#define ERR_OK 0 /* No error, everything OK. */
#define ERR_MEM -1 /* Out of memory error. */
#define ERR_BUF -2 /* Buffer error. */
#define ERR_TIMEOUT -3 /* Timeout. */
#define ERR_RTE -4 /* Routing problem. */
#define ERR_INPROGRESS -5 /* Operation in progress */
#define ERR_VAL -6 /* Illegal value. */
#define ERR_WOULDBLOCK -7 /* Operation would block. */
#define ERR_USE -8 /* Address in use. */
#define ERR_ISCONN -9 /* Already connected. */
#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN)
#define ERR_ABRT -10 /* Connection aborted. */
#define ERR_RST -11 /* Connection reset. */
#define ERR_CLSD -12 /* Connection closed. */
#define ERR_CONN -13 /* Not connected. */
#define ERR_ARG -14 /* Illegal argument. */
#define ERR_IF -15 /* Low-level netif error */
#ifdef LWIP_DEBUG
extern const char *lwip_strerr(err_t err);
#else
#define lwip_strerr(x) ""
#endif /* LWIP_DEBUG */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_ERR_H__ */

View File

@ -1,72 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_INIT_H__
#define __LWIP_INIT_H__
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C" {
#endif
/** X.x.x: Major version of the stack */
#define LWIP_VERSION_MAJOR 1U
/** x.X.x: Minor version of the stack */
#define LWIP_VERSION_MINOR 4U
/** x.x.X: Revision of the stack */
#define LWIP_VERSION_REVISION 1U
/** For release candidates, this is set to 1..254
* For official releases, this is set to 255 (LWIP_RC_RELEASE)
* For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */
#define LWIP_VERSION_RC 255U
/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */
#define LWIP_RC_RELEASE 255U
/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */
#define LWIP_RC_DEVELOPMENT 0U
#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE)
#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT)
#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT))
/** Provides the version of the stack */
#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \
LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC)
/* Modules initialization */
void lwip_init(void);
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_INIT_H__ */

Some files were not shown because too many files have changed in this diff Show More