aboutsummaryrefslogtreecommitdiff
path: root/lib/lufa/Projects/Webserver/Lib
diff options
context:
space:
mode:
authorDrashna Jaelre <drashna@live.com>2019-08-02 14:02:40 -0700
committerskullydazed <skullydazed@users.noreply.github.com>2019-08-30 15:01:52 -0700
commitcf4575b94a3c65e6535a159fc71fc885aebc2620 (patch)
tree2354f2b7a200e02246a564afefedc32357e62b8e /lib/lufa/Projects/Webserver/Lib
parent75ee8df19e0f14ba466f41ab673dde2fe2fdae9c (diff)
downloadqmk_firmware-cf4575b94a3c65e6535a159fc71fc885aebc2620.tar.gz
qmk_firmware-cf4575b94a3c65e6535a159fc71fc885aebc2620.zip
Fix the LUFA lib to use a submodule instead of just files (#6245)
* Remove LUFA files * Update descriptions for newer version of LUFA * Create PR6245.md * Fix CDC(Serial) type errors * Fix missed merge conflict for AUDIO_DTYPE_CSInterface
Diffstat (limited to 'lib/lufa/Projects/Webserver/Lib')
-rw-r--r--lib/lufa/Projects/Webserver/Lib/DHCPClientApp.c208
-rw-r--r--lib/lufa/Projects/Webserver/Lib/DHCPClientApp.h69
-rw-r--r--lib/lufa/Projects/Webserver/Lib/DHCPCommon.c103
-rw-r--r--lib/lufa/Projects/Webserver/Lib/DHCPCommon.h159
-rw-r--r--lib/lufa/Projects/Webserver/Lib/DHCPServerApp.c265
-rw-r--r--lib/lufa/Projects/Webserver/Lib/DHCPServerApp.h64
-rw-r--r--lib/lufa/Projects/Webserver/Lib/DataflashManager.c534
-rw-r--r--lib/lufa/Projects/Webserver/Lib/DataflashManager.h87
-rw-r--r--lib/lufa/Projects/Webserver/Lib/FATFs/00readme.txt135
-rw-r--r--lib/lufa/Projects/Webserver/Lib/FATFs/diskio.c65
-rw-r--r--lib/lufa/Projects/Webserver/Lib/FATFs/diskio.h52
-rw-r--r--lib/lufa/Projects/Webserver/Lib/FATFs/ff.c4139
-rw-r--r--lib/lufa/Projects/Webserver/Lib/FATFs/ff.h337
-rw-r--r--lib/lufa/Projects/Webserver/Lib/FATFs/ffconf.h190
-rw-r--r--lib/lufa/Projects/Webserver/Lib/FATFs/integer.h38
-rw-r--r--lib/lufa/Projects/Webserver/Lib/HTTPServerApp.c284
-rw-r--r--lib/lufa/Projects/Webserver/Lib/HTTPServerApp.h84
-rw-r--r--lib/lufa/Projects/Webserver/Lib/SCSI.c344
-rw-r--r--lib/lufa/Projects/Webserver/Lib/SCSI.h87
-rw-r--r--lib/lufa/Projects/Webserver/Lib/TELNETServerApp.c163
-rw-r--r--lib/lufa/Projects/Webserver/Lib/TELNETServerApp.h71
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uIPManagement.c298
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uIPManagement.h69
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uip/clock.c37
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uip/clock.h13
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uip/timer.c128
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uip/timer.h87
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uip/uip-split.c151
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uip/uip-split.h104
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uip/uip.c1941
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uip/uip.h2130
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uip/uip_arp.c432
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uip/uip_arp.h146
-rw-r--r--lib/lufa/Projects/Webserver/Lib/uip/uipopt.h740
34 files changed, 0 insertions, 13754 deletions
diff --git a/lib/lufa/Projects/Webserver/Lib/DHCPClientApp.c b/lib/lufa/Projects/Webserver/Lib/DHCPClientApp.c
deleted file mode 100644
index 760718127..000000000
--- a/lib/lufa/Projects/Webserver/Lib/DHCPClientApp.c
+++ /dev/null
@@ -1,208 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * DHCP Client Application. When connected to the uIP stack, this will retrieve IP configuration settings from the
34 * DHCP server on the network.
35 */
36
37#define INCLUDE_FROM_DHCPCLIENTAPP_C
38#include "DHCPClientApp.h"
39
40#if defined(ENABLE_DHCP_CLIENT) || defined(__DOXYGEN__)
41
42/** Initialization function for the DHCP client. */
43void DHCPClientApp_Init(void)
44{
45 /* Create a new UDP connection to the DHCP server port for the DHCP solicitation */
46 struct uip_udp_conn* Connection = uip_udp_new(&uip_broadcast_addr, HTONS(DHCP_SERVER_PORT));
47
48 /* If the connection was successfully created, bind it to the local DHCP client port */
49 if (Connection != NULL)
50 {
51 uip_udp_appstate_t* const AppState = &Connection->appstate;
52 uip_udp_bind(Connection, HTONS(DHCP_CLIENT_PORT));
53
54 /* Set the initial client state */
55 AppState->DHCPClient.CurrentState = DHCP_STATE_SendDiscover;
56
57 /* Set timeout period to half a second for a DHCP server to respond */
58 timer_set(&AppState->DHCPClient.Timeout, CLOCK_SECOND / 2);
59 }
60}
61
62/** uIP stack application callback for the DHCP client. This function must be called each time the TCP/IP stack
63 * needs a UDP packet to be processed.
64 */
65void DHCPClientApp_Callback(void)
66{
67 uip_udp_appstate_t* const AppState = &uip_udp_conn->appstate;
68 DHCP_Header_t* const AppData = (DHCP_Header_t*)uip_appdata;
69 uint16_t AppDataSize = 0;
70
71 switch (AppState->DHCPClient.CurrentState)
72 {
73 case DHCP_STATE_SendDiscover:
74 /* Clear all DHCP settings, reset client IP address */
75 memset(&AppState->DHCPClient.DHCPOffer_Data, 0x00, sizeof(AppState->DHCPClient.DHCPOffer_Data));
76 uip_sethostaddr((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.AllocatedIP);
77
78 /* Fill out the DHCP response header */
79 AppDataSize += DHCPClientApp_FillDHCPHeader(AppData, DHCP_DISCOVER, AppState);
80
81 /* Add the required DHCP options list to the packet */
82 uint8_t RequiredOptionList[] = {DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_ROUTER, DHCP_OPTION_DNS_SERVER};
83 AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_REQ_LIST, sizeof(RequiredOptionList),
84 RequiredOptionList);
85
86 /* Send the DHCP DISCOVER packet */
87 uip_udp_send(AppDataSize);
88
89 /* Reset the timeout timer, progress to next state */
90 timer_reset(&AppState->DHCPClient.Timeout);
91 AppState->DHCPClient.CurrentState = DHCP_STATE_WaitForOffer;
92
93 break;
94 case DHCP_STATE_WaitForOffer:
95 if (!(uip_newdata()))
96 {
97 /* Check if the DHCP timeout period has expired while waiting for a response */
98 if (timer_expired(&AppState->DHCPClient.Timeout))
99 AppState->DHCPClient.CurrentState = DHCP_STATE_SendDiscover;
100
101 break;
102 }
103
104 uint8_t OfferResponse_MessageType;
105 if ((AppData->TransactionID == DHCP_TRANSACTION_ID) &&
106 DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &OfferResponse_MessageType) &&
107 (OfferResponse_MessageType == DHCP_OFFER))
108 {
109 /* Received a DHCP offer for an IP address, copy over values for later request */
110 memcpy(&AppState->DHCPClient.DHCPOffer_Data.AllocatedIP, &AppData->YourIP, sizeof(uip_ipaddr_t));
111 DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK, &AppState->DHCPClient.DHCPOffer_Data.Netmask);
112 DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_ROUTER, &AppState->DHCPClient.DHCPOffer_Data.GatewayIP);
113 DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_SERVER_ID, &AppState->DHCPClient.DHCPOffer_Data.ServerIP);
114
115 timer_reset(&AppState->DHCPClient.Timeout);
116 AppState->DHCPClient.CurrentState = DHCP_STATE_SendRequest;
117 }
118
119 break;
120 case DHCP_STATE_SendRequest:
121 /* Fill out the DHCP response header */
122 AppDataSize += DHCPClientApp_FillDHCPHeader(AppData, DHCP_REQUEST, AppState);
123
124 /* Add the DHCP REQUESTED IP ADDRESS option to the packet */
125 AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_REQ_IPADDR, sizeof(uip_ipaddr_t),
126 &AppState->DHCPClient.DHCPOffer_Data.AllocatedIP);
127
128 /* Add the DHCP SERVER IP ADDRESS option to the packet */
129 AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SERVER_ID, sizeof(uip_ipaddr_t),
130 &AppState->DHCPClient.DHCPOffer_Data.ServerIP);
131
132 /* Send the DHCP REQUEST packet */
133 uip_udp_send(AppDataSize);
134
135 /* Reset the timeout timer, progress to next state */
136 timer_reset(&AppState->DHCPClient.Timeout);
137 AppState->DHCPClient.CurrentState = DHCP_STATE_WaitForACK;
138
139 break;
140 case DHCP_STATE_WaitForACK:
141 if (!(uip_newdata()))
142 {
143 /* Check if the DHCP timeout period has expired while waiting for a response */
144 if (timer_expired(&AppState->DHCPClient.Timeout))
145 AppState->DHCPClient.CurrentState = DHCP_STATE_SendDiscover;
146
147 break;
148 }
149
150 uint8_t RequestResponse_MessageType;
151 if ((AppData->TransactionID == DHCP_TRANSACTION_ID) &&
152 DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &RequestResponse_MessageType) &&
153 (RequestResponse_MessageType == DHCP_ACK))
154 {
155 /* Set the new network parameters from the DHCP server */
156 uip_sethostaddr((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.AllocatedIP);
157 uip_setnetmask((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.Netmask);
158 uip_setdraddr((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.GatewayIP);
159
160 AppState->DHCPClient.CurrentState = DHCP_STATE_AddressLeased;
161 }
162
163 break;
164 }
165}
166
167/** Fills the DHCP packet response with the appropriate BOOTP header for DHCP. This fills out all the required
168 * fields, leaving only the additional DHCP options to be added to the packet before it is sent to the DHCP server.
169 *
170 * \param[out] DHCPHeader Location in the packet buffer where the BOOTP header should be written to
171 * \param[in] DHCPMessageType DHCP Message type, such as DHCP_DISCOVER
172 * \param[in] AppState Application state of the current UDP connection
173 *
174 * \return Size in bytes of the created DHCP packet
175 */
176static uint16_t DHCPClientApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,
177 const uint8_t DHCPMessageType,
178 uip_udp_appstate_t* const AppState)
179{
180 /* Erase existing packet data so that we start will all 0x00 DHCP header data */
181 memset(DHCPHeader, 0, sizeof(DHCP_Header_t));
182
183 /* Fill out the DHCP packet header */
184 DHCPHeader->Operation = DHCP_OP_BOOTREQUEST;
185 DHCPHeader->HardwareType = DHCP_HTYPE_ETHERNET;
186 DHCPHeader->HardwareAddressLength = sizeof(MACAddress);
187 DHCPHeader->Hops = 0;
188 DHCPHeader->TransactionID = DHCP_TRANSACTION_ID;
189 DHCPHeader->ElapsedSeconds = 0;
190 DHCPHeader->Flags = HTONS(BOOTP_BROADCAST);
191 memcpy(&DHCPHeader->ClientIP, &uip_hostaddr, sizeof(uip_ipaddr_t));
192 memcpy(&DHCPHeader->YourIP, &AppState->DHCPClient.DHCPOffer_Data.AllocatedIP, sizeof(uip_ipaddr_t));
193 memcpy(&DHCPHeader->NextServerIP, &AppState->DHCPClient.DHCPOffer_Data.ServerIP, sizeof(uip_ipaddr_t));
194 memcpy(&DHCPHeader->ClientHardwareAddress, &MACAddress, sizeof(struct uip_eth_addr));
195 DHCPHeader->Cookie = DHCP_MAGIC_COOKIE;
196
197 /* Add a DHCP message type and terminator options to the start of the DHCP options field */
198 DHCPHeader->Options[0] = DHCP_OPTION_MSG_TYPE;
199 DHCPHeader->Options[1] = 1;
200 DHCPHeader->Options[2] = DHCPMessageType;
201 DHCPHeader->Options[3] = DHCP_OPTION_END;
202
203 /* Calculate the total number of bytes added to the outgoing packet */
204 return (sizeof(DHCP_Header_t) + 4);
205}
206
207#endif
208
diff --git a/lib/lufa/Projects/Webserver/Lib/DHCPClientApp.h b/lib/lufa/Projects/Webserver/Lib/DHCPClientApp.h
deleted file mode 100644
index 0aec00331..000000000
--- a/lib/lufa/Projects/Webserver/Lib/DHCPClientApp.h
+++ /dev/null
@@ -1,69 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * Header file for DHCPClientApp.c.
34 */
35
36#ifndef _DHCPCLIENT_APP_H_
37#define _DHCPCLIENT_APP_H_
38
39 /* Includes: */
40 #include <stdio.h>
41
42 #include <uip.h>
43
44 #include "Config/AppConfig.h"
45 #include "../Webserver.h"
46 #include "DHCPCommon.h"
47
48 /* Enums: */
49 /** States for each DHCP connection to a DHCP client. */
50 enum DHCP_Client_States_t
51 {
52 DHCP_STATE_SendDiscover, /**< Send DISCOVER packet to retrieve DHCP lease offers */
53 DHCP_STATE_WaitForOffer, /**< Waiting for OFFER packet giving available DHCP leases */
54 DHCP_STATE_SendRequest, /**< Send REQUEST packet to request a DHCP lease */
55 DHCP_STATE_WaitForACK, /**< Wait for ACK packet to complete the DHCP lease */
56 DHCP_STATE_AddressLeased, /**< DHCP address has been leased from a DHCP server */
57 };
58
59 /* Function Prototypes: */
60 void DHCPClientApp_Init(void);
61 void DHCPClientApp_Callback(void);
62
63 #if defined(INCLUDE_FROM_DHCPCLIENTAPP_C)
64 static uint16_t DHCPClientApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,
65 const uint8_t DHCPMessageType,
66 uip_udp_appstate_t* const AppState);
67 #endif
68#endif
69
diff --git a/lib/lufa/Projects/Webserver/Lib/DHCPCommon.c b/lib/lufa/Projects/Webserver/Lib/DHCPCommon.c
deleted file mode 100644
index 6d80f65ca..000000000
--- a/lib/lufa/Projects/Webserver/Lib/DHCPCommon.c
+++ /dev/null
@@ -1,103 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * Common DHCP routines to manage DHCP packet data.
34 */
35
36#include "DHCPCommon.h"
37
38#if defined(ENABLE_DHCP_CLIENT) || defined(ENABLE_DHCP_SERVER) || defined(__DOXYGEN__)
39
40/** Sets the given DHCP option in the DHCP packet's option list. This automatically moves the
41 * end of options terminator past the new option in the options list.
42 *
43 * \param[in,out] DHCPOptionList Pointer to the start of the DHCP packet's options list
44 * \param[in] Option DHCP option to add to the list
45 * \param[in] DataLen Size in bytes of the option data to add
46 * \param[in] OptionData Buffer where the option's data is to be sourced from
47 *
48 * \return Number of bytes added to the DHCP packet
49 */
50uint8_t DHCPCommon_SetOption(uint8_t* DHCPOptionList,
51 const uint8_t Option,
52 const uint8_t DataLen,
53 void* const OptionData)
54{
55 /* Skip through the DHCP options list until the terminator option is found */
56 while (*DHCPOptionList != DHCP_OPTION_END)
57 DHCPOptionList += (DHCPOptionList[1] + 2);
58
59 /* Overwrite the existing terminator with the new option, add a new terminator at the end of the list */
60 DHCPOptionList[0] = Option;
61 DHCPOptionList[1] = DataLen;
62 memcpy(&DHCPOptionList[2], OptionData, DataLen);
63 DHCPOptionList[2 + DataLen] = DHCP_OPTION_END;
64
65 /* Calculate the total number of bytes added to the outgoing packet */
66 return (2 + DataLen);
67}
68
69/** Retrieves the given option's data (if present) from the DHCP packet's options list.
70 *
71 * \param[in,out] DHCPOptionList Pointer to the start of the DHCP packet's options list
72 * \param[in] Option DHCP option to retrieve to the list
73 * \param[out] Destination Buffer where the option's data is to be written to if found
74 *
75 * \return Boolean \c true if the option was found in the DHCP packet's options list, \c false otherwise
76 */
77bool DHCPCommon_GetOption(const uint8_t* DHCPOptionList,
78 const uint8_t Option,
79 void* const Destination)
80{
81 /* Look through the incoming DHCP packet's options list for the requested option */
82 while (*DHCPOptionList != DHCP_OPTION_END)
83 {
84 /* Check if the current DHCP option in the packet is the one requested */
85 if (DHCPOptionList[0] == Option)
86 {
87 /* Copy request option's data to the destination buffer */
88 memcpy(Destination, &DHCPOptionList[2], DHCPOptionList[1]);
89
90 /* Indicate that the requested option data was successfully retrieved */
91 return true;
92 }
93
94 /* Skip to next DHCP option in the options list */
95 DHCPOptionList += (DHCPOptionList[1] + 2);
96 }
97
98 /* Requested option not found in the incoming packet's DHCP options list */
99 return false;
100}
101
102#endif
103
diff --git a/lib/lufa/Projects/Webserver/Lib/DHCPCommon.h b/lib/lufa/Projects/Webserver/Lib/DHCPCommon.h
deleted file mode 100644
index 8f54c1671..000000000
--- a/lib/lufa/Projects/Webserver/Lib/DHCPCommon.h
+++ /dev/null
@@ -1,159 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * Header file for common DHCP defines.
34 */
35
36#ifndef _DHCP_COMMON_H_
37#define _DHCP_COMMON_H_
38
39 /* Includes: */
40 #include <stdint.h>
41 #include <stdbool.h>
42 #include <string.h>
43
44 #include "Config/AppConfig.h"
45
46 #include <uip.h>
47
48 /* Macros: */
49 /** UDP listen port for a BOOTP server. */
50 #define DHCP_SERVER_PORT 67
51
52 /** UDP listen port for a BOOTP client. */
53 #define DHCP_CLIENT_PORT 68
54
55 /** BOOTP message type for a BOOTP REQUEST message. */
56 #define DHCP_OP_BOOTREQUEST 0x01
57
58 /** BOOTP message type for a BOOTP REPLY message. */
59 #define DHCP_OP_BOOTREPLY 0x02
60
61 /** BOOTP flag for a BOOTP broadcast message. */
62 #define BOOTP_BROADCAST 0x8000
63
64 /** Magic DHCP cookie for a BOOTP message to identify it as a DHCP message. */
65 #define DHCP_MAGIC_COOKIE 0x63538263
66
67 /** Unique transaction ID used to identify DHCP responses to the client. */
68 #define DHCP_TRANSACTION_ID 0x13245466
69
70 /** DHCP message type for a DISCOVER message. */
71 #define DHCP_DISCOVER 1
72
73 /** DHCP message type for an OFFER message. */
74 #define DHCP_OFFER 2
75
76 /** DHCP message type for a REQUEST message. */
77 #define DHCP_REQUEST 3
78
79 /** DHCP message type for a DECLINE message. */
80 #define DHCP_DECLINE 4
81
82 /** DHCP message type for an ACK message. */
83 #define DHCP_ACK 5
84
85 /** DHCP message type for a NAK message. */
86 #define DHCP_NAK 6
87
88 /** DHCP message type for a RELEASE message. */
89 #define DHCP_RELEASE 7
90
91 /** DHCP medium type for standard Ethernet. */
92 #define DHCP_HTYPE_ETHERNET 1
93
94 /** DHCP message option for the network subnet mask. */
95 #define DHCP_OPTION_SUBNET_MASK 1
96
97 /** DHCP message option for the network gateway IP. */
98 #define DHCP_OPTION_ROUTER 3
99
100 /** DHCP message option for the network DNS server. */
101 #define DHCP_OPTION_DNS_SERVER 6
102
103 /** DHCP message option for the requested client IP address. */
104 #define DHCP_OPTION_REQ_IPADDR 50
105
106 /** DHCP message option for the IP address lease time. */
107 #define DHCP_OPTION_LEASE_TIME 51
108
109 /** DHCP message option for the DHCP message type. */
110 #define DHCP_OPTION_MSG_TYPE 53
111
112 /** DHCP message option for the DHCP server IP. */
113 #define DHCP_OPTION_SERVER_ID 54
114
115 /** DHCP message option for the list of required options from the server. */
116 #define DHCP_OPTION_REQ_LIST 55
117
118 /** DHCP message option for the options list terminator. */
119 #define DHCP_OPTION_END 255
120
121 /* Type Defines: */
122 /** Type define for a DHCP packet inside an Ethernet frame. */
123 typedef struct
124 {
125 uint8_t Operation; /**< DHCP operation, either DHCP_OP_BOOTREQUEST or DHCP_OP_BOOTREPLY */
126 uint8_t HardwareType; /**< Hardware carrier type constant */
127 uint8_t HardwareAddressLength; /**< Length in bytes of a hardware (MAC) address on the network */
128 uint8_t Hops; /**< Number of hops required to reach the server, unused */
129
130 uint32_t TransactionID; /**< Unique ID of the DHCP packet, for positive matching between sent and received packets */
131
132 uint16_t ElapsedSeconds; /**< Elapsed seconds since the request was made */
133 uint16_t Flags; /**< BOOTP packet flags */
134
135 uip_ipaddr_t ClientIP; /**< Client IP address, if already leased an IP */
136 uip_ipaddr_t YourIP; /**< Client IP address */
137 uip_ipaddr_t NextServerIP; /**< Legacy BOOTP protocol field, unused for DHCP */
138 uip_ipaddr_t RelayAgentIP; /**< Legacy BOOTP protocol field, unused for DHCP */
139
140 uint8_t ClientHardwareAddress[16]; /**< Hardware (MAC) address of the client making a request to the DHCP server */
141 uint8_t ServerHostnameString[64]; /**< Legacy BOOTP protocol field, unused for DHCP */
142 uint8_t BootFileName[128]; /**< Legacy BOOTP protocol field, unused for DHCP */
143
144 uint32_t Cookie; /**< Magic BOOTP protocol cookie to indicate a valid packet */
145
146 uint8_t Options[]; /**< DHCP message options */
147 } DHCP_Header_t;
148
149 /* Function Prototypes: */
150 uint8_t DHCPCommon_SetOption(uint8_t* DHCPOptionList,
151 const uint8_t Option,
152 const uint8_t DataLen,
153 void* const OptionData);
154 bool DHCPCommon_GetOption(const uint8_t* DHCPOptionList,
155 const uint8_t Option,
156 void* const Destination);
157
158#endif
159
diff --git a/lib/lufa/Projects/Webserver/Lib/DHCPServerApp.c b/lib/lufa/Projects/Webserver/Lib/DHCPServerApp.c
deleted file mode 100644
index fea54ddb0..000000000
--- a/lib/lufa/Projects/Webserver/Lib/DHCPServerApp.c
+++ /dev/null
@@ -1,265 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * DHCP Server Application. When connected to the uIP stack, this will send IP configuration settings to a
34 * DHCP client on the network.
35 */
36
37#define INCLUDE_FROM_DHCPSERVERAPP_C
38#include "DHCPServerApp.h"
39
40#if defined(ENABLE_DHCP_SERVER) || defined(__DOXYGEN__)
41
42struct uip_conn* BroadcastConnection;
43
44uint8_t LeasedIPs[255 / 8];
45
46/** Initialization function for the DHCP server. */
47void DHCPServerApp_Init(void)
48{
49 /* Listen on port 67 for DHCP server connections from hosts */
50 uip_listen(HTONS(DHCP_SERVER_PORT));
51
52 /* Create a new UDP connection to the DHCP server port for the DHCP solicitation */
53 struct uip_udp_conn* BroadcastConnection = uip_udp_new(&uip_broadcast_addr, HTONS(DHCP_CLIENT_PORT));
54
55 /* If the connection was successfully created, bind it to the local DHCP client port */
56 if (BroadcastConnection != NULL)
57 uip_udp_bind(BroadcastConnection, HTONS(DHCP_SERVER_PORT));
58
59 /* Set all IP addresses as unleased */
60 memset(LeasedIPs, 0x00, sizeof(LeasedIPs));
61}
62
63/** uIP stack application callback for the DHCP server. This function must be called each time the TCP/IP stack
64 * needs a UDP packet to be processed.
65 */
66void DHCPServerApp_Callback(void)
67{
68 DHCP_Header_t* const AppData = (DHCP_Header_t*)uip_appdata;
69 uint16_t AppDataSize = 0;
70
71 /* Only process when new data arrives - don't retransmit lost packets */
72 if (uip_newdata())
73 {
74 /* Get the DHCP message type (if present), otherwise early-abort */
75 uint8_t DHCPMessageType;
76 if (!(DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &DHCPMessageType)))
77 return;
78
79 uip_ipaddr_t Netmask, GatewayIPAddress, PreferredClientIP;
80 struct uip_eth_addr RemoteMACAddress;
81 uint32_t TransactionID;
82
83 /* Get configured network mask, gateway IP and extract out DHCP transaction ID and remote IP */
84 uip_getnetmask(&Netmask);
85 uip_getdraddr(&GatewayIPAddress);
86 memcpy(&RemoteMACAddress, &AppData->ClientHardwareAddress, sizeof(struct uip_eth_addr));
87 TransactionID = AppData->TransactionID;
88
89 /* Try to extract out the client's preferred IP address if it is indicated in the packet */
90 if (!(DHCPCommon_GetOption(AppData->Options, DHCP_OPTION_REQ_IPADDR, &PreferredClientIP)))
91 memcpy(&PreferredClientIP, &uip_all_zeroes_addr, sizeof(uip_ipaddr_t));
92
93 switch (DHCPMessageType)
94 {
95 case DHCP_DISCOVER:
96 /* If no preference was made or the preferred IP is already taken, find a new address */
97 if (DHCPServerApp_CheckIfIPLeased(&PreferredClientIP))
98 DHCPServerApp_GetUnleasedIP(&PreferredClientIP);
99
100 /* Create a new DHCP OFFER packet with the offered IP address */
101 AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_OFFER, &RemoteMACAddress, &PreferredClientIP, TransactionID);
102
103 /* Add network mask and router information to the list of DHCP OFFER packet options */
104 AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK,
105 sizeof(uip_ipaddr_t), &Netmask);
106 AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_ROUTER,
107 sizeof(uip_ipaddr_t), &GatewayIPAddress);
108
109 /* Send the DHCP OFFER packet */
110 uip_poll_conn(BroadcastConnection);
111 memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));
112 uip_udp_send(AppDataSize);
113
114 break;
115 case DHCP_REQUEST:
116 /* Check to see if the requested IP address has already been leased to a client */
117 if (!(DHCPServerApp_CheckIfIPLeased(&PreferredClientIP)))
118 {
119 /* Create a new DHCP ACK packet to accept the IP address lease */
120 AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_ACK, &RemoteMACAddress, &PreferredClientIP, TransactionID);
121
122 /* Add network mask and router information to the list of DHCP ACK packet options */
123 AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK,
124 sizeof(uip_ipaddr_t), &Netmask);
125 AppDataSize += DHCPCommon_SetOption(AppData->Options, DHCP_OPTION_ROUTER,
126 sizeof(uip_ipaddr_t), &GatewayIPAddress);
127
128 /* Mark the requested IP as leased to a client */
129 DHCPServerApp_LeaseIP(&PreferredClientIP);
130 }
131 else
132 {
133 /* Create a new DHCP NAK packet to reject the requested allocation */
134 AppDataSize += DHCPServerApp_FillDHCPHeader(AppData, DHCP_NAK, &RemoteMACAddress, &uip_all_zeroes_addr, TransactionID);
135 }
136
137 /* Send the DHCP ACK or NAK packet */
138 uip_poll_conn(BroadcastConnection);
139 memcpy(&uip_udp_conn->ripaddr, &uip_broadcast_addr, sizeof(uip_ipaddr_t));
140 uip_udp_send(AppDataSize);
141
142 break;
143 case DHCP_RELEASE:
144 /* Mark the IP address as released in the allocation table */
145 DHCPServerApp_UnleaseIP(&uip_udp_conn->ripaddr);
146 break;
147 }
148 }
149}
150
151/** Fills the DHCP packet response with the appropriate BOOTP header for DHCP. This fills out all the required
152 * fields, leaving only the additional DHCP options to be added to the packet before it is sent to the DHCP client.
153 *
154 * \param[out] DHCPHeader Location in the packet buffer where the BOOTP header should be written to
155 * \param[in] DHCPMessageType DHCP Message type, such as DHCP_DISCOVER
156 * \param[in] ClientHardwareAddress Client MAC address the created transaction should be directed to
157 * \param[in] PreferredClientIP Preferred IP that should be given to the client if it is unallocated
158 * \param[in] TransactionID Transaction ID the created transaction should be associated with
159 *
160 * \return Size in bytes of the created DHCP packet
161 */
162static uint16_t DHCPServerApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,
163 const uint8_t DHCPMessageType,
164 const struct uip_eth_addr* const ClientHardwareAddress,
165 const uip_ipaddr_t* const PreferredClientIP,
166 const uint32_t TransactionID)
167{
168 /* Erase existing packet data so that we start will all 0x00 DHCP header data */
169 memset(DHCPHeader, 0, sizeof(DHCP_Header_t));
170
171 DHCPHeader->Operation = DHCPMessageType;
172 DHCPHeader->HardwareType = DHCP_HTYPE_ETHERNET;
173 DHCPHeader->HardwareAddressLength = sizeof(MACAddress);
174 DHCPHeader->Hops = 0;
175 DHCPHeader->TransactionID = TransactionID;
176 DHCPHeader->ElapsedSeconds = 0;
177 DHCPHeader->Flags = 0;
178 memcpy(&DHCPHeader->NextServerIP, &uip_hostaddr, sizeof(uip_ipaddr_t));
179 memcpy(&DHCPHeader->YourIP, PreferredClientIP, sizeof(uip_ipaddr_t));
180 memcpy(&DHCPHeader->ClientHardwareAddress, ClientHardwareAddress, sizeof(struct uip_eth_addr));
181 DHCPHeader->Cookie = DHCP_MAGIC_COOKIE;
182
183 /* Add a DHCP message type and terminator options to the start of the DHCP options field */
184 DHCPHeader->Options[0] = DHCP_OPTION_MSG_TYPE;
185 DHCPHeader->Options[1] = 1;
186 DHCPHeader->Options[2] = DHCPMessageType;
187 DHCPHeader->Options[3] = DHCP_OPTION_END;
188
189 /* Calculate the total number of bytes added to the outgoing packet */
190 return (sizeof(DHCP_Header_t) + 4);
191}
192
193/** Checks to see if the nominated IP address has already been allocated to a client.
194 *
195 * \param[in] IPAddress IP Address whose lease status should be checked
196 *
197 * \pre The IP address must be within the same /24 subnet as the virtual webserver.
198 *
199 * \return Boolean \c true if the IP has already been leased to a client, \c false otherwise.
200 */
201static bool DHCPServerApp_CheckIfIPLeased(const uip_ipaddr_t* const IPAddress)
202{
203 uint8_t Byte = (IPAddress->u8[3] / 8);
204 uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
205
206 /* Make sure that the requested IP address isn't already leased to the virtual server or another client */
207 if (IPAddress->u8[3] && !(IPAddress->u8[3] == uip_hostaddr.u8[3]) && !(LeasedIPs[Byte] & Mask))
208 return false;
209 else
210 return true;
211}
212
213/** Retrieves the next unleased IP in the IP address pool.
214 *
215 * \param[out] NewIPAddress Location where the generated IP Address should be stored
216 */
217static void DHCPServerApp_GetUnleasedIP(uip_ipaddr_t* const NewIPAddress)
218{
219 uip_ipaddr_copy(NewIPAddress, &uip_hostaddr);
220
221 /** Look through the current subnet, skipping the broadcast and zero IP addresses */
222 for (uint8_t IP = 1; IP < 254; IP++)
223 {
224 /* Update new IP address to lease with the current IP address to test */
225 NewIPAddress->u8[3] = IP;
226
227 /* If we've found an unleased IP, abort with the updated IP stored for the called */
228 if (!(DHCPServerApp_CheckIfIPLeased(NewIPAddress)))
229 return;
230 }
231}
232
233/** Marks the given IP Address as leased in the address pool, so that it will not be
234 * allocated to another client unless it is first released.
235 *
236 * \param[in] IPAddress IP Address to mark as leased
237 *
238 * \pre The IP address must be within the same /24 subnet as the virtual webserver.
239 */
240static void DHCPServerApp_LeaseIP(const uip_ipaddr_t* const IPAddress)
241{
242 uint8_t Byte = (IPAddress->u8[3] / 8);
243 uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
244
245 /* Mark the IP address as leased in the allocation table */
246 LeasedIPs[Byte] |= Mask;
247}
248
249/** Marks the given IP Address as not leased in the address pool, so that it can be
250 * allocated to another client upon request.
251 *
252 * \param[in] IPAddress IP Address to mark as not leased
253 *
254 * \pre The IP address must be within the same /24 subnet as the virtual webserver.
255 */
256static void DHCPServerApp_UnleaseIP(const uip_ipaddr_t* const IPAddress)
257{
258 uint8_t Byte = (IPAddress->u8[3] / 8);
259 uint8_t Mask = (1 << (IPAddress->u8[3] % 8));
260
261 /* Mark the IP address as unleased in the allocation table */
262 LeasedIPs[Byte] &= ~Mask;
263}
264#endif
265
diff --git a/lib/lufa/Projects/Webserver/Lib/DHCPServerApp.h b/lib/lufa/Projects/Webserver/Lib/DHCPServerApp.h
deleted file mode 100644
index a9dae7bf3..000000000
--- a/lib/lufa/Projects/Webserver/Lib/DHCPServerApp.h
+++ /dev/null
@@ -1,64 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * Header file for DHCPServerApp.c.
34 */
35
36#ifndef _DHCPSERVER_APP_H_
37#define _DHCPSERVER_APP_H_
38
39 /* Includes: */
40 #include <stdio.h>
41
42 #include <uip.h>
43
44 #include "Config/AppConfig.h"
45 #include "../Webserver.h"
46 #include "DHCPCommon.h"
47
48 /* Function Prototypes: */
49 void DHCPServerApp_Init(void);
50 void DHCPServerApp_Callback(void);
51
52 #if defined(INCLUDE_FROM_DHCPSERVERAPP_C)
53 static uint16_t DHCPServerApp_FillDHCPHeader(DHCP_Header_t* const DHCPHeader,
54 const uint8_t DHCPMessageType,
55 const struct uip_eth_addr* const ClientHardwareAddress,
56 const uip_ipaddr_t* const PreferredClientIP,
57 const uint32_t TransactionID);
58 static bool DHCPServerApp_CheckIfIPLeased(const uip_ipaddr_t* const IPAddress);
59 static void DHCPServerApp_GetUnleasedIP(uip_ipaddr_t* const NewIPAddress);
60 static void DHCPServerApp_LeaseIP(const uip_ipaddr_t* const IPAddress);
61 static void DHCPServerApp_UnleaseIP(const uip_ipaddr_t* const IPAddress);
62 #endif
63#endif
64
diff --git a/lib/lufa/Projects/Webserver/Lib/DataflashManager.c b/lib/lufa/Projects/Webserver/Lib/DataflashManager.c
deleted file mode 100644
index b1111ce39..000000000
--- a/lib/lufa/Projects/Webserver/Lib/DataflashManager.c
+++ /dev/null
@@ -1,534 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * Functions to manage the physical Dataflash media, including reading and writing of
34 * blocks of data. These functions are called by the SCSI layer when data must be stored
35 * or retrieved to/from the physical storage media. If a different media is used (such
36 * as a SD card or EEPROM), functions similar to these will need to be generated.
37 */
38
39#define INCLUDE_FROM_DATAFLASHMANAGER_C
40#include "DataflashManager.h"
41
42/** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board Dataflash IC(s), from
43 * the pre-selected data OUT endpoint. This routine reads in OS sized blocks from the endpoint and writes
44 * them to the Dataflash in Dataflash page sized blocks.
45 *
46 * \param[in] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
47 * \param[in] BlockAddress Data block starting address for the write sequence
48 * \param[in] TotalBlocks Number of blocks of data to write
49 */
50void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
51 const uint32_t BlockAddress,
52 uint16_t TotalBlocks)
53{
54 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
55 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
56 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
57 bool UsingSecondBuffer = false;
58
59 /* Select the correct starting Dataflash IC for the block requested */
60 Dataflash_SelectChipFromPage(CurrDFPage);
61
62#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
63 /* Copy selected dataflash's current page contents to the Dataflash buffer */
64 Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
65 Dataflash_SendAddressBytes(CurrDFPage, 0);
66 Dataflash_WaitWhileBusy();
67#endif
68
69 /* Send the Dataflash buffer write command */
70 Dataflash_SendByte(DF_CMD_BUFF1WRITE);
71 Dataflash_SendAddressBytes(0, CurrDFPageByte);
72
73 /* Wait until endpoint is ready before continuing */
74 if (Endpoint_WaitUntilReady())
75 return;
76
77 while (TotalBlocks)
78 {
79 uint8_t BytesInBlockDiv16 = 0;
80
81 /* Write an endpoint packet sized data block to the Dataflash */
82 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
83 {
84 /* Check if the endpoint is currently empty */
85 if (!(Endpoint_IsReadWriteAllowed()))
86 {
87 /* Clear the current endpoint bank */
88 Endpoint_ClearOUT();
89
90 /* Wait until the host has sent another packet */
91 if (Endpoint_WaitUntilReady())
92 return;
93 }
94
95 /* Check if end of Dataflash page reached */
96 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
97 {
98 /* Write the Dataflash buffer contents back to the Dataflash page */
99 Dataflash_WaitWhileBusy();
100 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
101 Dataflash_SendAddressBytes(CurrDFPage, 0);
102
103 /* Reset the Dataflash buffer counter, increment the page counter */
104 CurrDFPageByteDiv16 = 0;
105 CurrDFPage++;
106
107 /* Once all the Dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
108 if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
109 UsingSecondBuffer = !(UsingSecondBuffer);
110
111 /* Select the next Dataflash chip based on the new Dataflash page index */
112 Dataflash_SelectChipFromPage(CurrDFPage);
113
114#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
115 /* If less than one Dataflash page remaining, copy over the existing page to preserve trailing data */
116 if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
117 {
118 /* Copy selected dataflash's current page contents to the Dataflash buffer */
119 Dataflash_WaitWhileBusy();
120 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
121 Dataflash_SendAddressBytes(CurrDFPage, 0);
122 Dataflash_WaitWhileBusy();
123 }
124#endif
125
126 /* Send the Dataflash buffer write command */
127 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2WRITE : DF_CMD_BUFF1WRITE);
128 Dataflash_SendAddressBytes(0, 0);
129 }
130
131 /* Write one 16-byte chunk of data to the Dataflash */
132 Dataflash_SendByte(Endpoint_Read_8());
133 Dataflash_SendByte(Endpoint_Read_8());
134 Dataflash_SendByte(Endpoint_Read_8());
135 Dataflash_SendByte(Endpoint_Read_8());
136 Dataflash_SendByte(Endpoint_Read_8());
137 Dataflash_SendByte(Endpoint_Read_8());
138 Dataflash_SendByte(Endpoint_Read_8());
139 Dataflash_SendByte(Endpoint_Read_8());
140 Dataflash_SendByte(Endpoint_Read_8());
141 Dataflash_SendByte(Endpoint_Read_8());
142 Dataflash_SendByte(Endpoint_Read_8());
143 Dataflash_SendByte(Endpoint_Read_8());
144 Dataflash_SendByte(Endpoint_Read_8());
145 Dataflash_SendByte(Endpoint_Read_8());
146 Dataflash_SendByte(Endpoint_Read_8());
147 Dataflash_SendByte(Endpoint_Read_8());
148
149 /* Increment the Dataflash page 16 byte block counter */
150 CurrDFPageByteDiv16++;
151
152 /* Increment the block 16 byte block counter */
153 BytesInBlockDiv16++;
154
155 /* Check if the current command is being aborted by the host */
156 if (MSInterfaceInfo->State.IsMassStoreReset)
157 return;
158 }
159
160 /* Decrement the blocks remaining counter */
161 TotalBlocks--;
162 }
163
164 /* Write the Dataflash buffer contents back to the Dataflash page */
165 Dataflash_WaitWhileBusy();
166 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
167 Dataflash_SendAddressBytes(CurrDFPage, 0x00);
168 Dataflash_WaitWhileBusy();
169
170 /* If the endpoint is empty, clear it ready for the next packet from the host */
171 if (!(Endpoint_IsReadWriteAllowed()))
172 Endpoint_ClearOUT();
173
174 /* Deselect all Dataflash chips */
175 Dataflash_DeselectChip();
176}
177
178/** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board Dataflash IC(s), into
179 * the pre-selected data IN endpoint. This routine reads in Dataflash page sized blocks from the Dataflash
180 * and writes them in OS sized blocks to the endpoint.
181 *
182 * \param[in] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
183 * \param[in] BlockAddress Data block starting address for the read sequence
184 * \param[in] TotalBlocks Number of blocks of data to read
185 */
186void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
187 const uint32_t BlockAddress,
188 uint16_t TotalBlocks)
189{
190 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
191 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
192 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
193
194 /* Select the correct starting Dataflash IC for the block requested */
195 Dataflash_SelectChipFromPage(CurrDFPage);
196
197 /* Send the Dataflash main memory page read command */
198 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
199 Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
200 Dataflash_SendByte(0x00);
201 Dataflash_SendByte(0x00);
202 Dataflash_SendByte(0x00);
203 Dataflash_SendByte(0x00);
204
205 /* Wait until endpoint is ready before continuing */
206 if (Endpoint_WaitUntilReady())
207 return;
208
209 while (TotalBlocks)
210 {
211 uint8_t BytesInBlockDiv16 = 0;
212
213 /* Read an endpoint packet sized data block from the Dataflash */
214 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
215 {
216 /* Check if the endpoint is currently full */
217 if (!(Endpoint_IsReadWriteAllowed()))
218 {
219 /* Clear the endpoint bank to send its contents to the host */
220 Endpoint_ClearIN();
221
222 /* Wait until the endpoint is ready for more data */
223 if (Endpoint_WaitUntilReady())
224 return;
225 }
226
227 /* Check if end of Dataflash page reached */
228 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
229 {
230 /* Reset the Dataflash buffer counter, increment the page counter */
231 CurrDFPageByteDiv16 = 0;
232 CurrDFPage++;
233
234 /* Select the next Dataflash chip based on the new Dataflash page index */
235 Dataflash_SelectChipFromPage(CurrDFPage);
236
237 /* Send the Dataflash main memory page read command */
238 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
239 Dataflash_SendAddressBytes(CurrDFPage, 0);
240 Dataflash_SendByte(0x00);
241 Dataflash_SendByte(0x00);
242 Dataflash_SendByte(0x00);
243 Dataflash_SendByte(0x00);
244 }
245
246 /* Read one 16-byte chunk of data from the Dataflash */
247 Endpoint_Write_8(Dataflash_ReceiveByte());
248 Endpoint_Write_8(Dataflash_ReceiveByte());
249 Endpoint_Write_8(Dataflash_ReceiveByte());
250 Endpoint_Write_8(Dataflash_ReceiveByte());
251 Endpoint_Write_8(Dataflash_ReceiveByte());
252 Endpoint_Write_8(Dataflash_ReceiveByte());
253 Endpoint_Write_8(Dataflash_ReceiveByte());
254 Endpoint_Write_8(Dataflash_ReceiveByte());
255 Endpoint_Write_8(Dataflash_ReceiveByte());
256 Endpoint_Write_8(Dataflash_ReceiveByte());
257 Endpoint_Write_8(Dataflash_ReceiveByte());
258 Endpoint_Write_8(Dataflash_ReceiveByte());
259 Endpoint_Write_8(Dataflash_ReceiveByte());
260 Endpoint_Write_8(Dataflash_ReceiveByte());
261 Endpoint_Write_8(Dataflash_ReceiveByte());
262 Endpoint_Write_8(Dataflash_ReceiveByte());
263
264 /* Increment the Dataflash page 16 byte block counter */
265 CurrDFPageByteDiv16++;
266
267 /* Increment the block 16 byte block counter */
268 BytesInBlockDiv16++;
269
270 /* Check if the current command is being aborted by the host */
271 if (MSInterfaceInfo->State.IsMassStoreReset)
272 return;
273 }
274
275 /* Decrement the blocks remaining counter */
276 TotalBlocks--;
277 }
278
279 /* If the endpoint is full, send its contents to the host */
280 if (!(Endpoint_IsReadWriteAllowed()))
281 Endpoint_ClearIN();
282
283 /* Deselect all Dataflash chips */
284 Dataflash_DeselectChip();
285}
286
287/** Writes blocks (OS blocks, not Dataflash pages) to the storage medium, the board Dataflash IC(s), from
288 * the given RAM buffer. This routine reads in OS sized blocks from the buffer and writes them to the
289 * Dataflash in Dataflash page sized blocks. This can be linked to FAT libraries to write files to the
290 * Dataflash.
291 *
292 * \param[in] BlockAddress Data block starting address for the write sequence
293 * \param[in] TotalBlocks Number of blocks of data to write
294 * \param[in] BufferPtr Pointer to the data source RAM buffer
295 */
296void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress,
297 uint16_t TotalBlocks,
298 const uint8_t* BufferPtr)
299{
300 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
301 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
302 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
303 bool UsingSecondBuffer = false;
304
305 /* Select the correct starting Dataflash IC for the block requested */
306 Dataflash_SelectChipFromPage(CurrDFPage);
307
308#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
309 /* Copy selected dataflash's current page contents to the Dataflash buffer */
310 Dataflash_SendByte(DF_CMD_MAINMEMTOBUFF1);
311 Dataflash_SendAddressBytes(CurrDFPage, 0);
312 Dataflash_WaitWhileBusy();
313#endif
314
315 /* Send the Dataflash buffer write command */
316 Dataflash_SendByte(DF_CMD_BUFF1WRITE);
317 Dataflash_SendAddressBytes(0, CurrDFPageByte);
318
319 while (TotalBlocks)
320 {
321 uint8_t BytesInBlockDiv16 = 0;
322
323 /* Write an endpoint packet sized data block to the Dataflash */
324 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
325 {
326 /* Check if end of Dataflash page reached */
327 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
328 {
329 /* Write the Dataflash buffer contents back to the Dataflash page */
330 Dataflash_WaitWhileBusy();
331 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
332 Dataflash_SendAddressBytes(CurrDFPage, 0);
333
334 /* Reset the Dataflash buffer counter, increment the page counter */
335 CurrDFPageByteDiv16 = 0;
336 CurrDFPage++;
337
338 /* Once all the Dataflash ICs have had their first buffers filled, switch buffers to maintain throughput */
339 if (Dataflash_GetSelectedChip() == DATAFLASH_CHIP_MASK(DATAFLASH_TOTALCHIPS))
340 UsingSecondBuffer = !(UsingSecondBuffer);
341
342 /* Select the next Dataflash chip based on the new Dataflash page index */
343 Dataflash_SelectChipFromPage(CurrDFPage);
344
345#if (DATAFLASH_PAGE_SIZE > VIRTUAL_MEMORY_BLOCK_SIZE)
346 /* If less than one Dataflash page remaining, copy over the existing page to preserve trailing data */
347 if ((TotalBlocks * (VIRTUAL_MEMORY_BLOCK_SIZE >> 4)) < (DATAFLASH_PAGE_SIZE >> 4))
348 {
349 /* Copy selected dataflash's current page contents to the Dataflash buffer */
350 Dataflash_WaitWhileBusy();
351 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_MAINMEMTOBUFF2 : DF_CMD_MAINMEMTOBUFF1);
352 Dataflash_SendAddressBytes(CurrDFPage, 0);
353 Dataflash_WaitWhileBusy();
354 }
355#endif
356
357 /* Send the Dataflash buffer write command */
358 Dataflash_ToggleSelectedChipCS();
359 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2WRITE : DF_CMD_BUFF1WRITE);
360 Dataflash_SendAddressBytes(0, 0);
361 }
362
363 /* Write one 16-byte chunk of data to the Dataflash */
364 for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
365 Dataflash_SendByte(*(BufferPtr++));
366
367 /* Increment the Dataflash page 16 byte block counter */
368 CurrDFPageByteDiv16++;
369
370 /* Increment the block 16 byte block counter */
371 BytesInBlockDiv16++;
372 }
373
374 /* Decrement the blocks remaining counter */
375 TotalBlocks--;
376 }
377
378 /* Write the Dataflash buffer contents back to the Dataflash page */
379 Dataflash_WaitWhileBusy();
380 Dataflash_SendByte(UsingSecondBuffer ? DF_CMD_BUFF2TOMAINMEMWITHERASE : DF_CMD_BUFF1TOMAINMEMWITHERASE);
381 Dataflash_SendAddressBytes(CurrDFPage, 0x00);
382 Dataflash_WaitWhileBusy();
383
384 /* Deselect all Dataflash chips */
385 Dataflash_DeselectChip();
386}
387
388/** Reads blocks (OS blocks, not Dataflash pages) from the storage medium, the board Dataflash IC(s), into
389 * the preallocated RAM buffer. This routine reads in Dataflash page sized blocks from the Dataflash
390 * and writes them in OS sized blocks to the given buffer. This can be linked to FAT libraries to read
391 * the files stored on the Dataflash.
392 *
393 * \param[in] BlockAddress Data block starting address for the read sequence
394 * \param[in] TotalBlocks Number of blocks of data to read
395 * \param[out] BufferPtr Pointer to the data destination RAM buffer
396 */
397void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress,
398 uint16_t TotalBlocks,
399 uint8_t* BufferPtr)
400{
401 uint16_t CurrDFPage = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) / DATAFLASH_PAGE_SIZE);
402 uint16_t CurrDFPageByte = ((BlockAddress * VIRTUAL_MEMORY_BLOCK_SIZE) % DATAFLASH_PAGE_SIZE);
403 uint8_t CurrDFPageByteDiv16 = (CurrDFPageByte >> 4);
404
405 /* Select the correct starting Dataflash IC for the block requested */
406 Dataflash_SelectChipFromPage(CurrDFPage);
407
408 /* Send the Dataflash main memory page read command */
409 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
410 Dataflash_SendAddressBytes(CurrDFPage, CurrDFPageByte);
411 Dataflash_SendByte(0x00);
412 Dataflash_SendByte(0x00);
413 Dataflash_SendByte(0x00);
414 Dataflash_SendByte(0x00);
415
416 while (TotalBlocks)
417 {
418 uint8_t BytesInBlockDiv16 = 0;
419
420 /* Read an endpoint packet sized data block from the Dataflash */
421 while (BytesInBlockDiv16 < (VIRTUAL_MEMORY_BLOCK_SIZE >> 4))
422 {
423 /* Check if end of Dataflash page reached */
424 if (CurrDFPageByteDiv16 == (DATAFLASH_PAGE_SIZE >> 4))
425 {
426 /* Reset the Dataflash buffer counter, increment the page counter */
427 CurrDFPageByteDiv16 = 0;
428 CurrDFPage++;
429
430 /* Select the next Dataflash chip based on the new Dataflash page index */
431 Dataflash_SelectChipFromPage(CurrDFPage);
432
433 /* Send the Dataflash main memory page read command */
434 Dataflash_SendByte(DF_CMD_MAINMEMPAGEREAD);
435 Dataflash_SendAddressBytes(CurrDFPage, 0);
436 Dataflash_SendByte(0x00);
437 Dataflash_SendByte(0x00);
438 Dataflash_SendByte(0x00);
439 Dataflash_SendByte(0x00);
440 }
441
442 /* Read one 16-byte chunk of data from the Dataflash */
443 for (uint8_t ByteNum = 0; ByteNum < 16; ByteNum++)
444 *(BufferPtr++) = Dataflash_ReceiveByte();
445
446 /* Increment the Dataflash page 16 byte block counter */
447 CurrDFPageByteDiv16++;
448
449 /* Increment the block 16 byte block counter */
450 BytesInBlockDiv16++;
451 }
452
453 /* Decrement the blocks remaining counter */
454 TotalBlocks--;
455 }
456
457 /* Deselect all Dataflash chips */
458 Dataflash_DeselectChip();
459}
460
461/** Disables the Dataflash memory write protection bits on the board Dataflash ICs, if enabled. */
462void DataflashManager_ResetDataflashProtections(void)
463{
464 /* Select first Dataflash chip, send the read status register command */
465 Dataflash_SelectChip(DATAFLASH_CHIP1);
466 Dataflash_SendByte(DF_CMD_GETSTATUS);
467
468 /* Check if sector protection is enabled */
469 if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
470 {
471 Dataflash_ToggleSelectedChipCS();
472
473 /* Send the commands to disable sector protection */
474 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
475 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
476 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
477 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
478 }
479
480 /* Select second Dataflash chip (if present on selected board), send read status register command */
481 #if (DATAFLASH_TOTALCHIPS == 2)
482 Dataflash_SelectChip(DATAFLASH_CHIP2);
483 Dataflash_SendByte(DF_CMD_GETSTATUS);
484
485 /* Check if sector protection is enabled */
486 if (Dataflash_ReceiveByte() & DF_STATUS_SECTORPROTECTION_ON)
487 {
488 Dataflash_ToggleSelectedChipCS();
489
490 /* Send the commands to disable sector protection */
491 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[0]);
492 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[1]);
493 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[2]);
494 Dataflash_SendByte(DF_CMD_SECTORPROTECTIONOFF[3]);
495 }
496 #endif
497
498 /* Deselect current Dataflash chip */
499 Dataflash_DeselectChip();
500}
501
502/** Performs a simple test on the attached Dataflash IC(s) to ensure that they are working.
503 *
504 * \return Boolean \c true if all media chips are working, \c false otherwise
505 */
506bool DataflashManager_CheckDataflashOperation(void)
507{
508 uint8_t ReturnByte;
509
510 /* Test first Dataflash IC is present and responding to commands */
511 Dataflash_SelectChip(DATAFLASH_CHIP1);
512 Dataflash_SendByte(DF_CMD_READMANUFACTURERDEVICEINFO);
513 ReturnByte = Dataflash_ReceiveByte();
514 Dataflash_DeselectChip();
515
516 /* If returned data is invalid, fail the command */
517 if (ReturnByte != DF_MANUFACTURER_ATMEL)
518 return false;
519
520 #if (DATAFLASH_TOTALCHIPS == 2)
521 /* Test second Dataflash IC is present and responding to commands */
522 Dataflash_SelectChip(DATAFLASH_CHIP2);
523 Dataflash_SendByte(DF_CMD_READMANUFACTURERDEVICEINFO);
524 ReturnByte = Dataflash_ReceiveByte();
525 Dataflash_DeselectChip();
526
527 /* If returned data is invalid, fail the command */
528 if (ReturnByte != DF_MANUFACTURER_ATMEL)
529 return false;
530 #endif
531
532 return true;
533}
534
diff --git a/lib/lufa/Projects/Webserver/Lib/DataflashManager.h b/lib/lufa/Projects/Webserver/Lib/DataflashManager.h
deleted file mode 100644
index 367fbac8c..000000000
--- a/lib/lufa/Projects/Webserver/Lib/DataflashManager.h
+++ /dev/null
@@ -1,87 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * Header file for DataflashManager.c.
34 */
35
36#ifndef _DATAFLASH_MANAGER_H_
37#define _DATAFLASH_MANAGER_H_
38
39 /* Includes: */
40 #include <avr/io.h>
41
42 #include "../Descriptors.h"
43
44 #include <LUFA/Common/Common.h>
45 #include <LUFA/Drivers/USB/USB.h>
46 #include <LUFA/Drivers/Board/Dataflash.h>
47
48 /* Preprocessor Checks: */
49 #if (DATAFLASH_PAGE_SIZE % 16)
50 #error Dataflash page size must be a multiple of 16 bytes.
51 #endif
52
53 /* Defines: */
54 /** Total number of bytes of the storage medium, comprised of one or more Dataflash ICs. */
55 #define VIRTUAL_MEMORY_BYTES ((uint32_t)DATAFLASH_PAGES * DATAFLASH_PAGE_SIZE * DATAFLASH_TOTALCHIPS)
56
57 /** Block size of the device. This is kept at 512 to remain compatible with the OS despite the underlying
58 * storage media (Dataflash) using a different native block size. Do not change this value.
59 */
60 #define VIRTUAL_MEMORY_BLOCK_SIZE 512
61
62 /** Total number of blocks of the virtual memory for reporting to the host as the device's total capacity. Do not
63 * change this value; change VIRTUAL_MEMORY_BYTES instead to alter the media size.
64 */
65 #define VIRTUAL_MEMORY_BLOCKS (VIRTUAL_MEMORY_BYTES / VIRTUAL_MEMORY_BLOCK_SIZE)
66
67 /** Indicates if the disk is write protected or not. */
68 #define DISK_READ_ONLY false
69
70 /* Function Prototypes: */
71 void DataflashManager_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
72 const uint32_t BlockAddress,
73 uint16_t TotalBlocks);
74 void DataflashManager_ReadBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
75 const uint32_t BlockAddress,
76 uint16_t TotalBlocks);
77 void DataflashManager_WriteBlocks_RAM(const uint32_t BlockAddress,
78 uint16_t TotalBlocks,
79 const uint8_t* BufferPtr) ATTR_NON_NULL_PTR_ARG(3);
80 void DataflashManager_ReadBlocks_RAM(const uint32_t BlockAddress,
81 uint16_t TotalBlocks,
82 uint8_t* BufferPtr) ATTR_NON_NULL_PTR_ARG(3);
83 void DataflashManager_ResetDataflashProtections(void);
84 bool DataflashManager_CheckDataflashOperation(void);
85
86#endif
87
diff --git a/lib/lufa/Projects/Webserver/Lib/FATFs/00readme.txt b/lib/lufa/Projects/Webserver/Lib/FATFs/00readme.txt
deleted file mode 100644
index 80d8843d1..000000000
--- a/lib/lufa/Projects/Webserver/Lib/FATFs/00readme.txt
+++ /dev/null
@@ -1,135 +0,0 @@
1FatFs Module Source Files R0.09a (C)ChaN, 2012
2
3
4FILES
5
6 ffconf.h Configuration file for FatFs module.
7 ff.h Common include file for FatFs and application module.
8 ff.c FatFs module.
9 diskio.h Common include file for FatFs and disk I/O module.
10 diskio.c An example of glue function to attach existing disk I/O module to FatFs.
11 integer.h Integer type definitions for FatFs.
12 option Optional external functions.
13
14 Low level disk I/O module is not included in this archive because the FatFs
15 module is only a generic file system layer and not depend on any specific
16 storage device. You have to provide a low level disk I/O module that written
17 to control your storage device.
18
19
20
21AGREEMENTS
22
23 FatFs module is an open source software to implement FAT file system to
24 small embedded systems. This is a free software and is opened for education,
25 research and commercial developments under license policy of following trems.
26
27 Copyright (C) 2012, ChaN, all right reserved.
28
29 * The FatFs module is a free software and there is NO WARRANTY.
30 * No restriction on use. You can use, modify and redistribute it for
31 personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
32 * Redistributions of source code must retain the above copyright notice.
33
34
35
36REVISION HISTORY
37
38 Feb 26, 2006 R0.00 Prototype
39
40 Apr 29, 2006 R0.01 First release.
41
42 Jun 01, 2006 R0.02 Added FAT12.
43 Removed unbuffered mode.
44 Fixed a problem on small (<32M) patition.
45
46 Jun 10, 2006 R0.02a Added a configuration option _FS_MINIMUM.
47
48 Sep 22, 2006 R0.03 Added f_rename.
49 Changed option _FS_MINIMUM to _FS_MINIMIZE.
50
51 Dec 11, 2006 R0.03a Improved cluster scan algolithm to write files fast.
52 Fixed f_mkdir creates incorrect directory on FAT32.
53
54 Feb 04, 2007 R0.04 Supported multiple drive system. (FatFs)
55 Changed some APIs for multiple drive system.
56 Added f_mkfs. (FatFs)
57 Added _USE_FAT32 option. (Tiny-FatFs)
58
59 Apr 01, 2007 R0.04a Supported multiple partitions on a plysical drive. (FatFs)
60 Fixed an endian sensitive code in f_mkfs. (FatFs)
61 Added a capability of extending the file size to f_lseek.
62 Added minimization level 3.
63 Fixed a problem that can collapse a sector when recreate an
64 existing file in any sub-directory at non FAT32 cfg. (Tiny-FatFs)
65
66 May 05, 2007 R0.04b Added _USE_NTFLAG option.
67 Added FSInfo support.
68 Fixed some problems corresponds to FAT32. (Tiny-FatFs)
69 Fixed DBCS name can result FR_INVALID_NAME.
70 Fixed short seek (0 < ofs <= csize) collapses the file object.
71
72 Aug 25, 2007 R0.05 Changed arguments of f_read, f_write.
73 Changed arguments of f_mkfs. (FatFs)
74 Fixed f_mkfs on FAT32 creates incorrect FSInfo. (FatFs)
75 Fixed f_mkdir on FAT32 creates incorrect directory. (FatFs)
76
77 Feb 03, 2008 R0.05a Added f_truncate().
78 Added f_utime().
79 Fixed off by one error at FAT sub-type determination.
80 Fixed btr in f_read() can be mistruncated.
81 Fixed cached sector is not flushed when create and close without write.
82
83 Apr 01, 2008 R0.06 Added f_forward(). (Tiny-FatFs)
84 Added string functions: fputc(), fputs(), fprintf() and fgets().
85 Improved performance of f_lseek() on move to the same or following cluster.
86
87 Apr 01, 2009, R0.07 Merged Tiny-FatFs as a buffer configuration option.
88 Added long file name support.
89 Added multiple code page support.
90 Added re-entrancy for multitask operation.
91 Added auto cluster size selection to f_mkfs().
92 Added rewind option to f_readdir().
93 Changed result code of critical errors.
94 Renamed string functions to avoid name collision.
95
96 Apr 14, 2009, R0.07a Separated out OS dependent code on reentrant cfg.
97 Added multiple sector size support.
98
99 Jun 21, 2009, R0.07c Fixed f_unlink() may return FR_OK on error.
100 Fixed wrong cache control in f_lseek().
101 Added relative path feature.
102 Added f_chdir().
103 Added f_chdrive().
104 Added proper case conversion for extended characters.
105
106 Nov 03, 2009 R0.07e Separated out configuration options from ff.h to ffconf.h.
107 Added a configuration option, _LFN_UNICODE.
108 Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
109 Fixed name matching error on the 13 char boundary.
110 Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
111
112 May 15, 2010, R0.08 Added a memory configuration option. (_USE_LFN)
113 Added file lock feature. (_FS_SHARE)
114 Added fast seek feature. (_USE_FASTSEEK)
115 Changed some types on the API, XCHAR->TCHAR.
116 Changed fname member in the FILINFO structure on Unicode cfg.
117 String functions support UTF-8 encoding files on Unicode cfg.
118
119 Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2)
120 Added sector erase feature. (_USE_ERASE)
121 Moved file lock semaphore table from fs object to the bss.
122 Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'.
123 Fixed f_mkfs() creates wrong FAT32 volume.
124
125 Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write().
126 f_lseek() reports required table size on creating CLMP.
127 Extended format syntax of f_printf function.
128 Ignores duplicated directory separators in given path names.
129
130 Sep 06,'11 R0.09 f_mkfs() supports multiple partition to finish the multiple partition feature.
131 Added f_fdisk(). (_MULTI_PARTITION = 2)
132
133 Aug 27,'12 R0.09a Fixed assertion failure due to OS/2 EA on FAT12/16.
134 Changed API rejects null object pointer to avoid crash.
135 Changed option name _FS_SHARE to _FS_LOCK.
diff --git a/lib/lufa/Projects/Webserver/Lib/FATFs/diskio.c b/lib/lufa/Projects/Webserver/Lib/FATFs/diskio.c
deleted file mode 100644
index b119b1a40..000000000
--- a/lib/lufa/Projects/Webserver/Lib/FATFs/diskio.c
+++ /dev/null
@@ -1,65 +0,0 @@
1/*-----------------------------------------------------------------------*/
2/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
3/*-----------------------------------------------------------------------*/
4/* This is a stub disk I/O module that acts as front end of the existing */
5/* disk I/O modules and attach it to FatFs module with common interface. */
6/*-----------------------------------------------------------------------*/
7
8#include "diskio.h"
9
10/*-----------------------------------------------------------------------*/
11/* Initialize a Drive */
12
13DSTATUS disk_initialize (
14 BYTE drv /* Physical drive number (0..) */
15)
16{
17 return FR_OK;
18}
19
20
21
22/*-----------------------------------------------------------------------*/
23/* Return Disk Status */
24
25DSTATUS disk_status (
26 BYTE drv /* Physical drive number (0..) */
27)
28{
29 return FR_OK;
30}
31
32
33
34/*-----------------------------------------------------------------------*/
35/* Read Sector(s) */
36
37DRESULT disk_read (
38 BYTE drv, /* Physical drive number (0..) */
39 BYTE *buff, /* Data buffer to store read data */
40 DWORD sector, /* Sector address (LBA) */
41 BYTE count /* Number of sectors to read (1..128) */
42)
43{
44 DataflashManager_ReadBlocks_RAM(sector, count, buff);
45 return RES_OK;
46}
47
48
49
50/*-----------------------------------------------------------------------*/
51/* Write Sector(s) */
52
53#if _READONLY == 0
54DRESULT disk_write (
55 BYTE drv, /* Physical drive number (0..) */
56 const BYTE *buff, /* Data to be written */
57 DWORD sector, /* Sector address (LBA) */
58 BYTE count /* Number of sectors to write (1..128) */
59)
60{
61 DataflashManager_WriteBlocks_RAM(sector, count, buff);
62 return RES_OK;
63}
64#endif /* _READONLY */
65
diff --git a/lib/lufa/Projects/Webserver/Lib/FATFs/diskio.h b/lib/lufa/Projects/Webserver/Lib/FATFs/diskio.h
deleted file mode 100644
index 65e3048a0..000000000
--- a/lib/lufa/Projects/Webserver/Lib/FATFs/diskio.h
+++ /dev/null
@@ -1,52 +0,0 @@
1/*-----------------------------------------------------------------------
2/ Low level disk interface module include file
3/-----------------------------------------------------------------------*/
4
5#ifndef _DISKIO_DEFINED
6#define _DISKIO_DEFINED
7
8#ifdef __cplusplus
9extern "C" {
10#endif
11
12#include "integer.h"
13#include "ff.h"
14
15#include "../DataflashManager.h"
16
17
18/* Status of Disk Functions */
19typedef BYTE DSTATUS;
20
21/* Results of Disk Functions */
22typedef enum {
23 RES_OK = 0, /* 0: Successful */
24 RES_ERROR, /* 1: R/W Error */
25 RES_WRPRT, /* 2: Write Protected */
26 RES_NOTRDY, /* 3: Not Ready */
27 RES_PARERR /* 4: Invalid Parameter */
28} DRESULT;
29
30
31/*---------------------------------------*/
32/* Prototypes for disk control functions */
33
34DSTATUS disk_initialize (BYTE);
35DSTATUS disk_status (BYTE);
36DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
37DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
38DRESULT disk_ioctl (BYTE, BYTE, void*);
39
40
41/* Disk Status Bits (DSTATUS) */
42
43#define STA_NOINIT 0x01 /* Drive not initialized */
44#define STA_NODISK 0x02 /* No medium in the drive */
45#define STA_PROTECT 0x04 /* Write protected */
46
47
48#ifdef __cplusplus
49}
50#endif
51
52#endif
diff --git a/lib/lufa/Projects/Webserver/Lib/FATFs/ff.c b/lib/lufa/Projects/Webserver/Lib/FATFs/ff.c
deleted file mode 100644
index 2f58adf83..000000000
--- a/lib/lufa/Projects/Webserver/Lib/FATFs/ff.c
+++ /dev/null
@@ -1,4139 +0,0 @@
1/*----------------------------------------------------------------------------/
2/ FatFs - FAT file system module R0.09a (C)ChaN, 2012
3/-----------------------------------------------------------------------------/
4/ FatFs module is a generic FAT file system module for small embedded systems.
5/ This is a free software that opened for education, research and commercial
6/ developments under license policy of following terms.
7/
8/ Copyright (C) 2012, ChaN, all right reserved.
9/
10/ * The FatFs module is a free software and there is NO WARRANTY.
11/ * No restriction on use. You can use, modify and redistribute it for
12/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
13/ * Redistributions of source code must retain the above copyright notice.
14/
15/-----------------------------------------------------------------------------/
16/ Feb 26,'06 R0.00 Prototype.
17/
18/ Apr 29,'06 R0.01 First stable version.
19/
20/ Jun 01,'06 R0.02 Added FAT12 support.
21/ Removed unbuffered mode.
22/ Fixed a problem on small (<32M) partition.
23/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
24/
25/ Sep 22,'06 R0.03 Added f_rename().
26/ Changed option _FS_MINIMUM to _FS_MINIMIZE.
27/ Dec 11,'06 R0.03a Improved cluster scan algorithm to write files fast.
28/ Fixed f_mkdir() creates incorrect directory on FAT32.
29/
30/ Feb 04,'07 R0.04 Supported multiple drive system.
31/ Changed some interfaces for multiple drive system.
32/ Changed f_mountdrv() to f_mount().
33/ Added f_mkfs().
34/ Apr 01,'07 R0.04a Supported multiple partitions on a physical drive.
35/ Added a capability of extending file size to f_lseek().
36/ Added minimization level 3.
37/ Fixed an endian sensitive code in f_mkfs().
38/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
39/ Added FSInfo support.
40/ Fixed DBCS name can result FR_INVALID_NAME.
41/ Fixed short seek (<= csize) collapses the file object.
42/
43/ Aug 25,'07 R0.05 Changed arguments of f_read(), f_write() and f_mkfs().
44/ Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
45/ Fixed f_mkdir() on FAT32 creates incorrect directory.
46/ Feb 03,'08 R0.05a Added f_truncate() and f_utime().
47/ Fixed off by one error at FAT sub-type determination.
48/ Fixed btr in f_read() can be mistruncated.
49/ Fixed cached sector is not flushed when create and close without write.
50/
51/ Apr 01,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets().
52/ Improved performance of f_lseek() on moving to the same or following cluster.
53/
54/ Apr 01,'09 R0.07 Merged Tiny-FatFs as a configuration option. (_FS_TINY)
55/ Added long file name feature.
56/ Added multiple code page feature.
57/ Added re-entrancy for multitask operation.
58/ Added auto cluster size selection to f_mkfs().
59/ Added rewind option to f_readdir().
60/ Changed result code of critical errors.
61/ Renamed string functions to avoid name collision.
62/ Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg.
63/ Added multiple sector size feature.
64/ Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error.
65/ Fixed wrong cache control in f_lseek().
66/ Added relative path feature.
67/ Added f_chdir() and f_chdrive().
68/ Added proper case conversion to extended char.
69/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
70/ Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
71/ Fixed name matching error on the 13 char boundary.
72/ Added a configuration option, _LFN_UNICODE.
73/ Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
74/
75/ May 15,'10 R0.08 Added a memory configuration option. (_USE_LFN = 3)
76/ Added file lock feature. (_FS_SHARE)
77/ Added fast seek feature. (_USE_FASTSEEK)
78/ Changed some types on the API, XCHAR->TCHAR.
79/ Changed fname member in the FILINFO structure on Unicode cfg.
80/ String functions support UTF-8 encoding files on Unicode cfg.
81/ Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2)
82/ Added sector erase feature. (_USE_ERASE)
83/ Moved file lock semaphore table from fs object to the bss.
84/ Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'.
85/ Fixed f_mkfs() creates wrong FAT32 volume.
86/ Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write().
87/ f_lseek() reports required table size on creating CLMP.
88/ Extended format syntax of f_printf function.
89/ Ignores duplicated directory separators in given path name.
90/
91/ Sep 06,'11 R0.09 f_mkfs() supports multiple partition to finish the multiple partition feature.
92/ Added f_fdisk(). (_MULTI_PARTITION = 2)
93/ Aug 27,'12 R0.09a Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
94/ Changed f_open() and f_opendir reject null object pointer to avoid crash.
95/ Changed option name _FS_SHARE to _FS_LOCK.
96/---------------------------------------------------------------------------*/
97
98#include "ff.h" /* FatFs configurations and declarations */
99#include "diskio.h" /* Declarations of low level disk I/O functions */
100
101
102/*--------------------------------------------------------------------------
103
104 Module Private Definitions
105
106---------------------------------------------------------------------------*/
107
108#if _FATFS != 4004 /* Revision ID */
109#error Wrong include file (ff.h).
110#endif
111
112
113/* Definitions on sector size */
114#if _MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096
115#error Wrong sector size.
116#endif
117#if _MAX_SS != 512
118#define SS(fs) ((fs)->ssize) /* Variable sector size */
119#else
120#define SS(fs) 512U /* Fixed sector size */
121#endif
122
123
124/* Reentrancy related */
125#if _FS_REENTRANT
126#if _USE_LFN == 1
127#error Static LFN work area must not be used in re-entrant configuration.
128#endif
129#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; }
130#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; }
131#else
132#define ENTER_FF(fs)
133#define LEAVE_FF(fs, res) return res
134#endif
135
136#define ABORT(fs, res) { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
137
138
139/* File access control feature */
140#if _FS_LOCK
141#if _FS_READONLY
142#error _FS_LOCK must be 0 on read-only cfg.
143#endif
144typedef struct {
145 FATFS *fs; /* File ID 1, volume (NULL:blank entry) */
146 DWORD clu; /* File ID 2, directory */
147 WORD idx; /* File ID 3, directory index */
148 WORD ctr; /* File open counter, 0:none, 0x01..0xFF:read open count, 0x100:write mode */
149} FILESEM;
150#endif
151
152
153
154/* DBCS code ranges and SBCS extend char conversion table */
155
156#if _CODE_PAGE == 932 /* Japanese Shift-JIS */
157#define _DF1S 0x81 /* DBC 1st byte range 1 start */
158#define _DF1E 0x9F /* DBC 1st byte range 1 end */
159#define _DF2S 0xE0 /* DBC 1st byte range 2 start */
160#define _DF2E 0xFC /* DBC 1st byte range 2 end */
161#define _DS1S 0x40 /* DBC 2nd byte range 1 start */
162#define _DS1E 0x7E /* DBC 2nd byte range 1 end */
163#define _DS2S 0x80 /* DBC 2nd byte range 2 start */
164#define _DS2E 0xFC /* DBC 2nd byte range 2 end */
165
166#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
167#define _DF1S 0x81
168#define _DF1E 0xFE
169#define _DS1S 0x40
170#define _DS1E 0x7E
171#define _DS2S 0x80
172#define _DS2E 0xFE
173
174#elif _CODE_PAGE == 949 /* Korean */
175#define _DF1S 0x81
176#define _DF1E 0xFE
177#define _DS1S 0x41
178#define _DS1E 0x5A
179#define _DS2S 0x61
180#define _DS2E 0x7A
181#define _DS3S 0x81
182#define _DS3E 0xFE
183
184#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
185#define _DF1S 0x81
186#define _DF1E 0xFE
187#define _DS1S 0x40
188#define _DS1E 0x7E
189#define _DS2S 0xA1
190#define _DS2E 0xFE
191
192#elif _CODE_PAGE == 437 /* U.S. (OEM) */
193#define _DF1S 0
194#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
195 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
196 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
197 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
198
199#elif _CODE_PAGE == 720 /* Arabic (OEM) */
200#define _DF1S 0
201#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
202 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
203 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
204 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
205
206#elif _CODE_PAGE == 737 /* Greek (OEM) */
207#define _DF1S 0
208#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
209 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
210 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
211 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
212
213#elif _CODE_PAGE == 775 /* Baltic (OEM) */
214#define _DF1S 0
215#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
216 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
217 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
218 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
219
220#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */
221#define _DF1S 0
222#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
223 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
224 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
225 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
226
227#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */
228#define _DF1S 0
229#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \
230 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
231 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
232 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
233
234#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */
235#define _DF1S 0
236#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
237 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
238 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
239 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
240
241#elif _CODE_PAGE == 857 /* Turkish (OEM) */
242#define _DF1S 0
243#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
244 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
245 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
246 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
247
248#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */
249#define _DF1S 0
250#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
251 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
252 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
253 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
254
255#elif _CODE_PAGE == 862 /* Hebrew (OEM) */
256#define _DF1S 0
257#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
258 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
259 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
260 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
261
262#elif _CODE_PAGE == 866 /* Russian (OEM) */
263#define _DF1S 0
264#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
265 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
266 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
267 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
268
269#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */
270#define _DF1S 0
271#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
272 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
273 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
274 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
275
276#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
277#define _DF1S 0
278#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
279 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \
280 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
281 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
282
283#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
284#define _DF1S 0
285#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
286 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \
287 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
288 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF}
289
290#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
291#define _DF1S 0
292#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \
293 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
294 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
295 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
296
297#elif _CODE_PAGE == 1253 /* Greek (Windows) */
298#define _DF1S 0
299#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
300 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
301 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \
302 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF}
303
304#elif _CODE_PAGE == 1254 /* Turkish (Windows) */
305#define _DF1S 0
306#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \
307 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
308 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
309 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
310
311#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
312#define _DF1S 0
313#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
314 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
315 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
316 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
317
318#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
319#define _DF1S 0
320#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
321 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
322 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
323 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
324
325#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
326#define _DF1S 0
327#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
328 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
329 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
330 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
331
332#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
333#define _DF1S 0
334#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
335 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
336 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
337 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
338
339#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
340#if _USE_LFN
341#error Cannot use LFN feature without valid code page.
342#endif
343#define _DF1S 0
344
345#else
346#error Unknown code page
347
348#endif
349
350
351/* Character code support macros */
352#define IsUpper(c) (((c)>='A')&&((c)<='Z'))
353#define IsLower(c) (((c)>='a')&&((c)<='z'))
354#define IsDigit(c) (((c)>='0')&&((c)<='9'))
355
356#if _DF1S /* Code page is DBCS */
357
358#ifdef _DF2S /* Two 1st byte areas */
359#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
360#else /* One 1st byte area */
361#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
362#endif
363
364#ifdef _DS3S /* Three 2nd byte areas */
365#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
366#else /* Two 2nd byte areas */
367#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
368#endif
369
370#else /* Code page is SBCS */
371
372#define IsDBCS1(c) 0
373#define IsDBCS2(c) 0
374
375#endif /* _DF1S */
376
377
378/* Name status flags */
379#define NS 11 /* Index of name status byte in fn[] */
380#define NS_LOSS 0x01 /* Out of 8.3 format */
381#define NS_LFN 0x02 /* Force to create LFN entry */
382#define NS_LAST 0x04 /* Last segment */
383#define NS_BODY 0x08 /* Lower case flag (body) */
384#define NS_EXT 0x10 /* Lower case flag (ext) */
385#define NS_DOT 0x20 /* Dot entry */
386
387
388/* FAT sub-type boundaries */
389/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */
390#define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */
391#define MIN_FAT32 65526 /* Minimum number of clusters for FAT32 */
392
393
394/* FatFs refers the members in the FAT structures as byte array instead of
395/ structure member because the structure is not binary compatible between
396/ different platforms */
397
398#define BS_jmpBoot 0 /* Jump instruction (3) */
399#define BS_OEMName 3 /* OEM name (8) */
400#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */
401#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */
402#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */
403#define BPB_NumFATs 16 /* Number of FAT copies (1) */
404#define BPB_RootEntCnt 17 /* Number of root dir entries for FAT12/16 (2) */
405#define BPB_TotSec16 19 /* Volume size [sector] (2) */
406#define BPB_Media 21 /* Media descriptor (1) */
407#define BPB_FATSz16 22 /* FAT size [sector] (2) */
408#define BPB_SecPerTrk 24 /* Track size [sector] (2) */
409#define BPB_NumHeads 26 /* Number of heads (2) */
410#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */
411#define BPB_TotSec32 32 /* Volume size [sector] (4) */
412#define BS_DrvNum 36 /* Physical drive number (2) */
413#define BS_BootSig 38 /* Extended boot signature (1) */
414#define BS_VolID 39 /* Volume serial number (4) */
415#define BS_VolLab 43 /* Volume label (8) */
416#define BS_FilSysType 54 /* File system type (1) */
417#define BPB_FATSz32 36 /* FAT size [sector] (4) */
418#define BPB_ExtFlags 40 /* Extended flags (2) */
419#define BPB_FSVer 42 /* File system version (2) */
420#define BPB_RootClus 44 /* Root dir first cluster (4) */
421#define BPB_FSInfo 48 /* Offset of FSInfo sector (2) */
422#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */
423#define BS_DrvNum32 64 /* Physical drive number (2) */
424#define BS_BootSig32 66 /* Extended boot signature (1) */
425#define BS_VolID32 67 /* Volume serial number (4) */
426#define BS_VolLab32 71 /* Volume label (8) */
427#define BS_FilSysType32 82 /* File system type (1) */
428#define FSI_LeadSig 0 /* FSI: Leading signature (4) */
429#define FSI_StrucSig 484 /* FSI: Structure signature (4) */
430#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */
431#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */
432#define MBR_Table 446 /* MBR: Partition table offset (2) */
433#define SZ_PTE 16 /* MBR: Size of a partition table entry */
434#define BS_55AA 510 /* Boot sector signature (2) */
435
436#define DIR_Name 0 /* Short file name (11) */
437#define DIR_Attr 11 /* Attribute (1) */
438#define DIR_NTres 12 /* NT flag (1) */
439#define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */
440#define DIR_CrtTime 14 /* Created time (2) */
441#define DIR_CrtDate 16 /* Created date (2) */
442#define DIR_LstAccDate 18 /* Last accessed date (2) */
443#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */
444#define DIR_WrtTime 22 /* Modified time (2) */
445#define DIR_WrtDate 24 /* Modified date (2) */
446#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */
447#define DIR_FileSize 28 /* File size (4) */
448#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */
449#define LDIR_Attr 11 /* LFN attribute (1) */
450#define LDIR_Type 12 /* LFN type (1) */
451#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */
452#define LDIR_FstClusLO 26 /* Filled by zero (0) */
453#define SZ_DIR 32 /* Size of a directory entry */
454#define LLE 0x40 /* Last long entry flag in LDIR_Ord */
455#define DDE 0xE5 /* Deleted directory entry mark in DIR_Name[0] */
456#define NDDE 0x05 /* Replacement of the character collides with DDE */
457
458
459/*------------------------------------------------------------*/
460/* Module private work area */
461/*------------------------------------------------------------*/
462/* Note that uninitialized variables with static duration are
463/ zeroed/nulled at start-up. If not, the compiler or start-up
464/ routine is out of ANSI-C standard.
465*/
466
467#if _VOLUMES
468static
469FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */
470#else
471#error Number of volumes must not be 0.
472#endif
473
474static
475WORD Fsid; /* File system mount ID */
476
477#if _FS_RPATH
478static
479BYTE CurrVol; /* Current drive */
480#endif
481
482#if _FS_LOCK
483static
484FILESEM Files[_FS_LOCK]; /* File lock semaphores */
485#endif
486
487#if _USE_LFN == 0 /* No LFN feature */
488#define DEF_NAMEBUF BYTE sfn[12]
489#define INIT_BUF(dobj) (dobj).fn = sfn
490#define FREE_BUF()
491
492#elif _USE_LFN == 1 /* LFN feature with static working buffer */
493static WCHAR LfnBuf[_MAX_LFN+1];
494#define DEF_NAMEBUF BYTE sfn[12]
495#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
496#define FREE_BUF()
497
498#elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */
499#define DEF_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1]
500#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; }
501#define FREE_BUF()
502
503#elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */
504#define DEF_NAMEBUF BYTE sfn[12]; WCHAR *lfn
505#define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); \
506 if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); \
507 (dobj).lfn = lfn; (dobj).fn = sfn; }
508#define FREE_BUF() ff_memfree(lfn)
509
510#else
511#error Wrong LFN configuration.
512#endif
513
514
515
516
517/*--------------------------------------------------------------------------
518
519 Module Private Functions
520
521---------------------------------------------------------------------------*/
522
523
524/*-----------------------------------------------------------------------*/
525/* String functions */
526/*-----------------------------------------------------------------------*/
527
528/* Copy memory to memory */
529static
530void mem_cpy (void* dst, const void* src, UINT cnt) {
531 BYTE *d = (BYTE*)dst;
532 const BYTE *s = (const BYTE*)src;
533
534#if _WORD_ACCESS == 1
535 while (cnt >= sizeof (int)) {
536 *(int*)d = *(int*)s;
537 d += sizeof (int); s += sizeof (int);
538 cnt -= sizeof (int);
539 }
540#endif
541 while (cnt--)
542 *d++ = *s++;
543}
544
545/* Fill memory */
546static
547void mem_set (void* dst, int val, UINT cnt) {
548 BYTE *d = (BYTE*)dst;
549
550 while (cnt--)
551 *d++ = (BYTE)val;
552}
553
554/* Compare memory to memory */
555static
556int mem_cmp (const void* dst, const void* src, UINT cnt) {
557 const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
558 int r = 0;
559
560 while (cnt-- && (r = *d++ - *s++) == 0) ;
561 return r;
562}
563
564/* Check if chr is contained in the string */
565static
566int chk_chr (const char* str, int chr) {
567 while (*str && *str != chr) str++;
568 return *str;
569}
570
571
572
573/*-----------------------------------------------------------------------*/
574/* Request/Release grant to access the volume */
575/*-----------------------------------------------------------------------*/
576#if _FS_REENTRANT
577
578static
579int lock_fs (
580 FATFS *fs /* File system object */
581)
582{
583 return ff_req_grant(fs->sobj);
584}
585
586
587static
588void unlock_fs (
589 FATFS *fs, /* File system object */
590 FRESULT res /* Result code to be returned */
591)
592{
593 if (fs &&
594 res != FR_NOT_ENABLED &&
595 res != FR_INVALID_DRIVE &&
596 res != FR_INVALID_OBJECT &&
597 res != FR_TIMEOUT) {
598 ff_rel_grant(fs->sobj);
599 }
600}
601#endif
602
603
604
605/*-----------------------------------------------------------------------*/
606/* File lock control functions */
607/*-----------------------------------------------------------------------*/
608#if _FS_LOCK
609
610static
611FRESULT chk_lock ( /* Check if the file can be accessed */
612 DIR* dj, /* Directory object pointing the file to be checked */
613 int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
614)
615{
616 UINT i, be;
617
618 /* Search file semaphore table */
619 for (i = be = 0; i < _FS_LOCK; i++) {
620 if (Files[i].fs) { /* Existing entry */
621 if (Files[i].fs == dj->fs && /* Check if the file matched with an open file */
622 Files[i].clu == dj->sclust &&
623 Files[i].idx == dj->index) break;
624 } else { /* Blank entry */
625 be++;
626 }
627 }
628 if (i == _FS_LOCK) /* The file is not opened */
629 return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new file? */
630
631 /* The file has been opened. Reject any open against writing file and all write mode open */
632 return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
633}
634
635
636static
637int enq_lock (void) /* Check if an entry is available for a new file */
638{
639 UINT i;
640
641 for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;
642 return (i == _FS_LOCK) ? 0 : 1;
643}
644
645
646static
647UINT inc_lock ( /* Increment file open counter and returns its index (0:int error) */
648 DIR* dj, /* Directory object pointing the file to register or increment */
649 int acc /* Desired access mode (0:Read, !0:Write) */
650)
651{
652 UINT i;
653
654
655 for (i = 0; i < _FS_LOCK; i++) { /* Find the file */
656 if (Files[i].fs == dj->fs &&
657 Files[i].clu == dj->sclust &&
658 Files[i].idx == dj->index) break;
659 }
660
661 if (i == _FS_LOCK) { /* Not opened. Register it as new. */
662 for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;
663 if (i == _FS_LOCK) return 0; /* No space to register (int err) */
664 Files[i].fs = dj->fs;
665 Files[i].clu = dj->sclust;
666 Files[i].idx = dj->index;
667 Files[i].ctr = 0;
668 }
669
670 if (acc && Files[i].ctr) return 0; /* Access violation (int err) */
671
672 Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */
673
674 return i + 1;
675}
676
677
678static
679FRESULT dec_lock ( /* Decrement file open counter */
680 UINT i /* Semaphore index */
681)
682{
683 WORD n;
684 FRESULT res;
685
686
687 if (--i < _FS_LOCK) {
688 n = Files[i].ctr;
689 if (n == 0x100) n = 0;
690 if (n) n--;
691 Files[i].ctr = n;
692 if (!n) Files[i].fs = 0;
693 res = FR_OK;
694 } else {
695 res = FR_INT_ERR;
696 }
697 return res;
698}
699
700
701static
702void clear_lock ( /* Clear lock entries of the volume */
703 FATFS *fs
704)
705{
706 UINT i;
707
708 for (i = 0; i < _FS_LOCK; i++) {
709 if (Files[i].fs == fs) Files[i].fs = 0;
710 }
711}
712#endif
713
714
715
716/*-----------------------------------------------------------------------*/
717/* Change window offset */
718/*-----------------------------------------------------------------------*/
719
720static
721FRESULT move_window (
722 FATFS *fs, /* File system object */
723 DWORD sector /* Sector number to make appearance in the fs->win[] */
724) /* Move to zero only writes back dirty window */
725{
726 DWORD wsect;
727
728
729 wsect = fs->winsect;
730 if (wsect != sector) { /* Changed current window */
731#if !_FS_READONLY
732 if (fs->wflag) { /* Write back dirty window if needed */
733 if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK)
734 return FR_DISK_ERR;
735 fs->wflag = 0;
736 if (wsect < (fs->fatbase + fs->fsize)) { /* In FAT area */
737 BYTE nf;
738 for (nf = fs->n_fats; nf > 1; nf--) { /* Reflect the change to all FAT copies */
739 wsect += fs->fsize;
740 disk_write(fs->drv, fs->win, wsect, 1);
741 }
742 }
743 }
744#endif
745 if (sector) {
746 if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK)
747 return FR_DISK_ERR;
748 fs->winsect = sector;
749 }
750 }
751
752 return FR_OK;
753}
754
755
756
757
758/*-----------------------------------------------------------------------*/
759/* Clean-up cached data */
760/*-----------------------------------------------------------------------*/
761#if !_FS_READONLY
762static
763FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */
764 FATFS *fs /* File system object */
765)
766{
767 FRESULT res;
768
769
770 res = move_window(fs, 0);
771 if (res == FR_OK) {
772 /* Update FSInfo sector if needed */
773 if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
774 fs->winsect = 0;
775 /* Create FSInfo structure */
776 mem_set(fs->win, 0, 512);
777 ST_WORD(fs->win+BS_55AA, 0xAA55);
778 ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
779 ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
780 ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
781 ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
782 /* Write it into the FSInfo sector */
783 disk_write(fs->drv, fs->win, fs->fsi_sector, 1);
784 fs->fsi_flag = 0;
785 }
786 /* Make sure that no pending write process in the physical drive */
787 if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK)
788 res = FR_DISK_ERR;
789 }
790
791 return res;
792}
793#endif
794
795
796
797
798/*-----------------------------------------------------------------------*/
799/* Get sector# from cluster# */
800/*-----------------------------------------------------------------------*/
801
802
803DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
804 FATFS *fs, /* File system object */
805 DWORD clst /* Cluster# to be converted */
806)
807{
808 clst -= 2;
809 if (clst >= (fs->n_fatent - 2)) return 0; /* Invalid cluster# */
810 return clst * fs->csize + fs->database;
811}
812
813
814
815
816/*-----------------------------------------------------------------------*/
817/* FAT access - Read value of a FAT entry */
818/*-----------------------------------------------------------------------*/
819
820
821DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */
822 FATFS *fs, /* File system object */
823 DWORD clst /* Cluster# to get the link information */
824)
825{
826 UINT wc, bc;
827 BYTE *p;
828
829
830 if (clst < 2 || clst >= fs->n_fatent) /* Check range */
831 return 1;
832
833 switch (fs->fs_type) {
834 case FS_FAT12 :
835 bc = (UINT)clst; bc += bc / 2;
836 if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
837 wc = fs->win[bc % SS(fs)]; bc++;
838 if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
839 wc |= fs->win[bc % SS(fs)] << 8;
840 return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
841
842 case FS_FAT16 :
843 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)))) break;
844 p = &fs->win[clst * 2 % SS(fs)];
845 return LD_WORD(p);
846
847 case FS_FAT32 :
848 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)))) break;
849 p = &fs->win[clst * 4 % SS(fs)];
850 return LD_DWORD(p) & 0x0FFFFFFF;
851 }
852
853 return 0xFFFFFFFF; /* An error occurred at the disk I/O layer */
854}
855
856
857
858
859/*-----------------------------------------------------------------------*/
860/* FAT access - Change value of a FAT entry */
861/*-----------------------------------------------------------------------*/
862#if !_FS_READONLY
863
864FRESULT put_fat (
865 FATFS *fs, /* File system object */
866 DWORD clst, /* Cluster# to be changed in range of 2 to fs->n_fatent - 1 */
867 DWORD val /* New value to mark the cluster */
868)
869{
870 UINT bc;
871 BYTE *p;
872 FRESULT res;
873
874
875 if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
876 res = FR_INT_ERR;
877
878 } else {
879 switch (fs->fs_type) {
880 case FS_FAT12 :
881 bc = (UINT)clst; bc += bc / 2;
882 res = move_window(fs, fs->fatbase + (bc / SS(fs)));
883 if (res != FR_OK) break;
884 p = &fs->win[bc % SS(fs)];
885 *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
886 bc++;
887 fs->wflag = 1;
888 res = move_window(fs, fs->fatbase + (bc / SS(fs)));
889 if (res != FR_OK) break;
890 p = &fs->win[bc % SS(fs)];
891 *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
892 break;
893
894 case FS_FAT16 :
895 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
896 if (res != FR_OK) break;
897 p = &fs->win[clst * 2 % SS(fs)];
898 ST_WORD(p, (WORD)val);
899 break;
900
901 case FS_FAT32 :
902 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
903 if (res != FR_OK) break;
904 p = &fs->win[clst * 4 % SS(fs)];
905 val |= LD_DWORD(p) & 0xF0000000;
906 ST_DWORD(p, val);
907 break;
908
909 default :
910 res = FR_INT_ERR;
911 }
912 fs->wflag = 1;
913 }
914
915 return res;
916}
917#endif /* !_FS_READONLY */
918
919
920
921
922/*-----------------------------------------------------------------------*/
923/* FAT handling - Remove a cluster chain */
924/*-----------------------------------------------------------------------*/
925#if !_FS_READONLY
926static
927FRESULT remove_chain (
928 FATFS *fs, /* File system object */
929 DWORD clst /* Cluster# to remove a chain from */
930)
931{
932 FRESULT res;
933 DWORD nxt;
934#if _USE_ERASE
935 DWORD scl = clst, ecl = clst, rt[2];
936#endif
937
938 if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
939 res = FR_INT_ERR;
940
941 } else {
942 res = FR_OK;
943 while (clst < fs->n_fatent) { /* Not a last link? */
944 nxt = get_fat(fs, clst); /* Get cluster status */
945 if (nxt == 0) break; /* Empty cluster? */
946 if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */
947 if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */
948 res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */
949 if (res != FR_OK) break;
950 if (fs->free_clust != 0xFFFFFFFF) { /* Update FSInfo */
951 fs->free_clust++;
952 fs->fsi_flag = 1;
953 }
954#if _USE_ERASE
955 if (ecl + 1 == nxt) { /* Is next cluster contiguous? */
956 ecl = nxt;
957 } else { /* End of contiguous clusters */
958 rt[0] = clust2sect(fs, scl); /* Start sector */
959 rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */
960 disk_ioctl(fs->drv, CTRL_ERASE_SECTOR, rt); /* Erase the block */
961 scl = ecl = nxt;
962 }
963#endif
964 clst = nxt; /* Next cluster */
965 }
966 }
967
968 return res;
969}
970#endif
971
972
973
974
975/*-----------------------------------------------------------------------*/
976/* FAT handling - Stretch or Create a cluster chain */
977/*-----------------------------------------------------------------------*/
978#if !_FS_READONLY
979static
980DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
981 FATFS *fs, /* File system object */
982 DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
983)
984{
985 DWORD cs, ncl, scl;
986 FRESULT res;
987
988
989 if (clst == 0) { /* Create a new chain */
990 scl = fs->last_clust; /* Get suggested start point */
991 if (!scl || scl >= fs->n_fatent) scl = 1;
992 }
993 else { /* Stretch the current chain */
994 cs = get_fat(fs, clst); /* Check the cluster status */
995 if (cs < 2) return 1; /* It is an invalid cluster */
996 if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */
997 scl = clst;
998 }
999
1000 ncl = scl; /* Start cluster */
1001 for (;;) {
1002 ncl++; /* Next cluster */
1003 if (ncl >= fs->n_fatent) { /* Wrap around */
1004 ncl = 2;
1005 if (ncl > scl) return 0; /* No free cluster */
1006 }
1007 cs = get_fat(fs, ncl); /* Get the cluster status */
1008 if (cs == 0) break; /* Found a free cluster */
1009 if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */
1010 return cs;
1011 if (ncl == scl) return 0; /* No free cluster */
1012 }
1013
1014 res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */
1015 if (res == FR_OK && clst != 0) {
1016 res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */
1017 }
1018 if (res == FR_OK) {
1019 fs->last_clust = ncl; /* Update FSINFO */
1020 if (fs->free_clust != 0xFFFFFFFF) {
1021 fs->free_clust--;
1022 fs->fsi_flag = 1;
1023 }
1024 } else {
1025 ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;
1026 }
1027
1028 return ncl; /* Return new cluster number or error code */
1029}
1030#endif /* !_FS_READONLY */
1031
1032
1033
1034/*-----------------------------------------------------------------------*/
1035/* FAT handling - Convert offset into cluster with link map table */
1036/*-----------------------------------------------------------------------*/
1037
1038#if _USE_FASTSEEK
1039static
1040DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */
1041 FIL* fp, /* Pointer to the file object */
1042 DWORD ofs /* File offset to be converted to cluster# */
1043)
1044{
1045 DWORD cl, ncl, *tbl;
1046
1047
1048 tbl = fp->cltbl + 1; /* Top of CLMT */
1049 cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */
1050 for (;;) {
1051 ncl = *tbl++; /* Number of cluters in the fragment */
1052 if (!ncl) return 0; /* End of table? (error) */
1053 if (cl < ncl) break; /* In this fragment? */
1054 cl -= ncl; tbl++; /* Next fragment */
1055 }
1056 return cl + *tbl; /* Return the cluster number */
1057}
1058#endif /* _USE_FASTSEEK */
1059
1060
1061
1062/*-----------------------------------------------------------------------*/
1063/* Directory handling - Set directory index */
1064/*-----------------------------------------------------------------------*/
1065
1066static
1067FRESULT dir_sdi (
1068 DIR *dj, /* Pointer to directory object */
1069 WORD idx /* Index of directory table */
1070)
1071{
1072 DWORD clst;
1073 WORD ic;
1074
1075
1076 dj->index = idx;
1077 clst = dj->sclust;
1078 if (clst == 1 || clst >= dj->fs->n_fatent) /* Check start cluster range */
1079 return FR_INT_ERR;
1080 if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
1081 clst = dj->fs->dirbase;
1082
1083 if (clst == 0) { /* Static table (root-dir in FAT12/16) */
1084 dj->clust = clst;
1085 if (idx >= dj->fs->n_rootdir) /* Index is out of range */
1086 return FR_INT_ERR;
1087 dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */
1088 }
1089 else { /* Dynamic table (sub-dirs or root-dir in FAT32) */
1090 ic = SS(dj->fs) / SZ_DIR * dj->fs->csize; /* Entries per cluster */
1091 while (idx >= ic) { /* Follow cluster chain */
1092 clst = get_fat(dj->fs, clst); /* Get next cluster */
1093 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
1094 if (clst < 2 || clst >= dj->fs->n_fatent) /* Reached to end of table or int error */
1095 return FR_INT_ERR;
1096 idx -= ic;
1097 }
1098 dj->clust = clst;
1099 dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */
1100 }
1101
1102 dj->dir = dj->fs->win + (idx % (SS(dj->fs) / SZ_DIR)) * SZ_DIR; /* Ptr to the entry in the sector */
1103
1104 return FR_OK; /* Seek succeeded */
1105}
1106
1107
1108
1109
1110/*-----------------------------------------------------------------------*/
1111/* Directory handling - Move directory table index next */
1112/*-----------------------------------------------------------------------*/
1113
1114static
1115FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not stretch */
1116 DIR *dj, /* Pointer to directory object */
1117 int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
1118)
1119{
1120 DWORD clst;
1121 WORD i;
1122
1123
1124 stretch = stretch; /* To suppress warning on read-only cfg. */
1125 i = dj->index + 1;
1126 if (!i || !dj->sect) /* Report EOT when index has reached 65535 */
1127 return FR_NO_FILE;
1128
1129 if (!(i % (SS(dj->fs) / SZ_DIR))) { /* Sector changed? */
1130 dj->sect++; /* Next sector */
1131
1132 if (dj->clust == 0) { /* Static table */
1133 if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */
1134 return FR_NO_FILE;
1135 }
1136 else { /* Dynamic table */
1137 if (((i / (SS(dj->fs) / SZ_DIR)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */
1138 clst = get_fat(dj->fs, dj->clust); /* Get next cluster */
1139 if (clst <= 1) return FR_INT_ERR;
1140 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
1141 if (clst >= dj->fs->n_fatent) { /* When it reached end of dynamic table */
1142#if !_FS_READONLY
1143 BYTE c;
1144 if (!stretch) return FR_NO_FILE; /* When do not stretch, report EOT */
1145 clst = create_chain(dj->fs, dj->clust); /* Stretch cluster chain */
1146 if (clst == 0) return FR_DENIED; /* No free cluster */
1147 if (clst == 1) return FR_INT_ERR;
1148 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
1149 /* Clean-up stretched table */
1150 if (move_window(dj->fs, 0)) return FR_DISK_ERR; /* Flush active window */
1151 mem_set(dj->fs->win, 0, SS(dj->fs)); /* Clear window buffer */
1152 dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */
1153 for (c = 0; c < dj->fs->csize; c++) { /* Fill the new cluster with 0 */
1154 dj->fs->wflag = 1;
1155 if (move_window(dj->fs, 0)) return FR_DISK_ERR;
1156 dj->fs->winsect++;
1157 }
1158 dj->fs->winsect -= c; /* Rewind window address */
1159#else
1160 return FR_NO_FILE; /* Report EOT */
1161#endif
1162 }
1163 dj->clust = clst; /* Initialize data for new cluster */
1164 dj->sect = clust2sect(dj->fs, clst);
1165 }
1166 }
1167 }
1168
1169 dj->index = i;
1170 dj->dir = dj->fs->win + (i % (SS(dj->fs) / SZ_DIR)) * SZ_DIR;
1171
1172 return FR_OK;
1173}
1174
1175
1176
1177
1178/*-----------------------------------------------------------------------*/
1179/* Directory handling - Load/Store start cluster number */
1180/*-----------------------------------------------------------------------*/
1181
1182static
1183DWORD ld_clust (
1184 FATFS *fs, /* Pointer to the fs object */
1185 BYTE *dir /* Pointer to the directory entry */
1186)
1187{
1188 DWORD cl;
1189
1190 cl = LD_WORD(dir+DIR_FstClusLO);
1191 if (fs->fs_type == FS_FAT32)
1192 cl |= (DWORD)LD_WORD(dir+DIR_FstClusHI) << 16;
1193
1194 return cl;
1195}
1196
1197
1198#if !_FS_READONLY
1199static
1200void st_clust (
1201 BYTE *dir, /* Pointer to the directory entry */
1202 DWORD cl /* Value to be set */
1203)
1204{
1205 ST_WORD(dir+DIR_FstClusLO, cl);
1206 ST_WORD(dir+DIR_FstClusHI, cl >> 16);
1207}
1208#endif
1209
1210
1211
1212/*-----------------------------------------------------------------------*/
1213/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */
1214/*-----------------------------------------------------------------------*/
1215#if _USE_LFN
1216static
1217const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN chars in the directory entry */
1218
1219
1220static
1221int cmp_lfn ( /* 1:Matched, 0:Not matched */
1222 WCHAR *lfnbuf, /* Pointer to the LFN to be compared */
1223 BYTE *dir /* Pointer to the directory entry containing a part of LFN */
1224)
1225{
1226 UINT i, s;
1227 WCHAR wc, uc;
1228
1229
1230 i = ((dir[LDIR_Ord] & ~LLE) - 1) * 13; /* Get offset in the LFN buffer */
1231 s = 0; wc = 1;
1232 do {
1233 uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
1234 if (wc) { /* Last char has not been processed */
1235 wc = ff_wtoupper(uc); /* Convert it to upper case */
1236 if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */
1237 return 0; /* Not matched */
1238 } else {
1239 if (uc != 0xFFFF) return 0; /* Check filler */
1240 }
1241 } while (++s < 13); /* Repeat until all chars in the entry are checked */
1242
1243 if ((dir[LDIR_Ord] & LLE) && wc && lfnbuf[i]) /* Last segment matched but different length */
1244 return 0;
1245
1246 return 1; /* The part of LFN matched */
1247}
1248
1249
1250
1251static
1252int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */
1253 WCHAR *lfnbuf, /* Pointer to the Unicode-LFN buffer */
1254 BYTE *dir /* Pointer to the directory entry */
1255)
1256{
1257 UINT i, s;
1258 WCHAR wc, uc;
1259
1260
1261 i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
1262
1263 s = 0; wc = 1;
1264 do {
1265 uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
1266 if (wc) { /* Last char has not been processed */
1267 if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
1268 lfnbuf[i++] = wc = uc; /* Store it */
1269 } else {
1270 if (uc != 0xFFFF) return 0; /* Check filler */
1271 }
1272 } while (++s < 13); /* Read all character in the entry */
1273
1274 if (dir[LDIR_Ord] & LLE) { /* Put terminator if it is the last LFN part */
1275 if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
1276 lfnbuf[i] = 0;
1277 }
1278
1279 return 1;
1280}
1281
1282
1283#if !_FS_READONLY
1284static
1285void fit_lfn (
1286 const WCHAR *lfnbuf, /* Pointer to the LFN buffer */
1287 BYTE *dir, /* Pointer to the directory entry */
1288 BYTE ord, /* LFN order (1-20) */
1289 BYTE sum /* SFN sum */
1290)
1291{
1292 UINT i, s;
1293 WCHAR wc;
1294
1295
1296 dir[LDIR_Chksum] = sum; /* Set check sum */
1297 dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
1298 dir[LDIR_Type] = 0;
1299 ST_WORD(dir+LDIR_FstClusLO, 0);
1300
1301 i = (ord - 1) * 13; /* Get offset in the LFN buffer */
1302 s = wc = 0;
1303 do {
1304 if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective char */
1305 ST_WORD(dir+LfnOfs[s], wc); /* Put it */
1306 if (!wc) wc = 0xFFFF; /* Padding chars following last char */
1307 } while (++s < 13);
1308 if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLE; /* Bottom LFN part is the start of LFN sequence */
1309 dir[LDIR_Ord] = ord; /* Set the LFN order */
1310}
1311
1312#endif
1313#endif
1314
1315
1316
1317/*-----------------------------------------------------------------------*/
1318/* Create numbered name */
1319/*-----------------------------------------------------------------------*/
1320#if _USE_LFN
1321void gen_numname (
1322 BYTE *dst, /* Pointer to generated SFN */
1323 const BYTE *src, /* Pointer to source SFN to be modified */
1324 const WCHAR *lfn, /* Pointer to LFN */
1325 WORD seq /* Sequence number */
1326)
1327{
1328 BYTE ns[8], c;
1329 UINT i, j;
1330
1331
1332 mem_cpy(dst, src, 11);
1333
1334 if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */
1335 do seq = (seq >> 1) + (seq << 15) + (WORD)*lfn++; while (*lfn);
1336 }
1337
1338 /* itoa (hexdecimal) */
1339 i = 7;
1340 do {
1341 c = (seq % 16) + '0';
1342 if (c > '9') c += 7;
1343 ns[i--] = c;
1344 seq /= 16;
1345 } while (seq);
1346 ns[i] = '~';
1347
1348 /* Append the number */
1349 for (j = 0; j < i && dst[j] != ' '; j++) {
1350 if (IsDBCS1(dst[j])) {
1351 if (j == i - 1) break;
1352 j++;
1353 }
1354 }
1355 do {
1356 dst[j++] = (i < 8) ? ns[i++] : ' ';
1357 } while (j < 8);
1358}
1359#endif
1360
1361
1362
1363
1364/*-----------------------------------------------------------------------*/
1365/* Calculate sum of an SFN */
1366/*-----------------------------------------------------------------------*/
1367#if _USE_LFN
1368static
1369BYTE sum_sfn (
1370 const BYTE *dir /* Ptr to directory entry */
1371)
1372{
1373 BYTE sum = 0;
1374 UINT n = 11;
1375
1376 do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
1377 return sum;
1378}
1379#endif
1380
1381
1382
1383
1384/*-----------------------------------------------------------------------*/
1385/* Directory handling - Find an object in the directory */
1386/*-----------------------------------------------------------------------*/
1387
1388static
1389FRESULT dir_find (
1390 DIR *dj /* Pointer to the directory object linked to the file name */
1391)
1392{
1393 FRESULT res;
1394 BYTE c, *dir;
1395#if _USE_LFN
1396 BYTE a, ord, sum;
1397#endif
1398
1399 res = dir_sdi(dj, 0); /* Rewind directory object */
1400 if (res != FR_OK) return res;
1401
1402#if _USE_LFN
1403 ord = sum = 0xFF;
1404#endif
1405 do {
1406 res = move_window(dj->fs, dj->sect);
1407 if (res != FR_OK) break;
1408 dir = dj->dir; /* Ptr to the directory entry of current index */
1409 c = dir[DIR_Name];
1410 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
1411#if _USE_LFN /* LFN configuration */
1412 a = dir[DIR_Attr] & AM_MASK;
1413 if (c == DDE || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
1414 ord = 0xFF;
1415 } else {
1416 if (a == AM_LFN) { /* An LFN entry is found */
1417 if (dj->lfn) {
1418 if (c & LLE) { /* Is it start of LFN sequence? */
1419 sum = dir[LDIR_Chksum];
1420 c &= ~LLE; ord = c; /* LFN start order */
1421 dj->lfn_idx = dj->index;
1422 }
1423 /* Check validity of the LFN entry and compare it with given name */
1424 ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
1425 }
1426 } else { /* An SFN entry is found */
1427 if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
1428 ord = 0xFF; dj->lfn_idx = 0xFFFF; /* Reset LFN sequence */
1429 if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break; /* SFN matched? */
1430 }
1431 }
1432#else /* Non LFN configuration */
1433 if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
1434 break;
1435#endif
1436 res = dir_next(dj, 0); /* Next entry */
1437 } while (res == FR_OK);
1438
1439 return res;
1440}
1441
1442
1443
1444
1445/*-----------------------------------------------------------------------*/
1446/* Read an object from the directory */
1447/*-----------------------------------------------------------------------*/
1448#if _FS_MINIMIZE <= 1
1449static
1450FRESULT dir_read (
1451 DIR *dj /* Pointer to the directory object that pointing the entry to be read */
1452)
1453{
1454 FRESULT res;
1455 BYTE c, *dir;
1456#if _USE_LFN
1457 BYTE a, ord = 0xFF, sum = 0xFF;
1458#endif
1459
1460 res = FR_NO_FILE;
1461 while (dj->sect) {
1462 res = move_window(dj->fs, dj->sect);
1463 if (res != FR_OK) break;
1464 dir = dj->dir; /* Ptr to the directory entry of current index */
1465 c = dir[DIR_Name];
1466 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
1467#if _USE_LFN /* LFN configuration */
1468 a = dir[DIR_Attr] & AM_MASK;
1469 if (c == DDE || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
1470 ord = 0xFF;
1471 } else {
1472 if (a == AM_LFN) { /* An LFN entry is found */
1473 if (c & LLE) { /* Is it start of LFN sequence? */
1474 sum = dir[LDIR_Chksum];
1475 c &= ~LLE; ord = c;
1476 dj->lfn_idx = dj->index;
1477 }
1478 /* Check LFN validity and capture it */
1479 ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
1480 } else { /* An SFN entry is found */
1481 if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
1482 dj->lfn_idx = 0xFFFF; /* It has no LFN. */
1483 break;
1484 }
1485 }
1486#else /* Non LFN configuration */
1487 if (c != DDE && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */
1488 break;
1489#endif
1490 res = dir_next(dj, 0); /* Next entry */
1491 if (res != FR_OK) break;
1492 }
1493
1494 if (res != FR_OK) dj->sect = 0;
1495
1496 return res;
1497}
1498#endif
1499
1500
1501
1502/*-----------------------------------------------------------------------*/
1503/* Register an object to the directory */
1504/*-----------------------------------------------------------------------*/
1505#if !_FS_READONLY
1506static
1507FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
1508 DIR *dj /* Target directory with object name to be created */
1509)
1510{
1511 FRESULT res;
1512 BYTE c, *dir;
1513#if _USE_LFN /* LFN configuration */
1514 WORD n, ne, is;
1515 BYTE sn[12], *fn, sum;
1516 WCHAR *lfn;
1517
1518
1519 fn = dj->fn; lfn = dj->lfn;
1520 mem_cpy(sn, fn, 12);
1521
1522 if (_FS_RPATH && (sn[NS] & NS_DOT)) /* Cannot create dot entry */
1523 return FR_INVALID_NAME;
1524
1525 if (sn[NS] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
1526 fn[NS] = 0; dj->lfn = 0; /* Find only SFN */
1527 for (n = 1; n < 100; n++) {
1528 gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
1529 res = dir_find(dj); /* Check if the name collides with existing SFN */
1530 if (res != FR_OK) break;
1531 }
1532 if (n == 100) return FR_DENIED; /* Abort if too many collisions */
1533 if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */
1534 fn[NS] = sn[NS]; dj->lfn = lfn;
1535 }
1536
1537 if (sn[NS] & NS_LFN) { /* When LFN is to be created, reserve an SFN + LFN entries. */
1538 for (ne = 0; lfn[ne]; ne++) ;
1539 ne = (ne + 25) / 13;
1540 } else { /* Otherwise reserve only an SFN entry. */
1541 ne = 1;
1542 }
1543
1544 /* Reserve contiguous entries */
1545 res = dir_sdi(dj, 0);
1546 if (res != FR_OK) return res;
1547 n = is = 0;
1548 do {
1549 res = move_window(dj->fs, dj->sect);
1550 if (res != FR_OK) break;
1551 c = *dj->dir; /* Check the entry status */
1552 if (c == DDE || c == 0) { /* Is it a blank entry? */
1553 if (n == 0) is = dj->index; /* First index of the contiguous entry */
1554 if (++n == ne) break; /* A contiguous entry that required count is found */
1555 } else {
1556 n = 0; /* Not a blank entry. Restart to search */
1557 }
1558 res = dir_next(dj, 1); /* Next entry with table stretch */
1559 } while (res == FR_OK);
1560
1561 if (res == FR_OK && ne > 1) { /* Initialize LFN entry if needed */
1562 res = dir_sdi(dj, is);
1563 if (res == FR_OK) {
1564 sum = sum_sfn(dj->fn); /* Sum of the SFN tied to the LFN */
1565 ne--;
1566 do { /* Store LFN entries in bottom first */
1567 res = move_window(dj->fs, dj->sect);
1568 if (res != FR_OK) break;
1569 fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
1570 dj->fs->wflag = 1;
1571 res = dir_next(dj, 0); /* Next entry */
1572 } while (res == FR_OK && --ne);
1573 }
1574 }
1575
1576#else /* Non LFN configuration */
1577 res = dir_sdi(dj, 0);
1578 if (res == FR_OK) {
1579 do { /* Find a blank entry for the SFN */
1580 res = move_window(dj->fs, dj->sect);
1581 if (res != FR_OK) break;
1582 c = *dj->dir;
1583 if (c == DDE || c == 0) break; /* Is it a blank entry? */
1584 res = dir_next(dj, 1); /* Next entry with table stretch */
1585 } while (res == FR_OK);
1586 }
1587#endif
1588
1589 if (res == FR_OK) { /* Initialize the SFN entry */
1590 res = move_window(dj->fs, dj->sect);
1591 if (res == FR_OK) {
1592 dir = dj->dir;
1593 mem_set(dir, 0, SZ_DIR); /* Clean the entry */
1594 mem_cpy(dir, dj->fn, 11); /* Put SFN */
1595#if _USE_LFN
1596 dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */
1597#endif
1598 dj->fs->wflag = 1;
1599 }
1600 }
1601
1602 return res;
1603}
1604#endif /* !_FS_READONLY */
1605
1606
1607
1608
1609/*-----------------------------------------------------------------------*/
1610/* Remove an object from the directory */
1611/*-----------------------------------------------------------------------*/
1612#if !_FS_READONLY && !_FS_MINIMIZE
1613static
1614FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */
1615 DIR *dj /* Directory object pointing the entry to be removed */
1616)
1617{
1618 FRESULT res;
1619#if _USE_LFN /* LFN configuration */
1620 WORD i;
1621
1622 i = dj->index; /* SFN index */
1623 res = dir_sdi(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx)); /* Goto the SFN or top of the LFN entries */
1624 if (res == FR_OK) {
1625 do {
1626 res = move_window(dj->fs, dj->sect);
1627 if (res != FR_OK) break;
1628 *dj->dir = DDE; /* Mark the entry "deleted" */
1629 dj->fs->wflag = 1;
1630 if (dj->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */
1631 res = dir_next(dj, 0); /* Next entry */
1632 } while (res == FR_OK);
1633 if (res == FR_NO_FILE) res = FR_INT_ERR;
1634 }
1635
1636#else /* Non LFN configuration */
1637 res = dir_sdi(dj, dj->index);
1638 if (res == FR_OK) {
1639 res = move_window(dj->fs, dj->sect);
1640 if (res == FR_OK) {
1641 *dj->dir = DDE; /* Mark the entry "deleted" */
1642 dj->fs->wflag = 1;
1643 }
1644 }
1645#endif
1646
1647 return res;
1648}
1649#endif /* !_FS_READONLY */
1650
1651
1652
1653
1654/*-----------------------------------------------------------------------*/
1655/* Pick a segment and create the object name in directory form */
1656/*-----------------------------------------------------------------------*/
1657
1658static
1659FRESULT create_name (
1660 DIR *dj, /* Pointer to the directory object */
1661 const TCHAR **path /* Pointer to pointer to the segment in the path string */
1662)
1663{
1664#ifdef _EXCVT
1665 static const BYTE excvt[] = _EXCVT; /* Upper conversion table for extended chars */
1666#endif
1667
1668#if _USE_LFN /* LFN configuration */
1669 BYTE b, cf;
1670 WCHAR w, *lfn;
1671 UINT i, ni, si, di;
1672 const TCHAR *p;
1673
1674 /* Create LFN in Unicode */
1675 for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
1676 lfn = dj->lfn;
1677 si = di = 0;
1678 for (;;) {
1679 w = p[si++]; /* Get a character */
1680 if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */
1681 if (di >= _MAX_LFN) /* Reject too long name */
1682 return FR_INVALID_NAME;
1683#if !_LFN_UNICODE
1684 w &= 0xFF;
1685 if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
1686 b = (BYTE)p[si++]; /* Get 2nd byte */
1687 if (!IsDBCS2(b))
1688 return FR_INVALID_NAME; /* Reject invalid sequence */
1689 w = (w << 8) + b; /* Create a DBC */
1690 }
1691 w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */
1692 if (!w) return FR_INVALID_NAME; /* Reject invalid code */
1693#endif
1694 if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
1695 return FR_INVALID_NAME;
1696 lfn[di++] = w; /* Store the Unicode char */
1697 }
1698 *path = &p[si]; /* Return pointer to the next segment */
1699 cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
1700#if _FS_RPATH
1701 if ((di == 1 && lfn[di-1] == '.') || /* Is this a dot entry? */
1702 (di == 2 && lfn[di-1] == '.' && lfn[di-2] == '.')) {
1703 lfn[di] = 0;
1704 for (i = 0; i < 11; i++)
1705 dj->fn[i] = (i < di) ? '.' : ' ';
1706 dj->fn[i] = cf | NS_DOT; /* This is a dot entry */
1707 return FR_OK;
1708 }
1709#endif
1710 while (di) { /* Strip trailing spaces and dots */
1711 w = lfn[di-1];
1712 if (w != ' ' && w != '.') break;
1713 di--;
1714 }
1715 if (!di) return FR_INVALID_NAME; /* Reject nul string */
1716
1717 lfn[di] = 0; /* LFN is created */
1718
1719 /* Create SFN in directory form */
1720 mem_set(dj->fn, ' ', 11);
1721 for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
1722 if (si) cf |= NS_LOSS | NS_LFN;
1723 while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
1724
1725 b = i = 0; ni = 8;
1726 for (;;) {
1727 w = lfn[si++]; /* Get an LFN char */
1728 if (!w) break; /* Break on end of the LFN */
1729 if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
1730 cf |= NS_LOSS | NS_LFN; continue;
1731 }
1732
1733 if (i >= ni || si == di) { /* Extension or end of SFN */
1734 if (ni == 11) { /* Long extension */
1735 cf |= NS_LOSS | NS_LFN; break;
1736 }
1737 if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
1738 if (si > di) break; /* No extension */
1739 si = di; i = 8; ni = 11; /* Enter extension section */
1740 b <<= 2; continue;
1741 }
1742
1743 if (w >= 0x80) { /* Non ASCII char */
1744#ifdef _EXCVT
1745 w = ff_convert(w, 0); /* Unicode -> OEM code */
1746 if (w) w = excvt[w - 0x80]; /* Convert extended char to upper (SBCS) */
1747#else
1748 w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
1749#endif
1750 cf |= NS_LFN; /* Force create LFN entry */
1751 }
1752
1753 if (_DF1S && w >= 0x100) { /* Double byte char (always false on SBCS cfg) */
1754 if (i >= ni - 1) {
1755 cf |= NS_LOSS | NS_LFN; i = ni; continue;
1756 }
1757 dj->fn[i++] = (BYTE)(w >> 8);
1758 } else { /* Single byte char */
1759 if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal chars for SFN */
1760 w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */
1761 } else {
1762 if (IsUpper(w)) { /* ASCII large capital */
1763 b |= 2;
1764 } else {
1765 if (IsLower(w)) { /* ASCII small capital */
1766 b |= 1; w -= 0x20;
1767 }
1768 }
1769 }
1770 }
1771 dj->fn[i++] = (BYTE)w;
1772 }
1773
1774 if (dj->fn[0] == DDE) dj->fn[0] = NDDE; /* If the first char collides with deleted mark, replace it with 0x05 */
1775
1776 if (ni == 8) b <<= 2;
1777 if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
1778 cf |= NS_LFN;
1779 if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended char, NT flags are created */
1780 if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */
1781 if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */
1782 }
1783
1784 dj->fn[NS] = cf; /* SFN is created */
1785
1786 return FR_OK;
1787
1788
1789#else /* Non-LFN configuration */
1790 BYTE b, c, d, *sfn;
1791 UINT ni, si, i;
1792 const char *p;
1793
1794 /* Create file name in directory form */
1795 for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
1796 sfn = dj->fn;
1797 mem_set(sfn, ' ', 11);
1798 si = i = b = 0; ni = 8;
1799#if _FS_RPATH
1800 if (p[si] == '.') { /* Is this a dot entry? */
1801 for (;;) {
1802 c = (BYTE)p[si++];
1803 if (c != '.' || si >= 3) break;
1804 sfn[i++] = c;
1805 }
1806 if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
1807 *path = &p[si]; /* Return pointer to the next segment */
1808 sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */
1809 return FR_OK;
1810 }
1811#endif
1812 for (;;) {
1813 c = (BYTE)p[si++];
1814 if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */
1815 if (c == '.' || i >= ni) {
1816 if (ni != 8 || c != '.') return FR_INVALID_NAME;
1817 i = 8; ni = 11;
1818 b <<= 2; continue;
1819 }
1820 if (c >= 0x80) { /* Extended char? */
1821 b |= 3; /* Eliminate NT flag */
1822#ifdef _EXCVT
1823 c = excvt[c - 0x80]; /* Upper conversion (SBCS) */
1824#else
1825#if !_DF1S /* ASCII only cfg */
1826 return FR_INVALID_NAME;
1827#endif
1828#endif
1829 }
1830 if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
1831 d = (BYTE)p[si++]; /* Get 2nd byte */
1832 if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
1833 return FR_INVALID_NAME;
1834 sfn[i++] = c;
1835 sfn[i++] = d;
1836 } else { /* Single byte code */
1837 if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */
1838 return FR_INVALID_NAME;
1839 if (IsUpper(c)) { /* ASCII large capital? */
1840 b |= 2;
1841 } else {
1842 if (IsLower(c)) { /* ASCII small capital? */
1843 b |= 1; c -= 0x20;
1844 }
1845 }
1846 sfn[i++] = c;
1847 }
1848 }
1849 *path = &p[si]; /* Return pointer to the next segment */
1850 c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
1851
1852 if (!i) return FR_INVALID_NAME; /* Reject nul string */
1853 if (sfn[0] == DDE) sfn[0] = NDDE; /* When first char collides with DDE, replace it with 0x05 */
1854
1855 if (ni == 8) b <<= 2;
1856 if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */
1857 if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */
1858
1859 sfn[NS] = c; /* Store NT flag, File name is created */
1860
1861 return FR_OK;
1862#endif
1863}
1864
1865
1866
1867
1868/*-----------------------------------------------------------------------*/
1869/* Get file information from directory entry */
1870/*-----------------------------------------------------------------------*/
1871#if _FS_MINIMIZE <= 1
1872static
1873void get_fileinfo ( /* No return code */
1874 DIR *dj, /* Pointer to the directory object */
1875 FILINFO *fno /* Pointer to the file information to be filled */
1876)
1877{
1878 UINT i;
1879 BYTE nt, *dir;
1880 TCHAR *p, c;
1881
1882
1883 p = fno->fname;
1884 if (dj->sect) {
1885 dir = dj->dir;
1886 nt = dir[DIR_NTres]; /* NT flag */
1887 for (i = 0; i < 8; i++) { /* Copy name body */
1888 c = dir[i];
1889 if (c == ' ') break;
1890 if (c == NDDE) c = (TCHAR)DDE;
1891 if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
1892#if _LFN_UNICODE
1893 if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i+1]))
1894 c = (c << 8) | dir[++i];
1895 c = ff_convert(c, 1);
1896 if (!c) c = '?';
1897#endif
1898 *p++ = c;
1899 }
1900 if (dir[8] != ' ') { /* Copy name extension */
1901 *p++ = '.';
1902 for (i = 8; i < 11; i++) {
1903 c = dir[i];
1904 if (c == ' ') break;
1905 if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
1906#if _LFN_UNICODE
1907 if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i+1]))
1908 c = (c << 8) | dir[++i];
1909 c = ff_convert(c, 1);
1910 if (!c) c = '?';
1911#endif
1912 *p++ = c;
1913 }
1914 }
1915 fno->fattrib = dir[DIR_Attr]; /* Attribute */
1916 fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */
1917 fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */
1918 fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */
1919 }
1920 *p = 0; /* Terminate SFN str by a \0 */
1921
1922#if _USE_LFN
1923 if (fno->lfname && fno->lfsize) {
1924 TCHAR *tp = fno->lfname;
1925 WCHAR w, *lfn;
1926
1927 i = 0;
1928 if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
1929 lfn = dj->lfn;
1930 while ((w = *lfn++) != 0) { /* Get an LFN char */
1931#if !_LFN_UNICODE
1932 w = ff_convert(w, 0); /* Unicode -> OEM conversion */
1933 if (!w) { i = 0; break; } /* Could not convert, no LFN */
1934 if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */
1935 tp[i++] = (TCHAR)(w >> 8);
1936#endif
1937 if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overflow, no LFN */
1938 tp[i++] = (TCHAR)w;
1939 }
1940 }
1941 tp[i] = 0; /* Terminate the LFN str by a \0 */
1942 }
1943#endif
1944}
1945#endif /* _FS_MINIMIZE <= 1 */
1946
1947
1948
1949
1950/*-----------------------------------------------------------------------*/
1951/* Follow a file path */
1952/*-----------------------------------------------------------------------*/
1953
1954static
1955FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
1956 DIR *dj, /* Directory object to return last directory and found object */
1957 const TCHAR *path /* Full-path string to find a file or directory */
1958)
1959{
1960 FRESULT res;
1961 BYTE *dir, ns;
1962
1963
1964#if _FS_RPATH
1965 if (*path == '/' || *path == '\\') { /* There is a heading separator */
1966 path++; dj->sclust = 0; /* Strip it and start from the root dir */
1967 } else { /* No heading separator */
1968 dj->sclust = dj->fs->cdir; /* Start from the current dir */
1969 }
1970#else
1971 if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
1972 path++;
1973 dj->sclust = 0; /* Start from the root dir */
1974#endif
1975
1976 if ((UINT)*path < ' ') { /* Nul path means the start directory itself */
1977 res = dir_sdi(dj, 0);
1978 dj->dir = 0;
1979 } else { /* Follow path */
1980 for (;;) {
1981 res = create_name(dj, &path); /* Get a segment */
1982 if (res != FR_OK) break;
1983 res = dir_find(dj); /* Find it */
1984 ns = *(dj->fn+NS);
1985 if (res != FR_OK) { /* Failed to find the object */
1986 if (res != FR_NO_FILE) break; /* Abort if any hard error occurred */
1987 /* Object not found */
1988 if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exit */
1989 dj->sclust = 0; dj->dir = 0; /* It is the root dir */
1990 res = FR_OK;
1991 if (!(ns & NS_LAST)) continue;
1992 } else { /* Could not find the object */
1993 if (!(ns & NS_LAST)) res = FR_NO_PATH;
1994 }
1995 break;
1996 }
1997 if (ns & NS_LAST) break; /* Last segment match. Function completed. */
1998 dir = dj->dir; /* There is next segment. Follow the sub directory */
1999 if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
2000 res = FR_NO_PATH; break;
2001 }
2002 dj->sclust = ld_clust(dj->fs, dir);
2003 }
2004 }
2005
2006 return res;
2007}
2008
2009
2010
2011
2012/*-----------------------------------------------------------------------*/
2013/* Load a sector and check if it is an FAT Volume Boot Record */
2014/*-----------------------------------------------------------------------*/
2015
2016static
2017BYTE check_fs ( /* 0:FAT-VBR, 1:Any BR but not FAT, 2:Not a BR, 3:Disk error */
2018 FATFS *fs, /* File system object */
2019 DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
2020)
2021{
2022 if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK) /* Load boot record */
2023 return 3;
2024 if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always placed at offset 510 even if the sector size is >512) */
2025 return 2;
2026
2027 if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
2028 return 0;
2029 if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
2030 return 0;
2031
2032 return 1;
2033}
2034
2035
2036
2037
2038/*-----------------------------------------------------------------------*/
2039/* Check if the file system object is valid or not */
2040/*-----------------------------------------------------------------------*/
2041
2042static
2043FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */
2044 const TCHAR **path, /* Pointer to pointer to the path name (drive number) */
2045 FATFS **rfs, /* Pointer to pointer to the found file system object */
2046 BYTE wmode /* !=0: Check write protection for write access */
2047)
2048{
2049 BYTE fmt, b, pi, *tbl;
2050 UINT vol;
2051 DSTATUS stat;
2052 DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
2053 WORD nrsv;
2054 const TCHAR *p = *path;
2055 FATFS *fs;
2056
2057
2058 /* Get logical drive number from the path name */
2059 vol = p[0] - '0'; /* Is there a drive number? */
2060 if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */
2061 p += 2; *path = p; /* Return pointer to the path name */
2062 } else { /* No drive number is given */
2063#if _FS_RPATH
2064 vol = CurrVol; /* Use current drive */
2065#else
2066 vol = 0; /* Use drive 0 */
2067#endif
2068 }
2069
2070 /* Check if the file system object is valid or not */
2071 *rfs = 0;
2072 if (vol >= _VOLUMES) /* Is the drive number valid? */
2073 return FR_INVALID_DRIVE;
2074 fs = FatFs[vol]; /* Get corresponding file system object */
2075 if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
2076
2077 ENTER_FF(fs); /* Lock file system */
2078
2079 *rfs = fs; /* Return pointer to the corresponding file system object */
2080 if (fs->fs_type) { /* If the volume has been mounted */
2081 stat = disk_status(fs->drv);
2082 if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */
2083 if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */
2084 return FR_WRITE_PROTECTED;
2085 return FR_OK; /* The file system object is valid */
2086 }
2087 }
2088
2089 /* The file system object is not valid. */
2090 /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */
2091
2092 fs->fs_type = 0; /* Clear the file system object */
2093 fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */
2094 stat = disk_initialize(fs->drv); /* Initialize the physical drive */
2095 if (stat & STA_NOINIT) /* Check if the initialization succeeded */
2096 return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */
2097 if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */
2098 return FR_WRITE_PROTECTED;
2099#if _MAX_SS != 512 /* Get disk sector size (variable sector size cfg only) */
2100 if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &fs->ssize) != RES_OK)
2101 return FR_DISK_ERR;
2102#endif
2103 /* Search FAT partition on the drive. Supports only generic partitions, FDISK and SFD. */
2104 fmt = check_fs(fs, bsect = 0); /* Load sector 0 and check if it is an FAT-VBR (in SFD) */
2105 if (LD2PT(vol) && !fmt) fmt = 1; /* Force non-SFD if the volume is forced partition */
2106 if (fmt == 1) { /* Not an FAT-VBR, the physical drive can be partitioned */
2107 /* Check the partition listed in the partition table */
2108 pi = LD2PT(vol);
2109 if (pi) pi--;
2110 tbl = &fs->win[MBR_Table + pi * SZ_PTE];/* Partition table */
2111 if (tbl[4]) { /* Is the partition existing? */
2112 bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */
2113 fmt = check_fs(fs, bsect); /* Check the partition */
2114 }
2115 }
2116 if (fmt == 3) return FR_DISK_ERR;
2117 if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */
2118
2119 /* An FAT volume is found. Following code initializes the file system object */
2120
2121 if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */
2122 return FR_NO_FILESYSTEM;
2123
2124 fasize = LD_WORD(fs->win+BPB_FATSz16); /* Number of sectors per FAT */
2125 if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32);
2126 fs->fsize = fasize;
2127
2128 fs->n_fats = b = fs->win[BPB_NumFATs]; /* Number of FAT copies */
2129 if (b != 1 && b != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
2130 fasize *= b; /* Number of sectors for FAT area */
2131
2132 fs->csize = b = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
2133 if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */
2134
2135 fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Number of root directory entries */
2136 if (fs->n_rootdir % (SS(fs) / SZ_DIR)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */
2137
2138 tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */
2139 if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
2140
2141 nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt); /* Number of reserved sectors */
2142 if (!nrsv) return FR_NO_FILESYSTEM; /* (BPB_RsvdSecCnt must not be 0) */
2143
2144 /* Determine the FAT sub type */
2145 sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIR); /* RSV+FAT+DIR */
2146 if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
2147 nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
2148 if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
2149 fmt = FS_FAT12;
2150 if (nclst >= MIN_FAT16) fmt = FS_FAT16;
2151 if (nclst >= MIN_FAT32) fmt = FS_FAT32;
2152
2153 /* Boundaries and Limits */
2154 fs->n_fatent = nclst + 2; /* Number of FAT entries */
2155 fs->database = bsect + sysect; /* Data start sector */
2156 fs->fatbase = bsect + nrsv; /* FAT start sector */
2157 if (fmt == FS_FAT32) {
2158 if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
2159 fs->dirbase = LD_DWORD(fs->win+BPB_RootClus); /* Root directory start cluster */
2160 szbfat = fs->n_fatent * 4; /* (Required FAT size) */
2161 } else {
2162 if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
2163 fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
2164 szbfat = (fmt == FS_FAT16) ? /* (Required FAT size) */
2165 fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
2166 }
2167 if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than required) */
2168 return FR_NO_FILESYSTEM;
2169
2170#if !_FS_READONLY
2171 /* Initialize cluster allocation information */
2172 fs->free_clust = 0xFFFFFFFF;
2173 fs->last_clust = 0;
2174
2175 /* Get fsinfo if available */
2176 if (fmt == FS_FAT32) {
2177 fs->fsi_flag = 0;
2178 fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
2179 if (disk_read(fs->drv, fs->win, fs->fsi_sector, 1) == RES_OK &&
2180 LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
2181 LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
2182 LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
2183 fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
2184 fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
2185 }
2186 }
2187#endif
2188 fs->fs_type = fmt; /* FAT sub-type */
2189 fs->id = ++Fsid; /* File system mount ID */
2190 fs->winsect = 0; /* Invalidate sector cache */
2191 fs->wflag = 0;
2192#if _FS_RPATH
2193 fs->cdir = 0; /* Current directory (root dir) */
2194#endif
2195#if _FS_LOCK /* Clear file lock semaphores */
2196 clear_lock(fs);
2197#endif
2198
2199 return FR_OK;
2200}
2201
2202
2203
2204
2205/*-----------------------------------------------------------------------*/
2206/* Check if the file/dir object is valid or not */
2207/*-----------------------------------------------------------------------*/
2208
2209static
2210FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
2211 void* obj /* Pointer to the object FIL/DIR to check validity */
2212)
2213{
2214 FIL *fil;
2215
2216
2217 fil = (FIL*)obj; /* Assuming offset of fs and id in the FIL/DIR is identical */
2218 if (!fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id)
2219 return FR_INVALID_OBJECT;
2220
2221 ENTER_FF(fil->fs); /* Lock file system */
2222
2223 if (disk_status(fil->fs->drv) & STA_NOINIT)
2224 return FR_NOT_READY;
2225
2226 return FR_OK;
2227}
2228
2229
2230
2231
2232/*--------------------------------------------------------------------------
2233
2234 Public Functions
2235
2236--------------------------------------------------------------------------*/
2237
2238
2239
2240/*-----------------------------------------------------------------------*/
2241/* Mount/Unmount a Logical Drive */
2242/*-----------------------------------------------------------------------*/
2243
2244FRESULT f_mount (
2245 BYTE vol, /* Logical drive number to be mounted/unmounted */
2246 FATFS *fs /* Pointer to new file system object (NULL for unmount)*/
2247)
2248{
2249 FATFS *rfs;
2250
2251
2252 if (vol >= _VOLUMES) /* Check if the drive number is valid */
2253 return FR_INVALID_DRIVE;
2254 rfs = FatFs[vol]; /* Get current fs object */
2255
2256 if (rfs) {
2257#if _FS_LOCK
2258 clear_lock(rfs);
2259#endif
2260#if _FS_REENTRANT /* Discard sync object of the current volume */
2261 if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
2262#endif
2263 rfs->fs_type = 0; /* Clear old fs object */
2264 }
2265
2266 if (fs) {
2267 fs->fs_type = 0; /* Clear new fs object */
2268#if _FS_REENTRANT /* Create sync object for the new volume */
2269 if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
2270#endif
2271 }
2272 FatFs[vol] = fs; /* Register new fs object */
2273
2274 return FR_OK;
2275}
2276
2277
2278
2279
2280/*-----------------------------------------------------------------------*/
2281/* Open or Create a File */
2282/*-----------------------------------------------------------------------*/
2283
2284FRESULT f_open (
2285 FIL *fp, /* Pointer to the blank file object */
2286 const TCHAR *path, /* Pointer to the file name */
2287 BYTE mode /* Access mode and file open mode flags */
2288)
2289{
2290 FRESULT res;
2291 DIR dj;
2292 BYTE *dir;
2293 DEF_NAMEBUF;
2294
2295
2296 if (!fp) return FR_INVALID_OBJECT;
2297 fp->fs = 0; /* Clear file object */
2298
2299#if !_FS_READONLY
2300 mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
2301 res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ));
2302#else
2303 mode &= FA_READ;
2304 res = chk_mounted(&path, &dj.fs, 0);
2305#endif
2306 if (res == FR_OK) {
2307 INIT_BUF(dj);
2308 res = follow_path(&dj, path); /* Follow the file path */
2309 dir = dj.dir;
2310#if !_FS_READONLY /* R/W configuration */
2311 if (res == FR_OK) {
2312 if (!dir) /* Current dir itself */
2313 res = FR_INVALID_NAME;
2314#if _FS_LOCK
2315 else
2316 res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
2317#endif
2318 }
2319 /* Create or Open a file */
2320 if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
2321 DWORD dw, cl;
2322
2323 if (res != FR_OK) { /* No file, create new */
2324 if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
2325#if _FS_LOCK
2326 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
2327#else
2328 res = dir_register(&dj);
2329#endif
2330 mode |= FA_CREATE_ALWAYS; /* File is created */
2331 dir = dj.dir; /* New entry */
2332 }
2333 else { /* Any object is already existing */
2334 if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */
2335 res = FR_DENIED;
2336 } else {
2337 if (mode & FA_CREATE_NEW) /* Cannot create as new file */
2338 res = FR_EXIST;
2339 }
2340 }
2341 if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
2342 dw = get_fattime(); /* Created time */
2343 ST_DWORD(dir+DIR_CrtTime, dw);
2344 dir[DIR_Attr] = 0; /* Reset attribute */
2345 ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */
2346 cl = ld_clust(dj.fs, dir); /* Get start cluster */
2347 st_clust(dir, 0); /* cluster = 0 */
2348 dj.fs->wflag = 1;
2349 if (cl) { /* Remove the cluster chain if exist */
2350 dw = dj.fs->winsect;
2351 res = remove_chain(dj.fs, cl);
2352 if (res == FR_OK) {
2353 dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
2354 res = move_window(dj.fs, dw);
2355 }
2356 }
2357 }
2358 }
2359 else { /* Open an existing file */
2360 if (res == FR_OK) { /* Follow succeeded */
2361 if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
2362 res = FR_NO_FILE;
2363 } else {
2364 if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
2365 res = FR_DENIED;
2366 }
2367 }
2368 }
2369 if (res == FR_OK) {
2370 if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */
2371 mode |= FA__WRITTEN;
2372 fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
2373 fp->dir_ptr = dir;
2374#if _FS_LOCK
2375 fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
2376 if (!fp->lockid) res = FR_INT_ERR;
2377#endif
2378 }
2379
2380#else /* R/O configuration */
2381 if (res == FR_OK) { /* Follow succeeded */
2382 dir = dj.dir;
2383 if (!dir) { /* Current dir itself */
2384 res = FR_INVALID_NAME;
2385 } else {
2386 if (dir[DIR_Attr] & AM_DIR) /* It is a directory */
2387 res = FR_NO_FILE;
2388 }
2389 }
2390#endif
2391 FREE_BUF();
2392
2393 if (res == FR_OK) {
2394 fp->flag = mode; /* File access mode */
2395 fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */
2396 fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
2397 fp->fptr = 0; /* File pointer */
2398 fp->dsect = 0;
2399#if _USE_FASTSEEK
2400 fp->cltbl = 0; /* Normal seek mode */
2401#endif
2402 fp->fs = dj.fs; fp->id = dj.fs->id; /* Validate file object */
2403 }
2404 }
2405
2406 LEAVE_FF(dj.fs, res);
2407}
2408
2409
2410
2411
2412/*-----------------------------------------------------------------------*/
2413/* Read File */
2414/*-----------------------------------------------------------------------*/
2415
2416FRESULT f_read (
2417 FIL *fp, /* Pointer to the file object */
2418 void *buff, /* Pointer to data buffer */
2419 UINT btr, /* Number of bytes to read */
2420 UINT *br /* Pointer to number of bytes read */
2421)
2422{
2423 FRESULT res;
2424 DWORD clst, sect, remain;
2425 UINT rcnt, cc;
2426 BYTE csect, *rbuff = buff;
2427
2428
2429 *br = 0; /* Clear read byte counter */
2430
2431 res = validate(fp); /* Check validity */
2432 if (res != FR_OK) LEAVE_FF(fp->fs, res);
2433 if (fp->flag & FA__ERROR) /* Aborted file? */
2434 LEAVE_FF(fp->fs, FR_INT_ERR);
2435 if (!(fp->flag & FA_READ)) /* Check access mode */
2436 LEAVE_FF(fp->fs, FR_DENIED);
2437 remain = fp->fsize - fp->fptr;
2438 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
2439
2440 for ( ; btr; /* Repeat until all data read */
2441 rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
2442 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
2443 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
2444 if (!csect) { /* On the cluster boundary? */
2445 if (fp->fptr == 0) { /* On the top of the file? */
2446 clst = fp->sclust; /* Follow from the origin */
2447 } else { /* Middle or end of the file */
2448#if _USE_FASTSEEK
2449 if (fp->cltbl)
2450 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
2451 else
2452#endif
2453 clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */
2454 }
2455 if (clst < 2) ABORT(fp->fs, FR_INT_ERR);
2456 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
2457 fp->clust = clst; /* Update current cluster */
2458 }
2459 sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
2460 if (!sect) ABORT(fp->fs, FR_INT_ERR);
2461 sect += csect;
2462 cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */
2463 if (cc) { /* Read maximum contiguous sectors directly */
2464 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
2465 cc = fp->fs->csize - csect;
2466 if (disk_read(fp->fs->drv, rbuff, sect, (BYTE)cc) != RES_OK)
2467 ABORT(fp->fs, FR_DISK_ERR);
2468#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */
2469#if _FS_TINY
2470 if (fp->fs->wflag && fp->fs->winsect - sect < cc)
2471 mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
2472#else
2473 if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
2474 mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
2475#endif
2476#endif
2477 rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
2478 continue;
2479 }
2480#if !_FS_TINY
2481 if (fp->dsect != sect) { /* Load data sector if not in cache */
2482#if !_FS_READONLY
2483 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
2484 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
2485 ABORT(fp->fs, FR_DISK_ERR);
2486 fp->flag &= ~FA__DIRTY;
2487 }
2488#endif
2489 if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */
2490 ABORT(fp->fs, FR_DISK_ERR);
2491 }
2492#endif
2493 fp->dsect = sect;
2494 }
2495 rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */
2496 if (rcnt > btr) rcnt = btr;
2497#if _FS_TINY
2498 if (move_window(fp->fs, fp->dsect)) /* Move sector window */
2499 ABORT(fp->fs, FR_DISK_ERR);
2500 mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
2501#else
2502 mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
2503#endif
2504 }
2505
2506 LEAVE_FF(fp->fs, FR_OK);
2507}
2508
2509
2510
2511
2512#if !_FS_READONLY
2513/*-----------------------------------------------------------------------*/
2514/* Write File */
2515/*-----------------------------------------------------------------------*/
2516
2517FRESULT f_write (
2518 FIL *fp, /* Pointer to the file object */
2519 const void *buff, /* Pointer to the data to be written */
2520 UINT btw, /* Number of bytes to write */
2521 UINT *bw /* Pointer to number of bytes written */
2522)
2523{
2524 FRESULT res;
2525 DWORD clst, sect;
2526 UINT wcnt, cc;
2527 const BYTE *wbuff = buff;
2528 BYTE csect;
2529
2530
2531 *bw = 0; /* Clear write byte counter */
2532
2533 res = validate(fp); /* Check validity */
2534 if (res != FR_OK) LEAVE_FF(fp->fs, res);
2535 if (fp->flag & FA__ERROR) /* Aborted file? */
2536 LEAVE_FF(fp->fs, FR_INT_ERR);
2537 if (!(fp->flag & FA_WRITE)) /* Check access mode */
2538 LEAVE_FF(fp->fs, FR_DENIED);
2539 if ((DWORD)(fp->fsize + btw) < fp->fsize) btw = 0; /* File size cannot reach 4GB */
2540
2541 for ( ; btw; /* Repeat until all data written */
2542 wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
2543 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
2544 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
2545 if (!csect) { /* On the cluster boundary? */
2546 if (fp->fptr == 0) { /* On the top of the file? */
2547 clst = fp->sclust; /* Follow from the origin */
2548 if (clst == 0) /* When no cluster is allocated, */
2549 fp->sclust = clst = create_chain(fp->fs, 0); /* Create a new cluster chain */
2550 } else { /* Middle or end of the file */
2551#if _USE_FASTSEEK
2552 if (fp->cltbl)
2553 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
2554 else
2555#endif
2556 clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */
2557 }
2558 if (clst == 0) break; /* Could not allocate a new cluster (disk full) */
2559 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
2560 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
2561 fp->clust = clst; /* Update current cluster */
2562 }
2563#if _FS_TINY
2564 if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0)) /* Write-back sector cache */
2565 ABORT(fp->fs, FR_DISK_ERR);
2566#else
2567 if (fp->flag & FA__DIRTY) { /* Write-back sector cache */
2568 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
2569 ABORT(fp->fs, FR_DISK_ERR);
2570 fp->flag &= ~FA__DIRTY;
2571 }
2572#endif
2573 sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
2574 if (!sect) ABORT(fp->fs, FR_INT_ERR);
2575 sect += csect;
2576 cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */
2577 if (cc) { /* Write maximum contiguous sectors directly */
2578 if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
2579 cc = fp->fs->csize - csect;
2580 if (disk_write(fp->fs->drv, wbuff, sect, (BYTE)cc) != RES_OK)
2581 ABORT(fp->fs, FR_DISK_ERR);
2582#if _FS_TINY
2583 if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
2584 mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
2585 fp->fs->wflag = 0;
2586 }
2587#else
2588 if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
2589 mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
2590 fp->flag &= ~FA__DIRTY;
2591 }
2592#endif
2593 wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
2594 continue;
2595 }
2596#if _FS_TINY
2597 if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */
2598 if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
2599 fp->fs->winsect = sect;
2600 }
2601#else
2602 if (fp->dsect != sect) { /* Fill sector cache with file data */
2603 if (fp->fptr < fp->fsize &&
2604 disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
2605 ABORT(fp->fs, FR_DISK_ERR);
2606 }
2607#endif
2608 fp->dsect = sect;
2609 }
2610 wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */
2611 if (wcnt > btw) wcnt = btw;
2612#if _FS_TINY
2613 if (move_window(fp->fs, fp->dsect)) /* Move sector window */
2614 ABORT(fp->fs, FR_DISK_ERR);
2615 mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
2616 fp->fs->wflag = 1;
2617#else
2618 mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
2619 fp->flag |= FA__DIRTY;
2620#endif
2621 }
2622
2623 if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
2624 fp->flag |= FA__WRITTEN; /* Set file change flag */
2625
2626 LEAVE_FF(fp->fs, FR_OK);
2627}
2628
2629
2630
2631
2632/*-----------------------------------------------------------------------*/
2633/* Synchronize the File Object */
2634/*-----------------------------------------------------------------------*/
2635
2636FRESULT f_sync (
2637 FIL *fp /* Pointer to the file object */
2638)
2639{
2640 FRESULT res;
2641 DWORD tim;
2642 BYTE *dir;
2643
2644
2645 res = validate(fp); /* Check validity of the object */
2646 if (res == FR_OK) {
2647 if (fp->flag & FA__WRITTEN) { /* Has the file been written? */
2648#if !_FS_TINY /* Write-back dirty buffer */
2649 if (fp->flag & FA__DIRTY) {
2650 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
2651 LEAVE_FF(fp->fs, FR_DISK_ERR);
2652 fp->flag &= ~FA__DIRTY;
2653 }
2654#endif
2655 /* Update the directory entry */
2656 res = move_window(fp->fs, fp->dir_sect);
2657 if (res == FR_OK) {
2658 dir = fp->dir_ptr;
2659 dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
2660 ST_DWORD(dir+DIR_FileSize, fp->fsize); /* Update file size */
2661 st_clust(dir, fp->sclust); /* Update start cluster */
2662 tim = get_fattime(); /* Update updated time */
2663 ST_DWORD(dir+DIR_WrtTime, tim);
2664 ST_WORD(dir+DIR_LstAccDate, 0);
2665 fp->flag &= ~FA__WRITTEN;
2666 fp->fs->wflag = 1;
2667 res = sync(fp->fs);
2668 }
2669 }
2670 }
2671
2672 LEAVE_FF(fp->fs, res);
2673}
2674
2675#endif /* !_FS_READONLY */
2676
2677
2678
2679
2680/*-----------------------------------------------------------------------*/
2681/* Close File */
2682/*-----------------------------------------------------------------------*/
2683
2684FRESULT f_close (
2685 FIL *fp /* Pointer to the file object to be closed */
2686)
2687{
2688 FRESULT res;
2689
2690
2691#if _FS_READONLY
2692 res = validate(fp);
2693 {
2694#if _FS_REENTRANT
2695 FATFS *fs = fp->fs;
2696#endif
2697 if (res == FR_OK) fp->fs = 0; /* Discard file object */
2698 LEAVE_FF(fs, res);
2699 }
2700#else
2701 res = f_sync(fp); /* Flush cached data */
2702#if _FS_LOCK
2703 if (res == FR_OK) { /* Decrement open counter */
2704#if _FS_REENTRANT
2705 FATFS *fs = fp->fs;;
2706 res = validate(fp);
2707 if (res == FR_OK) {
2708 res = dec_lock(fp->lockid);
2709 unlock_fs(fs, FR_OK);
2710 }
2711#else
2712 res = dec_lock(fp->lockid);
2713#endif
2714 }
2715#endif
2716 if (res == FR_OK) fp->fs = 0; /* Discard file object */
2717 return res;
2718#endif
2719}
2720
2721
2722
2723
2724/*-----------------------------------------------------------------------*/
2725/* Current Drive/Directory Handlings */
2726/*-----------------------------------------------------------------------*/
2727
2728#if _FS_RPATH >= 1
2729
2730FRESULT f_chdrive (
2731 BYTE drv /* Drive number */
2732)
2733{
2734 if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
2735
2736 CurrVol = drv;
2737
2738 return FR_OK;
2739}
2740
2741
2742
2743FRESULT f_chdir (
2744 const TCHAR *path /* Pointer to the directory path */
2745)
2746{
2747 FRESULT res;
2748 DIR dj;
2749 DEF_NAMEBUF;
2750
2751
2752 res = chk_mounted(&path, &dj.fs, 0);
2753 if (res == FR_OK) {
2754 INIT_BUF(dj);
2755 res = follow_path(&dj, path); /* Follow the path */
2756 FREE_BUF();
2757 if (res == FR_OK) { /* Follow completed */
2758 if (!dj.dir) {
2759 dj.fs->cdir = dj.sclust; /* Start directory itself */
2760 } else {
2761 if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */
2762 dj.fs->cdir = ld_clust(dj.fs, dj.dir);
2763 else
2764 res = FR_NO_PATH; /* Reached but a file */
2765 }
2766 }
2767 if (res == FR_NO_FILE) res = FR_NO_PATH;
2768 }
2769
2770 LEAVE_FF(dj.fs, res);
2771}
2772
2773
2774#if _FS_RPATH >= 2
2775FRESULT f_getcwd (
2776 TCHAR *path, /* Pointer to the directory path */
2777 UINT sz_path /* Size of path */
2778)
2779{
2780 FRESULT res;
2781 DIR dj;
2782 UINT i, n;
2783 DWORD ccl;
2784 TCHAR *tp;
2785 FILINFO fno;
2786 DEF_NAMEBUF;
2787
2788
2789 *path = 0;
2790 res = chk_mounted((const TCHAR**)&path, &dj.fs, 0); /* Get current volume */
2791 if (res == FR_OK) {
2792 INIT_BUF(dj);
2793 i = sz_path; /* Bottom of buffer (dir stack base) */
2794 dj.sclust = dj.fs->cdir; /* Start to follow upper dir from current dir */
2795 while ((ccl = dj.sclust) != 0) { /* Repeat while current dir is a sub-dir */
2796 res = dir_sdi(&dj, 1); /* Get parent dir */
2797 if (res != FR_OK) break;
2798 res = dir_read(&dj);
2799 if (res != FR_OK) break;
2800 dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent dir */
2801 res = dir_sdi(&dj, 0);
2802 if (res != FR_OK) break;
2803 do { /* Find the entry links to the child dir */
2804 res = dir_read(&dj);
2805 if (res != FR_OK) break;
2806 if (ccl == ld_clust(dj.fs, dj.dir)) break; /* Found the entry */
2807 res = dir_next(&dj, 0);
2808 } while (res == FR_OK);
2809 if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */
2810 if (res != FR_OK) break;
2811#if _USE_LFN
2812 fno.lfname = path;
2813 fno.lfsize = i;
2814#endif
2815 get_fileinfo(&dj, &fno); /* Get the dir name and push it to the buffer */
2816 tp = fno.fname;
2817 if (_USE_LFN && *path) tp = path;
2818 for (n = 0; tp[n]; n++) ;
2819 if (i < n + 3) {
2820 res = FR_NOT_ENOUGH_CORE; break;
2821 }
2822 while (n) path[--i] = tp[--n];
2823 path[--i] = '/';
2824 }
2825 tp = path;
2826 if (res == FR_OK) {
2827 *tp++ = '0' + CurrVol; /* Put drive number */
2828 *tp++ = ':';
2829 if (i == sz_path) { /* Root-dir */
2830 *tp++ = '/';
2831 } else { /* Sub-dir */
2832 do /* Add stacked path str */
2833 *tp++ = path[i++];
2834 while (i < sz_path);
2835 }
2836 }
2837 *tp = 0;
2838 FREE_BUF();
2839 }
2840
2841 LEAVE_FF(dj.fs, res);
2842}
2843#endif /* _FS_RPATH >= 2 */
2844#endif /* _FS_RPATH >= 1 */
2845
2846
2847
2848#if _FS_MINIMIZE <= 2
2849/*-----------------------------------------------------------------------*/
2850/* Seek File R/W Pointer */
2851/*-----------------------------------------------------------------------*/
2852
2853FRESULT f_lseek (
2854 FIL *fp, /* Pointer to the file object */
2855 DWORD ofs /* File pointer from top of file */
2856)
2857{
2858 FRESULT res;
2859
2860
2861 res = validate(fp); /* Check validity of the object */
2862 if (res != FR_OK) LEAVE_FF(fp->fs, res);
2863 if (fp->flag & FA__ERROR) /* Check abort flag */
2864 LEAVE_FF(fp->fs, FR_INT_ERR);
2865
2866#if _USE_FASTSEEK
2867 if (fp->cltbl) { /* Fast seek */
2868 DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
2869
2870 if (ofs == CREATE_LINKMAP) { /* Create CLMT */
2871 tbl = fp->cltbl;
2872 tlen = *tbl++; ulen = 2; /* Given table size and required table size */
2873 cl = fp->sclust; /* Top of the chain */
2874 if (cl) {
2875 do {
2876 /* Get a fragment */
2877 tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */
2878 do {
2879 pcl = cl; ncl++;
2880 cl = get_fat(fp->fs, cl);
2881 if (cl <= 1) ABORT(fp->fs, FR_INT_ERR);
2882 if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
2883 } while (cl == pcl + 1);
2884 if (ulen <= tlen) { /* Store the length and top of the fragment */
2885 *tbl++ = ncl; *tbl++ = tcl;
2886 }
2887 } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */
2888 }
2889 *fp->cltbl = ulen; /* Number of items used */
2890 if (ulen <= tlen)
2891 *tbl = 0; /* Terminate table */
2892 else
2893 res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */
2894
2895 } else { /* Fast seek */
2896 if (ofs > fp->fsize) /* Clip offset at the file size */
2897 ofs = fp->fsize;
2898 fp->fptr = ofs; /* Set file pointer */
2899 if (ofs) {
2900 fp->clust = clmt_clust(fp, ofs - 1);
2901 dsc = clust2sect(fp->fs, fp->clust);
2902 if (!dsc) ABORT(fp->fs, FR_INT_ERR);
2903 dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1);
2904 if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */
2905#if !_FS_TINY
2906#if !_FS_READONLY
2907 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
2908 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
2909 ABORT(fp->fs, FR_DISK_ERR);
2910 fp->flag &= ~FA__DIRTY;
2911 }
2912#endif
2913 if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */
2914 ABORT(fp->fs, FR_DISK_ERR);
2915#endif
2916 fp->dsect = dsc;
2917 }
2918 }
2919 }
2920 } else
2921#endif
2922
2923 /* Normal Seek */
2924 {
2925 DWORD clst, bcs, nsect, ifptr;
2926
2927 if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */
2928#if !_FS_READONLY
2929 && !(fp->flag & FA_WRITE)
2930#endif
2931 ) ofs = fp->fsize;
2932
2933 ifptr = fp->fptr;
2934 fp->fptr = nsect = 0;
2935 if (ofs) {
2936 bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */
2937 if (ifptr > 0 &&
2938 (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
2939 fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
2940 ofs -= fp->fptr;
2941 clst = fp->clust;
2942 } else { /* When seek to back cluster, */
2943 clst = fp->sclust; /* start from the first cluster */
2944#if !_FS_READONLY
2945 if (clst == 0) { /* If no cluster chain, create a new chain */
2946 clst = create_chain(fp->fs, 0);
2947 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
2948 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
2949 fp->sclust = clst;
2950 }
2951#endif
2952 fp->clust = clst;
2953 }
2954 if (clst != 0) {
2955 while (ofs > bcs) { /* Cluster following loop */
2956#if !_FS_READONLY
2957 if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
2958 clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */
2959 if (clst == 0) { /* When disk gets full, clip file size */
2960 ofs = bcs; break;
2961 }
2962 } else
2963#endif
2964 clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */
2965 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
2966 if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR);
2967 fp->clust = clst;
2968 fp->fptr += bcs;
2969 ofs -= bcs;
2970 }
2971 fp->fptr += ofs;
2972 if (ofs % SS(fp->fs)) {
2973 nsect = clust2sect(fp->fs, clst); /* Current sector */
2974 if (!nsect) ABORT(fp->fs, FR_INT_ERR);
2975 nsect += ofs / SS(fp->fs);
2976 }
2977 }
2978 }
2979 if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */
2980#if !_FS_TINY
2981#if !_FS_READONLY
2982 if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
2983 if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
2984 ABORT(fp->fs, FR_DISK_ERR);
2985 fp->flag &= ~FA__DIRTY;
2986 }
2987#endif
2988 if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */
2989 ABORT(fp->fs, FR_DISK_ERR);
2990#endif
2991 fp->dsect = nsect;
2992 }
2993#if !_FS_READONLY
2994 if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */
2995 fp->fsize = fp->fptr;
2996 fp->flag |= FA__WRITTEN;
2997 }
2998#endif
2999 }
3000
3001 LEAVE_FF(fp->fs, res);
3002}
3003
3004
3005
3006#if _FS_MINIMIZE <= 1
3007/*-----------------------------------------------------------------------*/
3008/* Create a Directory Object */
3009/*-----------------------------------------------------------------------*/
3010
3011FRESULT f_opendir (
3012 DIR *dj, /* Pointer to directory object to create */
3013 const TCHAR *path /* Pointer to the directory path */
3014)
3015{
3016 FRESULT res;
3017 FATFS *fs;
3018 DEF_NAMEBUF;
3019
3020
3021 if (!dj) return FR_INVALID_OBJECT;
3022
3023 res = chk_mounted(&path, &dj->fs, 0);
3024 fs = dj->fs;
3025 if (res == FR_OK) {
3026 INIT_BUF(*dj);
3027 res = follow_path(dj, path); /* Follow the path to the directory */
3028 FREE_BUF();
3029 if (res == FR_OK) { /* Follow completed */
3030 if (dj->dir) { /* It is not the root dir */
3031 if (dj->dir[DIR_Attr] & AM_DIR) { /* The object is a directory */
3032 dj->sclust = ld_clust(fs, dj->dir);
3033 } else { /* The object is not a directory */
3034 res = FR_NO_PATH;
3035 }
3036 }
3037 if (res == FR_OK) {
3038 dj->id = fs->id;
3039 res = dir_sdi(dj, 0); /* Rewind dir */
3040 }
3041 }
3042 if (res == FR_NO_FILE) res = FR_NO_PATH;
3043 if (res != FR_OK) dj->fs = 0; /* Invalidate the dir object if function failed */
3044 } else {
3045 dj->fs = 0;
3046 }
3047
3048 LEAVE_FF(fs, res);
3049}
3050
3051
3052
3053
3054/*-----------------------------------------------------------------------*/
3055/* Read Directory Entry in Sequence */
3056/*-----------------------------------------------------------------------*/
3057
3058FRESULT f_readdir (
3059 DIR *dj, /* Pointer to the open directory object */
3060 FILINFO *fno /* Pointer to file information to return */
3061)
3062{
3063 FRESULT res;
3064 DEF_NAMEBUF;
3065
3066
3067 res = validate(dj); /* Check validity of the object */
3068 if (res == FR_OK) {
3069 if (!fno) {
3070 res = dir_sdi(dj, 0); /* Rewind the directory object */
3071 } else {
3072 INIT_BUF(*dj);
3073 res = dir_read(dj); /* Read an directory item */
3074 if (res == FR_NO_FILE) { /* Reached end of dir */
3075 dj->sect = 0;
3076 res = FR_OK;
3077 }
3078 if (res == FR_OK) { /* A valid entry is found */
3079 get_fileinfo(dj, fno); /* Get the object information */
3080 res = dir_next(dj, 0); /* Increment index for next */
3081 if (res == FR_NO_FILE) {
3082 dj->sect = 0;
3083 res = FR_OK;
3084 }
3085 }
3086 FREE_BUF();
3087 }
3088 }
3089
3090 LEAVE_FF(dj->fs, res);
3091}
3092
3093
3094
3095#if _FS_MINIMIZE == 0
3096/*-----------------------------------------------------------------------*/
3097/* Get File Status */
3098/*-----------------------------------------------------------------------*/
3099
3100FRESULT f_stat (
3101 const TCHAR *path, /* Pointer to the file path */
3102 FILINFO *fno /* Pointer to file information to return */
3103)
3104{
3105 FRESULT res;
3106 DIR dj;
3107 DEF_NAMEBUF;
3108
3109
3110 res = chk_mounted(&path, &dj.fs, 0);
3111 if (res == FR_OK) {
3112 INIT_BUF(dj);
3113 res = follow_path(&dj, path); /* Follow the file path */
3114 if (res == FR_OK) { /* Follow completed */
3115 if (dj.dir) /* Found an object */
3116 get_fileinfo(&dj, fno);
3117 else /* It is root dir */
3118 res = FR_INVALID_NAME;
3119 }
3120 FREE_BUF();
3121 }
3122
3123 LEAVE_FF(dj.fs, res);
3124}
3125
3126
3127
3128#if !_FS_READONLY
3129/*-----------------------------------------------------------------------*/
3130/* Get Number of Free Clusters */
3131/*-----------------------------------------------------------------------*/
3132
3133FRESULT f_getfree (
3134 const TCHAR *path, /* Pointer to the logical drive number (root dir) */
3135 DWORD *nclst, /* Pointer to the variable to return number of free clusters */
3136 FATFS **fatfs /* Pointer to pointer to corresponding file system object to return */
3137)
3138{
3139 FRESULT res;
3140 FATFS *fs;
3141 DWORD n, clst, sect, stat;
3142 UINT i;
3143 BYTE fat, *p;
3144
3145
3146 /* Get drive number */
3147 res = chk_mounted(&path, fatfs, 0);
3148 fs = *fatfs;
3149 if (res == FR_OK) {
3150 /* If free_clust is valid, return it without full cluster scan */
3151 if (fs->free_clust <= fs->n_fatent - 2) {
3152 *nclst = fs->free_clust;
3153 } else {
3154 /* Get number of free clusters */
3155 fat = fs->fs_type;
3156 n = 0;
3157 if (fat == FS_FAT12) {
3158 clst = 2;
3159 do {
3160 stat = get_fat(fs, clst);
3161 if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
3162 if (stat == 1) { res = FR_INT_ERR; break; }
3163 if (stat == 0) n++;
3164 } while (++clst < fs->n_fatent);
3165 } else {
3166 clst = fs->n_fatent;
3167 sect = fs->fatbase;
3168 i = 0; p = 0;
3169 do {
3170 if (!i) {
3171 res = move_window(fs, sect++);
3172 if (res != FR_OK) break;
3173 p = fs->win;
3174 i = SS(fs);
3175 }
3176 if (fat == FS_FAT16) {
3177 if (LD_WORD(p) == 0) n++;
3178 p += 2; i -= 2;
3179 } else {
3180 if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
3181 p += 4; i -= 4;
3182 }
3183 } while (--clst);
3184 }
3185 fs->free_clust = n;
3186 if (fat == FS_FAT32) fs->fsi_flag = 1;
3187 *nclst = n;
3188 }
3189 }
3190 LEAVE_FF(fs, res);
3191}
3192
3193
3194
3195
3196/*-----------------------------------------------------------------------*/
3197/* Truncate File */
3198/*-----------------------------------------------------------------------*/
3199
3200FRESULT f_truncate (
3201 FIL *fp /* Pointer to the file object */
3202)
3203{
3204 FRESULT res;
3205 DWORD ncl;
3206
3207
3208 if (!fp) return FR_INVALID_OBJECT;
3209
3210 res = validate(fp); /* Check validity of the object */
3211 if (res == FR_OK) {
3212 if (fp->flag & FA__ERROR) { /* Check abort flag */
3213 res = FR_INT_ERR;
3214 } else {
3215 if (!(fp->flag & FA_WRITE)) /* Check access mode */
3216 res = FR_DENIED;
3217 }
3218 }
3219 if (res == FR_OK) {
3220 if (fp->fsize > fp->fptr) {
3221 fp->fsize = fp->fptr; /* Set file size to current R/W point */
3222 fp->flag |= FA__WRITTEN;
3223 if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */
3224 res = remove_chain(fp->fs, fp->sclust);
3225 fp->sclust = 0;
3226 } else { /* When truncate a part of the file, remove remaining clusters */
3227 ncl = get_fat(fp->fs, fp->clust);
3228 res = FR_OK;
3229 if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
3230 if (ncl == 1) res = FR_INT_ERR;
3231 if (res == FR_OK && ncl < fp->fs->n_fatent) {
3232 res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF);
3233 if (res == FR_OK) res = remove_chain(fp->fs, ncl);
3234 }
3235 }
3236 }
3237 if (res != FR_OK) fp->flag |= FA__ERROR;
3238 }
3239
3240 LEAVE_FF(fp->fs, res);
3241}
3242
3243
3244
3245
3246/*-----------------------------------------------------------------------*/
3247/* Delete a File or Directory */
3248/*-----------------------------------------------------------------------*/
3249
3250FRESULT f_unlink (
3251 const TCHAR *path /* Pointer to the file or directory path */
3252)
3253{
3254 FRESULT res;
3255 DIR dj, sdj;
3256 BYTE *dir;
3257 DWORD dclst;
3258 DEF_NAMEBUF;
3259
3260
3261 res = chk_mounted(&path, &dj.fs, 1);
3262 if (res == FR_OK) {
3263 INIT_BUF(dj);
3264 res = follow_path(&dj, path); /* Follow the file path */
3265 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
3266 res = FR_INVALID_NAME; /* Cannot remove dot entry */
3267#if _FS_LOCK
3268 if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open file */
3269#endif
3270 if (res == FR_OK) { /* The object is accessible */
3271 dir = dj.dir;
3272 if (!dir) {
3273 res = FR_INVALID_NAME; /* Cannot remove the start directory */
3274 } else {
3275 if (dir[DIR_Attr] & AM_RDO)
3276 res = FR_DENIED; /* Cannot remove R/O object */
3277 }
3278 dclst = ld_clust(dj.fs, dir);
3279 if (res == FR_OK && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-dir? */
3280 if (dclst < 2) {
3281 res = FR_INT_ERR;
3282 } else {
3283 mem_cpy(&sdj, &dj, sizeof (DIR)); /* Check if the sub-dir is empty or not */
3284 sdj.sclust = dclst;
3285 res = dir_sdi(&sdj, 2); /* Exclude dot entries */
3286 if (res == FR_OK) {
3287 res = dir_read(&sdj);
3288 if (res == FR_OK /* Not empty dir */
3289#if _FS_RPATH
3290 || dclst == dj.fs->cdir /* Current dir */
3291#endif
3292 ) res = FR_DENIED;
3293 if (res == FR_NO_FILE) res = FR_OK; /* Empty */
3294 }
3295 }
3296 }
3297 if (res == FR_OK) {
3298 res = dir_remove(&dj); /* Remove the directory entry */
3299 if (res == FR_OK) {
3300 if (dclst) /* Remove the cluster chain if exist */
3301 res = remove_chain(dj.fs, dclst);
3302 if (res == FR_OK) res = sync(dj.fs);
3303 }
3304 }
3305 }
3306 FREE_BUF();
3307 }
3308 LEAVE_FF(dj.fs, res);
3309}
3310
3311
3312
3313
3314/*-----------------------------------------------------------------------*/
3315/* Create a Directory */
3316/*-----------------------------------------------------------------------*/
3317
3318FRESULT f_mkdir (
3319 const TCHAR *path /* Pointer to the directory path */
3320)
3321{
3322 FRESULT res;
3323 DIR dj;
3324 BYTE *dir, n;
3325 DWORD dsc, dcl, pcl, tim = get_fattime();
3326 DEF_NAMEBUF;
3327
3328
3329 res = chk_mounted(&path, &dj.fs, 1);
3330 if (res == FR_OK) {
3331 INIT_BUF(dj);
3332 res = follow_path(&dj, path); /* Follow the file path */
3333 if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */
3334 if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
3335 res = FR_INVALID_NAME;
3336 if (res == FR_NO_FILE) { /* Can create a new directory */
3337 dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */
3338 res = FR_OK;
3339 if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */
3340 if (dcl == 1) res = FR_INT_ERR;
3341 if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
3342 if (res == FR_OK) /* Flush FAT */
3343 res = move_window(dj.fs, 0);
3344 if (res == FR_OK) { /* Initialize the new directory table */
3345 dsc = clust2sect(dj.fs, dcl);
3346 dir = dj.fs->win;
3347 mem_set(dir, 0, SS(dj.fs));
3348 mem_set(dir+DIR_Name, ' ', 8+3); /* Create "." entry */
3349 dir[DIR_Name] = '.';
3350 dir[DIR_Attr] = AM_DIR;
3351 ST_DWORD(dir+DIR_WrtTime, tim);
3352 st_clust(dir, dcl);
3353 mem_cpy(dir+SZ_DIR, dir, SZ_DIR); /* Create ".." entry */
3354 dir[33] = '.'; pcl = dj.sclust;
3355 if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
3356 pcl = 0;
3357 st_clust(dir+SZ_DIR, pcl);
3358 for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */
3359 dj.fs->winsect = dsc++;
3360 dj.fs->wflag = 1;
3361 res = move_window(dj.fs, 0);
3362 if (res != FR_OK) break;
3363 mem_set(dir, 0, SS(dj.fs));
3364 }
3365 }
3366 if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directory */
3367 if (res != FR_OK) {
3368 remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */
3369 } else {
3370 dir = dj.dir;
3371 dir[DIR_Attr] = AM_DIR; /* Attribute */
3372 ST_DWORD(dir+DIR_WrtTime, tim); /* Created time */
3373 st_clust(dir, dcl); /* Table start cluster */
3374 dj.fs->wflag = 1;
3375 res = sync(dj.fs);
3376 }
3377 }
3378 FREE_BUF();
3379 }
3380
3381 LEAVE_FF(dj.fs, res);
3382}
3383
3384
3385
3386
3387/*-----------------------------------------------------------------------*/
3388/* Change Attribute */
3389/*-----------------------------------------------------------------------*/
3390
3391FRESULT f_chmod (
3392 const TCHAR *path, /* Pointer to the file path */
3393 BYTE value, /* Attribute bits */
3394 BYTE mask /* Attribute mask to change */
3395)
3396{
3397 FRESULT res;
3398 DIR dj;
3399 BYTE *dir;
3400 DEF_NAMEBUF;
3401
3402
3403 res = chk_mounted(&path, &dj.fs, 1);
3404 if (res == FR_OK) {
3405 INIT_BUF(dj);
3406 res = follow_path(&dj, path); /* Follow the file path */
3407 FREE_BUF();
3408 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
3409 res = FR_INVALID_NAME;
3410 if (res == FR_OK) {
3411 dir = dj.dir;
3412 if (!dir) { /* Is it a root directory? */
3413 res = FR_INVALID_NAME;
3414 } else { /* File or sub directory */
3415 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
3416 dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
3417 dj.fs->wflag = 1;
3418 res = sync(dj.fs);
3419 }
3420 }
3421 }
3422
3423 LEAVE_FF(dj.fs, res);
3424}
3425
3426
3427
3428
3429/*-----------------------------------------------------------------------*/
3430/* Change Timestamp */
3431/*-----------------------------------------------------------------------*/
3432
3433FRESULT f_utime (
3434 const TCHAR *path, /* Pointer to the file/directory name */
3435 const FILINFO *fno /* Pointer to the time stamp to be set */
3436)
3437{
3438 FRESULT res;
3439 DIR dj;
3440 BYTE *dir;
3441 DEF_NAMEBUF;
3442
3443
3444 res = chk_mounted(&path, &dj.fs, 1);
3445 if (res == FR_OK) {
3446 INIT_BUF(dj);
3447 res = follow_path(&dj, path); /* Follow the file path */
3448 FREE_BUF();
3449 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
3450 res = FR_INVALID_NAME;
3451 if (res == FR_OK) {
3452 dir = dj.dir;
3453 if (!dir) { /* Root directory */
3454 res = FR_INVALID_NAME;
3455 } else { /* File or sub-directory */
3456 ST_WORD(dir+DIR_WrtTime, fno->ftime);
3457 ST_WORD(dir+DIR_WrtDate, fno->fdate);
3458 dj.fs->wflag = 1;
3459 res = sync(dj.fs);
3460 }
3461 }
3462 }
3463
3464 LEAVE_FF(dj.fs, res);
3465}
3466
3467
3468
3469
3470/*-----------------------------------------------------------------------*/
3471/* Rename File/Directory */
3472/*-----------------------------------------------------------------------*/
3473
3474FRESULT f_rename (
3475 const TCHAR *path_old, /* Pointer to the old name */
3476 const TCHAR *path_new /* Pointer to the new name */
3477)
3478{
3479 FRESULT res;
3480 DIR djo, djn;
3481 BYTE buf[21], *dir;
3482 DWORD dw;
3483 DEF_NAMEBUF;
3484
3485
3486 res = chk_mounted(&path_old, &djo.fs, 1);
3487 if (res == FR_OK) {
3488 djn.fs = djo.fs;
3489 INIT_BUF(djo);
3490 res = follow_path(&djo, path_old); /* Check old object */
3491 if (_FS_RPATH && res == FR_OK && (djo.fn[NS] & NS_DOT))
3492 res = FR_INVALID_NAME;
3493#if _FS_LOCK
3494 if (res == FR_OK) res = chk_lock(&djo, 2);
3495#endif
3496 if (res == FR_OK) { /* Old object is found */
3497 if (!djo.dir) { /* Is root dir? */
3498 res = FR_NO_FILE;
3499 } else {
3500 mem_cpy(buf, djo.dir+DIR_Attr, 21); /* Save the object information except for name */
3501 mem_cpy(&djn, &djo, sizeof (DIR)); /* Check new object */
3502 res = follow_path(&djn, path_new);
3503 if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */
3504 if (res == FR_NO_FILE) { /* Is it a valid path and no name collision? */
3505/* Start critical section that an interruption or error can cause cross-link */
3506 res = dir_register(&djn); /* Register the new entry */
3507 if (res == FR_OK) {
3508 dir = djn.dir; /* Copy object information except for name */
3509 mem_cpy(dir+13, buf+2, 19);
3510 dir[DIR_Attr] = buf[0] | AM_ARC;
3511 djo.fs->wflag = 1;
3512 if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) { /* Update .. entry in the directory if needed */
3513 dw = clust2sect(djo.fs, ld_clust(djo.fs, dir));
3514 if (!dw) {
3515 res = FR_INT_ERR;
3516 } else {
3517 res = move_window(djo.fs, dw);
3518 dir = djo.fs->win+SZ_DIR; /* .. entry */
3519 if (res == FR_OK && dir[1] == '.') {
3520 dw = (djo.fs->fs_type == FS_FAT32 && djn.sclust == djo.fs->dirbase) ? 0 : djn.sclust;
3521 st_clust(dir, dw);
3522 djo.fs->wflag = 1;
3523 }
3524 }
3525 }
3526 if (res == FR_OK) {
3527 res = dir_remove(&djo); /* Remove old entry */
3528 if (res == FR_OK)
3529 res = sync(djo.fs);
3530 }
3531 }
3532/* End critical section */
3533 }
3534 }
3535 }
3536 FREE_BUF();
3537 }
3538 LEAVE_FF(djo.fs, res);
3539}
3540
3541#endif /* !_FS_READONLY */
3542#endif /* _FS_MINIMIZE == 0 */
3543#endif /* _FS_MINIMIZE <= 1 */
3544#endif /* _FS_MINIMIZE <= 2 */
3545
3546
3547
3548/*-----------------------------------------------------------------------*/
3549/* Forward data to the stream directly (available on only tiny cfg) */
3550/*-----------------------------------------------------------------------*/
3551#if _USE_FORWARD && _FS_TINY
3552
3553FRESULT f_forward (
3554 FIL *fp, /* Pointer to the file object */
3555 UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
3556 UINT btr, /* Number of bytes to forward */
3557 UINT *bf /* Pointer to number of bytes forwarded */
3558)
3559{
3560 FRESULT res;
3561 DWORD remain, clst, sect;
3562 UINT rcnt;
3563 BYTE csect;
3564
3565
3566 *bf = 0; /* Clear transfer byte counter */
3567
3568 if (!fp) return FR_INVALID_OBJECT;
3569
3570 res = validate(fp); /* Check validity of the object */
3571 if (res != FR_OK) LEAVE_FF(fp->fs, res);
3572 if (fp->flag & FA__ERROR) /* Check error flag */
3573 LEAVE_FF(fp->fs, FR_INT_ERR);
3574 if (!(fp->flag & FA_READ)) /* Check access mode */
3575 LEAVE_FF(fp->fs, FR_DENIED);
3576
3577 remain = fp->fsize - fp->fptr;
3578 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
3579
3580 for ( ; btr && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */
3581 fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
3582 csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
3583 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
3584 if (!csect) { /* On the cluster boundary? */
3585 clst = (fp->fptr == 0) ? /* On the top of the file? */
3586 fp->sclust : get_fat(fp->fs, fp->clust);
3587 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
3588 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
3589 fp->clust = clst; /* Update current cluster */
3590 }
3591 }
3592 sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */
3593 if (!sect) ABORT(fp->fs, FR_INT_ERR);
3594 sect += csect;
3595 if (move_window(fp->fs, sect)) /* Move sector window */
3596 ABORT(fp->fs, FR_DISK_ERR);
3597 fp->dsect = sect;
3598 rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */
3599 if (rcnt > btr) rcnt = btr;
3600 rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
3601 if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
3602 }
3603
3604 LEAVE_FF(fp->fs, FR_OK);
3605}
3606#endif /* _USE_FORWARD */
3607
3608
3609
3610#if _USE_MKFS && !_FS_READONLY
3611/*-----------------------------------------------------------------------*/
3612/* Create File System on the Drive */
3613/*-----------------------------------------------------------------------*/
3614#define N_ROOTDIR 512 /* Number of root dir entries for FAT12/16 */
3615#define N_FATS 1 /* Number of FAT copies (1 or 2) */
3616
3617
3618FRESULT f_mkfs (
3619 BYTE drv, /* Logical drive number */
3620 BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */
3621 UINT au /* Allocation unit size [bytes] */
3622)
3623{
3624 static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0};
3625 static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
3626 BYTE fmt, md, sys, *tbl, pdrv, part;
3627 DWORD n_clst, vs, n, wsect;
3628 UINT i;
3629 DWORD b_vol, b_fat, b_dir, b_data; /* LBA */
3630 DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */
3631 FATFS *fs;
3632 DSTATUS stat;
3633
3634
3635 /* Check mounted drive and clear work area */
3636 if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
3637 if (sfd > 1) return FR_INVALID_PARAMETER;
3638 if (au & (au - 1)) return FR_INVALID_PARAMETER;
3639 fs = FatFs[drv];
3640 if (!fs) return FR_NOT_ENABLED;
3641 fs->fs_type = 0;
3642 pdrv = LD2PD(drv); /* Physical drive */
3643 part = LD2PT(drv); /* Partition (0:auto detect, 1-4:get from partition table)*/
3644
3645 /* Get disk statics */
3646 stat = disk_initialize(pdrv);
3647 if (stat & STA_NOINIT) return FR_NOT_READY;
3648 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
3649#if _MAX_SS != 512 /* Get disk sector size */
3650 if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
3651 return FR_DISK_ERR;
3652#endif
3653 if (_MULTI_PARTITION && part) {
3654 /* Get partition information from partition table in the MBR */
3655 if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
3656 if (LD_WORD(fs->win+BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;
3657 tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
3658 if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */
3659 b_vol = LD_DWORD(tbl+8); /* Volume start sector */
3660 n_vol = LD_DWORD(tbl+12); /* Volume size */
3661 } else {
3662 /* Create a partition in this function */
3663 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
3664 return FR_DISK_ERR;
3665 b_vol = (sfd) ? 0 : 63; /* Volume start sector */
3666 n_vol -= b_vol; /* Volume size */
3667 }
3668
3669 if (!au) { /* AU auto selection */
3670 vs = n_vol / (2000 / (SS(fs) / 512));
3671 for (i = 0; vs < vst[i]; i++) ;
3672 au = cst[i];
3673 }
3674 au /= SS(fs); /* Number of sectors per cluster */
3675 if (au == 0) au = 1;
3676 if (au > 128) au = 128;
3677
3678 /* Pre-compute number of clusters and FAT sub-type */
3679 n_clst = n_vol / au;
3680 fmt = FS_FAT12;
3681 if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
3682 if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
3683
3684 /* Determine offset and size of FAT structure */
3685 if (fmt == FS_FAT32) {
3686 n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
3687 n_rsv = 32;
3688 n_dir = 0;
3689 } else {
3690 n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
3691 n_fat = (n_fat + SS(fs) - 1) / SS(fs);
3692 n_rsv = 1;
3693 n_dir = (DWORD)N_ROOTDIR * SZ_DIR / SS(fs);
3694 }
3695 b_fat = b_vol + n_rsv; /* FAT area start sector */
3696 b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */
3697 b_data = b_dir + n_dir; /* Data area start sector */
3698 if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */
3699
3700 /* Align data start sector to erase block boundary (for flash memory media) */
3701 if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
3702 n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */
3703 n = (n - b_data) / N_FATS;
3704 if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */
3705 n_rsv += n;
3706 b_fat += n;
3707 } else { /* FAT12/16: Expand FAT size */
3708 n_fat += n;
3709 }
3710
3711 /* Determine number of clusters and final check of validity of the FAT sub-type */
3712 n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
3713 if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16)
3714 || (fmt == FS_FAT32 && n_clst < MIN_FAT32))
3715 return FR_MKFS_ABORTED;
3716
3717 switch (fmt) { /* Determine system ID for partition table */
3718 case FS_FAT12: sys = 0x01; break;
3719 case FS_FAT16: sys = (n_vol < 0x10000) ? 0x04 : 0x06; break;
3720 default: sys = 0x0C;
3721 }
3722
3723 if (_MULTI_PARTITION && part) {
3724 /* Update system ID in the partition table */
3725 tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
3726 tbl[4] = sys;
3727 if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
3728 md = 0xF8;
3729 } else {
3730 if (sfd) { /* No partition table (SFD) */
3731 md = 0xF0;
3732 } else { /* Create partition table (FDISK) */
3733 mem_set(fs->win, 0, SS(fs));
3734 tbl = fs->win+MBR_Table; /* Create partition table for single partition in the drive */
3735 tbl[1] = 1; /* Partition start head */
3736 tbl[2] = 1; /* Partition start sector */
3737 tbl[3] = 0; /* Partition start cylinder */
3738 tbl[4] = sys; /* System type */
3739 tbl[5] = 254; /* Partition end head */
3740 n = (b_vol + n_vol) / 63 / 255;
3741 tbl[6] = (BYTE)((n >> 2) | 63); /* Partition end sector */
3742 tbl[7] = (BYTE)n; /* End cylinder */
3743 ST_DWORD(tbl+8, 63); /* Partition start in LBA */
3744 ST_DWORD(tbl+12, n_vol); /* Partition size in LBA */
3745 ST_WORD(fs->win+BS_55AA, 0xAA55); /* MBR signature */
3746 if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR sector */
3747 return FR_DISK_ERR;
3748 md = 0xF8;
3749 }
3750 }
3751
3752 /* Create BPB in the VBR */
3753 tbl = fs->win; /* Clear sector */
3754 mem_set(tbl, 0, SS(fs));
3755 mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */
3756 i = SS(fs); /* Sector size */
3757 ST_WORD(tbl+BPB_BytsPerSec, i);
3758 tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */
3759 ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */
3760 tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */
3761 i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of rootdir entries */
3762 ST_WORD(tbl+BPB_RootEntCnt, i);
3763 if (n_vol < 0x10000) { /* Number of total sectors */
3764 ST_WORD(tbl+BPB_TotSec16, n_vol);
3765 } else {
3766 ST_DWORD(tbl+BPB_TotSec32, n_vol);
3767 }
3768 tbl[BPB_Media] = md; /* Media descriptor */
3769 ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */
3770 ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */
3771 ST_DWORD(tbl+BPB_HiddSec, b_vol); /* Hidden sectors */
3772 n = get_fattime(); /* Use current time as VSN */
3773 if (fmt == FS_FAT32) {
3774 ST_DWORD(tbl+BS_VolID32, n); /* VSN */
3775 ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of sectors per FAT */
3776 ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory start cluster (2) */
3777 ST_WORD(tbl+BPB_FSInfo, 1); /* FSInfo record offset (VBR+1) */
3778 ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (VBR+6) */
3779 tbl[BS_DrvNum32] = 0x80; /* Drive number */
3780 tbl[BS_BootSig32] = 0x29; /* Extended boot signature */
3781 mem_cpy(tbl+BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */
3782 } else {
3783 ST_DWORD(tbl+BS_VolID, n); /* VSN */
3784 ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of sectors per FAT */
3785 tbl[BS_DrvNum] = 0x80; /* Drive number */
3786 tbl[BS_BootSig] = 0x29; /* Extended boot signature */
3787 mem_cpy(tbl+BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */
3788 }
3789 ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */
3790 if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */
3791 return FR_DISK_ERR;
3792 if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR+6) */
3793 disk_write(pdrv, tbl, b_vol + 6, 1);
3794
3795 /* Initialize FAT area */
3796 wsect = b_fat;
3797 for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */
3798 mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */
3799 n = md; /* Media descriptor byte */
3800 if (fmt != FS_FAT32) {
3801 n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
3802 ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT12/16) */
3803 } else {
3804 n |= 0xFFFFFF00;
3805 ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT32) */
3806 ST_DWORD(tbl+4, 0xFFFFFFFF);
3807 ST_DWORD(tbl+8, 0x0FFFFFFF); /* Reserve cluster #2 for root dir */
3808 }
3809 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
3810 return FR_DISK_ERR;
3811 mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */
3812 for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */
3813 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
3814 return FR_DISK_ERR;
3815 }
3816 }
3817
3818 /* Initialize root directory */
3819 i = (fmt == FS_FAT32) ? au : n_dir;
3820 do {
3821 if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
3822 return FR_DISK_ERR;
3823 } while (--i);
3824
3825#if _USE_ERASE /* Erase data area if needed */
3826 {
3827 DWORD eb[2];
3828
3829 eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
3830 disk_ioctl(pdrv, CTRL_ERASE_SECTOR, eb);
3831 }
3832#endif
3833
3834 /* Create FSInfo if needed */
3835 if (fmt == FS_FAT32) {
3836 ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
3837 ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
3838 ST_DWORD(tbl+FSI_Free_Count, n_clst - 1); /* Number of free clusters */
3839 ST_DWORD(tbl+FSI_Nxt_Free, 2); /* Last allocated cluster# */
3840 ST_WORD(tbl+BS_55AA, 0xAA55);
3841 disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR+1) */
3842 disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR+7) */
3843 }
3844
3845 return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
3846}
3847
3848
3849#if _MULTI_PARTITION == 2
3850/*-----------------------------------------------------------------------*/
3851/* Divide Physical Drive */
3852/*-----------------------------------------------------------------------*/
3853
3854FRESULT f_fdisk (
3855 BYTE pdrv, /* Physical drive number */
3856 const DWORD szt[], /* Pointer to the size table for each partitions */
3857 void* work /* Pointer to the working buffer */
3858)
3859{
3860 UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;
3861 BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;
3862 DSTATUS stat;
3863 DWORD sz_disk, sz_part, s_part;
3864
3865
3866 stat = disk_initialize(pdrv);
3867 if (stat & STA_NOINIT) return FR_NOT_READY;
3868 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
3869 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR;
3870
3871 /* Determine CHS in the table regardless of the drive geometry */
3872 for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ;
3873 if (n == 256) n--;
3874 e_hd = n - 1;
3875 sz_cyl = 63 * n;
3876 tot_cyl = sz_disk / sz_cyl;
3877
3878 /* Create partition table */
3879 mem_set(buf, 0, _MAX_SS);
3880 p = buf + MBR_Table; b_cyl = 0;
3881 for (i = 0; i < 4; i++, p += SZ_PTE) {
3882 p_cyl = (szt[i] <= 100) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl;
3883 if (!p_cyl) continue;
3884 s_part = (DWORD)sz_cyl * b_cyl;
3885 sz_part = (DWORD)sz_cyl * p_cyl;
3886 if (i == 0) { /* Exclude first track of cylinder 0 */
3887 s_hd = 1;
3888 s_part += 63; sz_part -= 63;
3889 } else {
3890 s_hd = 0;
3891 }
3892 e_cyl = b_cyl + p_cyl - 1;
3893 if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER;
3894
3895 /* Set partition table */
3896 p[1] = s_hd; /* Start head */
3897 p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */
3898 p[3] = (BYTE)b_cyl; /* Start cylinder */
3899 p[4] = 0x06; /* System type (temporary setting) */
3900 p[5] = e_hd; /* End head */
3901 p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */
3902 p[7] = (BYTE)e_cyl; /* End cylinder */
3903 ST_DWORD(p + 8, s_part); /* Start sector in LBA */
3904 ST_DWORD(p + 12, sz_part); /* Partition size */
3905
3906 /* Next partition */
3907 b_cyl += p_cyl;
3908 }
3909 ST_WORD(p, 0xAA55);
3910
3911 /* Write it to the MBR */
3912 return (disk_write(pdrv, buf, 0, 1) || disk_ioctl(pdrv, CTRL_SYNC, 0)) ? FR_DISK_ERR : FR_OK;
3913}
3914
3915
3916#endif /* _MULTI_PARTITION == 2 */
3917#endif /* _USE_MKFS && !_FS_READONLY */
3918
3919
3920
3921
3922#if _USE_STRFUNC
3923/*-----------------------------------------------------------------------*/
3924/* Get a string from the file */
3925/*-----------------------------------------------------------------------*/
3926TCHAR* f_gets (
3927 TCHAR* buff, /* Pointer to the string buffer to read */
3928 int len, /* Size of string buffer (characters) */
3929 FIL* fil /* Pointer to the file object */
3930)
3931{
3932 int n = 0;
3933 TCHAR c, *p = buff;
3934 BYTE s[2];
3935 UINT rc;
3936
3937
3938 while (n < len - 1) { /* Read bytes until buffer gets filled */
3939 f_read(fil, s, 1, &rc);
3940 if (rc != 1) break; /* Break on EOF or error */
3941 c = s[0];
3942#if _LFN_UNICODE /* Read a character in UTF-8 encoding */
3943 if (c >= 0x80) {
3944 if (c < 0xC0) continue; /* Skip stray trailer */
3945 if (c < 0xE0) { /* Two-byte sequence */
3946 f_read(fil, s, 1, &rc);
3947 if (rc != 1) break;
3948 c = ((c & 0x1F) << 6) | (s[0] & 0x3F);
3949 if (c < 0x80) c = '?';
3950 } else {
3951 if (c < 0xF0) { /* Three-byte sequence */
3952 f_read(fil, s, 2, &rc);
3953 if (rc != 2) break;
3954 c = (c << 12) | ((s[0] & 0x3F) << 6) | (s[1] & 0x3F);
3955 if (c < 0x800) c = '?';
3956 } else { /* Reject four-byte sequence */
3957 c = '?';
3958 }
3959 }
3960 }
3961#endif
3962#if _USE_STRFUNC >= 2
3963 if (c == '\r') continue; /* Strip '\r' */
3964#endif
3965 *p++ = c;
3966 n++;
3967 if (c == '\n') break; /* Break on EOL */
3968 }
3969 *p = 0;
3970 return n ? buff : 0; /* When no data read (eof or error), return with error. */
3971}
3972
3973
3974
3975#if !_FS_READONLY
3976#include <stdarg.h>
3977/*-----------------------------------------------------------------------*/
3978/* Put a character to the file */
3979/*-----------------------------------------------------------------------*/
3980int f_putc (
3981 TCHAR c, /* A character to be output */
3982 FIL* fil /* Pointer to the file object */
3983)
3984{
3985 UINT bw, btw;
3986 BYTE s[3];
3987
3988
3989#if _USE_STRFUNC >= 2
3990 if (c == '\n') f_putc ('\r', fil); /* LF -> CRLF conversion */
3991#endif
3992
3993#if _LFN_UNICODE /* Write the character in UTF-8 encoding */
3994 if (c < 0x80) { /* 7-bit */
3995 s[0] = (BYTE)c;
3996 btw = 1;
3997 } else {
3998 if (c < 0x800) { /* 11-bit */
3999 s[0] = (BYTE)(0xC0 | (c >> 6));
4000 s[1] = (BYTE)(0x80 | (c & 0x3F));
4001 btw = 2;
4002 } else { /* 16-bit */
4003 s[0] = (BYTE)(0xE0 | (c >> 12));
4004 s[1] = (BYTE)(0x80 | ((c >> 6) & 0x3F));
4005 s[2] = (BYTE)(0x80 | (c & 0x3F));
4006 btw = 3;
4007 }
4008 }
4009#else /* Write the character without conversion */
4010 s[0] = (BYTE)c;
4011 btw = 1;
4012#endif
4013 f_write(fil, s, btw, &bw); /* Write the char to the file */
4014 return (bw == btw) ? 1 : EOF; /* Return the result */
4015}
4016
4017
4018
4019
4020/*-----------------------------------------------------------------------*/
4021/* Put a string to the file */
4022/*-----------------------------------------------------------------------*/
4023int f_puts (
4024 const TCHAR* str, /* Pointer to the string to be output */
4025 FIL* fil /* Pointer to the file object */
4026)
4027{
4028 int n;
4029
4030
4031 for (n = 0; *str; str++, n++) {
4032 if (f_putc(*str, fil) == EOF) return EOF;
4033 }
4034 return n;
4035}
4036
4037
4038
4039
4040/*-----------------------------------------------------------------------*/
4041/* Put a formatted string to the file */
4042/*-----------------------------------------------------------------------*/
4043int f_printf (
4044 FIL* fil, /* Pointer to the file object */
4045 const TCHAR* str, /* Pointer to the format string */
4046 ... /* Optional arguments... */
4047)
4048{
4049 va_list arp;
4050 BYTE f, r;
4051 UINT i, j, w;
4052 ULONG v;
4053 TCHAR c, d, s[16], *p;
4054 int res, chc, cc;
4055
4056
4057 va_start(arp, str);
4058
4059 for (cc = res = 0; cc != EOF; res += cc) {
4060 c = *str++;
4061 if (c == 0) break; /* End of string */
4062 if (c != '%') { /* Non escape character */
4063 cc = f_putc(c, fil);
4064 if (cc != EOF) cc = 1;
4065 continue;
4066 }
4067 w = f = 0;
4068 c = *str++;
4069 if (c == '0') { /* Flag: '0' padding */
4070 f = 1; c = *str++;
4071 } else {
4072 if (c == '-') { /* Flag: left justified */
4073 f = 2; c = *str++;
4074 }
4075 }
4076 while (IsDigit(c)) { /* Precision */
4077 w = w * 10 + c - '0';
4078 c = *str++;
4079 }
4080 if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
4081 f |= 4; c = *str++;
4082 }
4083 if (!c) break;
4084 d = c;
4085 if (IsLower(d)) d -= 0x20;
4086 switch (d) { /* Type is... */
4087 case 'S' : /* String */
4088 p = va_arg(arp, TCHAR*);
4089 for (j = 0; p[j]; j++) ;
4090 chc = 0;
4091 if (!(f & 2)) {
4092 while (j++ < w) chc += (cc = f_putc(' ', fil));
4093 }
4094 chc += (cc = f_puts(p, fil));
4095 while (j++ < w) chc += (cc = f_putc(' ', fil));
4096 if (cc != EOF) cc = chc;
4097 continue;
4098 case 'C' : /* Character */
4099 cc = f_putc((TCHAR)va_arg(arp, int), fil); continue;
4100 case 'B' : /* Binary */
4101 r = 2; break;
4102 case 'O' : /* Octal */
4103 r = 8; break;
4104 case 'D' : /* Signed decimal */
4105 case 'U' : /* Unsigned decimal */
4106 r = 10; break;
4107 case 'X' : /* Hexdecimal */
4108 r = 16; break;
4109 default: /* Unknown type (pass-through) */
4110 cc = f_putc(c, fil); continue;
4111 }
4112
4113 /* Get an argument and put it in numeral */
4114 v = (f & 4) ? (ULONG)va_arg(arp, long) : ((d == 'D') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int));
4115 if (d == 'D' && (v & 0x80000000)) {
4116 v = 0 - v;
4117 f |= 8;
4118 }
4119 i = 0;
4120 do {
4121 d = (TCHAR)(v % r); v /= r;
4122 if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
4123 s[i++] = d + '0';
4124 } while (v && i < sizeof s / sizeof s[0]);
4125 if (f & 8) s[i++] = '-';
4126 j = i; d = (f & 1) ? '0' : ' ';
4127 res = 0;
4128 while (!(f & 2) && j++ < w) res += (cc = f_putc(d, fil));
4129 do res += (cc = f_putc(s[--i], fil)); while(i);
4130 while (j++ < w) res += (cc = f_putc(' ', fil));
4131 if (cc != EOF) cc = res;
4132 }
4133
4134 va_end(arp);
4135 return (cc == EOF) ? cc : res;
4136}
4137
4138#endif /* !_FS_READONLY */
4139#endif /* _USE_STRFUNC */
diff --git a/lib/lufa/Projects/Webserver/Lib/FATFs/ff.h b/lib/lufa/Projects/Webserver/Lib/FATFs/ff.h
deleted file mode 100644
index 627cbaabe..000000000
--- a/lib/lufa/Projects/Webserver/Lib/FATFs/ff.h
+++ /dev/null
@@ -1,337 +0,0 @@
1/*---------------------------------------------------------------------------/
2/ FatFs - FAT file system module include file R0.09a (C)ChaN, 2012
3/----------------------------------------------------------------------------/
4/ FatFs module is a generic FAT file system module for small embedded systems.
5/ This is a free software that opened for education, research and commercial
6/ developments under license policy of following terms.
7/
8/ Copyright (C) 2012, ChaN, all right reserved.
9/
10/ * The FatFs module is a free software and there is NO WARRANTY.
11/ * No restriction on use. You can use, modify and redistribute it for
12/ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
13/ * Redistributions of source code must retain the above copyright notice.
14/
15/----------------------------------------------------------------------------*/
16
17#ifndef _FATFS
18#define _FATFS 4004 /* Revision ID */
19
20#ifdef __cplusplus
21extern "C" {
22#endif
23
24#include "integer.h" /* Basic integer types */
25#include "ffconf.h" /* FatFs configuration options */
26
27#if _FATFS != _FFCONF
28#error Wrong configuration file (ffconf.h).
29#endif
30
31
32
33/* Definitions of volume management */
34
35#if _MULTI_PARTITION /* Multiple partition configuration */
36typedef struct {
37 BYTE pd; /* Physical drive number */
38 BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
39} PARTITION;
40extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
41#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
42#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
43
44#else /* Single partition configuration */
45#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
46#define LD2PT(vol) 0 /* Always mounts the 1st partition or in SFD */
47
48#endif
49
50
51
52/* Type of path name strings on FatFs API */
53
54#if _LFN_UNICODE /* Unicode string */
55#if !_USE_LFN
56#error _LFN_UNICODE must be 0 in non-LFN cfg.
57#endif
58#ifndef _INC_TCHAR
59typedef WCHAR TCHAR;
60#define _T(x) L ## x
61#define _TEXT(x) L ## x
62#endif
63
64#else /* ANSI/OEM string */
65#ifndef _INC_TCHAR
66typedef char TCHAR;
67#define _T(x) x
68#define _TEXT(x) x
69#endif
70
71#endif
72
73
74
75/* File system object structure (FATFS) */
76
77typedef struct {
78 BYTE fs_type; /* FAT sub-type (0:Not mounted) */
79 BYTE drv; /* Physical drive number */
80 BYTE csize; /* Sectors per cluster (1,2,4...128) */
81 BYTE n_fats; /* Number of FAT copies (1,2) */
82 BYTE wflag; /* win[] dirty flag (1:must be written back) */
83 BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
84 WORD id; /* File system mount ID */
85 WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
86#if _MAX_SS != 512
87 WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
88#endif
89#if _FS_REENTRANT
90 _SYNC_t sobj; /* Identifier of sync object */
91#endif
92#if !_FS_READONLY
93 DWORD last_clust; /* Last allocated cluster */
94 DWORD free_clust; /* Number of free clusters */
95 DWORD fsi_sector; /* fsinfo sector (FAT32) */
96#endif
97#if _FS_RPATH
98 DWORD cdir; /* Current directory start cluster (0:root) */
99#endif
100 DWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */
101 DWORD fsize; /* Sectors per FAT */
102 DWORD fatbase; /* FAT start sector */
103 DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
104 DWORD database; /* Data start sector */
105 DWORD winsect; /* Current sector appearing in the win[] */
106 BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */
107} FATFS;
108
109
110
111/* File object structure (FIL) */
112
113typedef struct {
114 FATFS* fs; /* Pointer to the related file system object */
115 WORD id; /* File system mount ID of the related file system object */
116 BYTE flag; /* File status flags */
117 BYTE pad1;
118 DWORD fptr; /* File read/write pointer (0ed on file open) */
119 DWORD fsize; /* File size */
120 DWORD sclust; /* File data start cluster (0:no data cluster, always 0 when fsize is 0) */
121 DWORD clust; /* Current cluster of fpter */
122 DWORD dsect; /* Current data sector of fpter */
123#if !_FS_READONLY
124 DWORD dir_sect; /* Sector containing the directory entry */
125 BYTE* dir_ptr; /* Pointer to the directory entry in the window */
126#endif
127#if _USE_FASTSEEK
128 DWORD* cltbl; /* Pointer to the cluster link map table (null on file open) */
129#endif
130#if _FS_LOCK
131 UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
132#endif
133#if !_FS_TINY
134 BYTE buf[_MAX_SS]; /* File data read/write buffer */
135#endif
136} FIL;
137
138
139
140/* Directory object structure (DIR) */
141
142typedef struct {
143 FATFS* fs; /* Pointer to the owner file system object */
144 WORD id; /* Owner file system mount ID */
145 WORD index; /* Current read/write index number */
146 DWORD sclust; /* Table start cluster (0:Root dir) */
147 DWORD clust; /* Current cluster */
148 DWORD sect; /* Current sector */
149 BYTE* dir; /* Pointer to the current SFN entry in the win[] */
150 BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
151#if _USE_LFN
152 WCHAR* lfn; /* Pointer to the LFN working buffer */
153 WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
154#endif
155} DIR;
156
157
158
159/* File status structure (FILINFO) */
160
161typedef struct {
162 DWORD fsize; /* File size */
163 WORD fdate; /* Last modified date */
164 WORD ftime; /* Last modified time */
165 BYTE fattrib; /* Attribute */
166 TCHAR fname[13]; /* Short file name (8.3 format) */
167#if _USE_LFN
168 TCHAR* lfname; /* Pointer to the LFN buffer */
169 UINT lfsize; /* Size of LFN buffer in TCHAR */
170#endif
171} FILINFO;
172
173
174
175/* File function return code (FRESULT) */
176
177typedef enum {
178 FR_OK = 0, /* (0) Succeeded */
179 FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
180 FR_INT_ERR, /* (2) Assertion failed */
181 FR_NOT_READY, /* (3) The physical drive cannot work */
182 FR_NO_FILE, /* (4) Could not find the file */
183 FR_NO_PATH, /* (5) Could not find the path */
184 FR_INVALID_NAME, /* (6) The path name format is invalid */
185 FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
186 FR_EXIST, /* (8) Access denied due to prohibited access */
187 FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
188 FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
189 FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
190 FR_NOT_ENABLED, /* (12) The volume has no work area */
191 FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
192 FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
193 FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
194 FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
195 FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
196 FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
197 FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
198} FRESULT;
199
200
201
202/*--------------------------------------------------------------*/
203/* FatFs module application interface */
204
205FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
206FRESULT f_open (FIL*, const TCHAR*, BYTE); /* Open or create a file */
207FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
208FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
209FRESULT f_close (FIL*); /* Close an open file object */
210FRESULT f_opendir (DIR*, const TCHAR*); /* Open an existing directory */
211FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
212FRESULT f_stat (const TCHAR*, FILINFO*); /* Get file status */
213FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
214FRESULT f_getfree (const TCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
215FRESULT f_truncate (FIL*); /* Truncate file */
216FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
217FRESULT f_unlink (const TCHAR*); /* Delete an existing file or directory */
218FRESULT f_mkdir (const TCHAR*); /* Create a new directory */
219FRESULT f_chmod (const TCHAR*, BYTE, BYTE); /* Change attribute of the file/dir */
220FRESULT f_utime (const TCHAR*, const FILINFO*); /* Change times-tamp of the file/dir */
221FRESULT f_rename (const TCHAR*, const TCHAR*); /* Rename/Move a file or directory */
222FRESULT f_chdrive (BYTE); /* Change current drive */
223FRESULT f_chdir (const TCHAR*); /* Change current directory */
224FRESULT f_getcwd (TCHAR*, UINT); /* Get current directory */
225FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */
226FRESULT f_mkfs (BYTE, BYTE, UINT); /* Create a file system on the drive */
227FRESULT f_fdisk (BYTE, const DWORD[], void*); /* Divide a physical drive into some partitions */
228int f_putc (TCHAR, FIL*); /* Put a character to the file */
229int f_puts (const TCHAR*, FIL*); /* Put a string to the file */
230int f_printf (FIL*, const TCHAR*, ...); /* Put a formatted string to the file */
231TCHAR* f_gets (TCHAR*, int, FIL*); /* Get a string from the file */
232
233#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
234#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
235#define f_tell(fp) ((fp)->fptr)
236#define f_size(fp) ((fp)->fsize)
237
238#ifndef EOF
239#define EOF (-1)
240#endif
241
242
243
244
245/*--------------------------------------------------------------*/
246/* Additional user defined functions */
247
248/* RTC function */
249#if !_FS_READONLY
250DWORD get_fattime (void);
251#endif
252
253/* Unicode support functions */
254#if _USE_LFN /* Unicode - OEM code conversion */
255WCHAR ff_convert (WCHAR, UINT); /* OEM-Unicode bidirectional conversion */
256WCHAR ff_wtoupper (WCHAR); /* Unicode upper-case conversion */
257#if _USE_LFN == 3 /* Memory functions */
258void* ff_memalloc (UINT); /* Allocate memory block */
259void ff_memfree (void*); /* Free memory block */
260#endif
261#endif
262
263/* Sync functions */
264#if _FS_REENTRANT
265int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */
266int ff_req_grant (_SYNC_t); /* Lock sync object */
267void ff_rel_grant (_SYNC_t); /* Unlock sync object */
268int ff_del_syncobj (_SYNC_t); /* Delete a sync object */
269#endif
270
271
272
273
274/*--------------------------------------------------------------*/
275/* Flags and offset address */
276
277
278/* File access control and file status flags (FIL.flag) */
279
280#define FA_READ 0x01
281#define FA_OPEN_EXISTING 0x00
282#define FA__ERROR 0x80
283
284#if !_FS_READONLY
285#define FA_WRITE 0x02
286#define FA_CREATE_NEW 0x04
287#define FA_CREATE_ALWAYS 0x08
288#define FA_OPEN_ALWAYS 0x10
289#define FA__WRITTEN 0x20
290#define FA__DIRTY 0x40
291#endif
292
293
294/* FAT sub type (FATFS.fs_type) */
295
296#define FS_FAT12 1
297#define FS_FAT16 2
298#define FS_FAT32 3
299
300
301/* File attribute bits for directory entry */
302
303#define AM_RDO 0x01 /* Read only */
304#define AM_HID 0x02 /* Hidden */
305#define AM_SYS 0x04 /* System */
306#define AM_VOL 0x08 /* Volume label */
307#define AM_LFN 0x0F /* LFN entry */
308#define AM_DIR 0x10 /* Directory */
309#define AM_ARC 0x20 /* Archive */
310#define AM_MASK 0x3F /* Mask of defined bits */
311
312
313/* Fast seek feature */
314#define CREATE_LINKMAP 0xFFFFFFFF
315
316
317
318/*--------------------------------*/
319/* Multi-byte word access macros */
320
321#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
322#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
323#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
324#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
325#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
326#else /* Use byte-by-byte access to the FAT structure */
327#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
328#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
329#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
330#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
331#endif
332
333#ifdef __cplusplus
334}
335#endif
336
337#endif /* _FATFS */
diff --git a/lib/lufa/Projects/Webserver/Lib/FATFs/ffconf.h b/lib/lufa/Projects/Webserver/Lib/FATFs/ffconf.h
deleted file mode 100644
index 243a20fa2..000000000
--- a/lib/lufa/Projects/Webserver/Lib/FATFs/ffconf.h
+++ /dev/null
@@ -1,190 +0,0 @@
1/*---------------------------------------------------------------------------/
2/ FatFs - FAT file system module configuration file R0.09a (C)ChaN, 2012
3/----------------------------------------------------------------------------/
4/
5/ CAUTION! Do not forget to make clean the project after any changes to
6/ the configuration options.
7/
8/----------------------------------------------------------------------------*/
9#ifndef _FFCONF
10#define _FFCONF 4004 /* Revision ID */
11
12
13/*---------------------------------------------------------------------------/
14/ Function and Buffer Configurations
15/----------------------------------------------------------------------------*/
16
17#define _FS_TINY 1 /* 0:Normal or 1:Tiny */
18/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
19/ object instead of the sector buffer in the individual file object for file
20/ data transfer. This reduces memory consumption 512 bytes each file object. */
21
22
23#define _FS_READONLY 1 /* 0:Read/Write or 1:Read only */
24/* Setting _FS_READONLY to 1 defines read only configuration. This removes
25/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
26/ f_truncate and useless f_getfree. */
27
28
29#define _FS_MINIMIZE 2 /* 0 to 3 */
30/* The _FS_MINIMIZE option defines minimization level to remove some functions.
31/
32/ 0: Full function.
33/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
34/ are removed.
35/ 2: f_opendir and f_readdir are removed in addition to 1.
36/ 3: f_lseek is removed in addition to 2. */
37
38
39#define _USE_STRFUNC 0 /* 0:Disable or 1-2:Enable */
40/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
41
42
43#define _USE_MKFS 0 /* 0:Disable or 1:Enable */
44/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
45
46
47#define _USE_FORWARD 0 /* 0:Disable or 1:Enable */
48/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
49
50
51#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */
52/* To enable fast seek feature, set _USE_FASTSEEK to 1. */
53
54
55
56/*---------------------------------------------------------------------------/
57/ Locale and Namespace Configurations
58/----------------------------------------------------------------------------*/
59
60#define _CODE_PAGE 932
61/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
62/ Incorrect setting of the code page can cause a file open failure.
63/
64/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows)
65/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows)
66/ 949 - Korean (DBCS, OEM, Windows)
67/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows)
68/ 1250 - Central Europe (Windows)
69/ 1251 - Cyrillic (Windows)
70/ 1252 - Latin 1 (Windows)
71/ 1253 - Greek (Windows)
72/ 1254 - Turkish (Windows)
73/ 1255 - Hebrew (Windows)
74/ 1256 - Arabic (Windows)
75/ 1257 - Baltic (Windows)
76/ 1258 - Vietnam (OEM, Windows)
77/ 437 - U.S. (OEM)
78/ 720 - Arabic (OEM)
79/ 737 - Greek (OEM)
80/ 775 - Baltic (OEM)
81/ 850 - Multilingual Latin 1 (OEM)
82/ 858 - Multilingual Latin 1 + Euro (OEM)
83/ 852 - Latin 2 (OEM)
84/ 855 - Cyrillic (OEM)
85/ 866 - Russian (OEM)
86/ 857 - Turkish (OEM)
87/ 862 - Hebrew (OEM)
88/ 874 - Thai (OEM, Windows)
89/ 1 - ASCII only (Valid for non LFN cfg.)
90*/
91
92
93#define _USE_LFN 0 /* 0 to 3 */
94#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
95/* The _USE_LFN option switches the LFN support.
96/
97/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
98/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
99/ 2: Enable LFN with dynamic working buffer on the STACK.
100/ 3: Enable LFN with dynamic working buffer on the HEAP.
101/
102/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
103/ Unicode handling functions ff_convert() and ff_wtoupper() must be added
104/ to the project. When enable to use heap, memory control functions
105/ ff_memalloc() and ff_memfree() must be added to the project. */
106
107
108#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */
109/* To switch the character code set on FatFs API to Unicode,
110/ enable LFN feature and set _LFN_UNICODE to 1. */
111
112
113#define _FS_RPATH 0 /* 0 to 2 */
114/* The _FS_RPATH option configures relative path feature.
115/
116/ 0: Disable relative path feature and remove related functions.
117/ 1: Enable relative path. f_chdrive() and f_chdir() are available.
118/ 2: f_getcwd() is available in addition to 1.
119/
120/ Note that output of the f_readdir function is affected by this option. */
121
122
123
124/*---------------------------------------------------------------------------/
125/ Physical Drive Configurations
126/----------------------------------------------------------------------------*/
127
128#define _VOLUMES 1
129/* Number of volumes (logical drives) to be used. */
130
131
132#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */
133/* Maximum sector size to be handled.
134/ Always set 512 for memory card and hard disk but a larger value may be
135/ required for on-board flash memory, floppy disk and optical disk.
136/ When _MAX_SS is larger than 512, it configures FatFs to variable sector size
137/ and GET_SECTOR_SIZE command must be implemented to the disk_ioctl function. */
138
139
140#define _MULTI_PARTITION 0 /* 0:Single partition, 1/2:Enable multiple partition */
141/* When set to 0, each volume is bound to the same physical drive number and
142/ it can mount only first primary partition. When it is set to 1, each volume
143/ is tied to the partitions listed in VolToPart[]. */
144
145
146#define _USE_ERASE 0 /* 0:Disable or 1:Enable */
147/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command
148/ should be added to the disk_ioctl function. */
149
150
151
152/*---------------------------------------------------------------------------/
153/ System Configurations
154/----------------------------------------------------------------------------*/
155
156#define _WORD_ACCESS 1 /* 0 or 1 */
157/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS
158/ option defines which access method is used to the word data on the FAT volume.
159/
160/ 0: Byte-by-byte access.
161/ 1: Word access. Do not choose this unless following condition is met.
162/
163/ When the byte order on the memory is big-endian or address miss-aligned word
164/ access results incorrect behavior, the _WORD_ACCESS must be set to 0.
165/ If it is not the case, the value can also be set to 1 to improve the
166/ performance and code size. */
167
168
169/* A header file that defines sync object types on the O/S, such as
170/ windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */
171
172#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */
173#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */
174#define _SYNC_t HANDLE /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */
175
176/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module.
177/
178/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect.
179/ 1: Enable reentrancy. Also user provided synchronization handlers,
180/ ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj
181/ function must be added to the project. */
182
183
184#define _FS_LOCK 0 /* 0:Disable or >=1:Enable */
185/* To enable file lock control feature, set _FS_LOCK to 1 or greater.
186 The value defines how many files can be opened simultaneously. */
187
188
189#endif /* _FFCONFIG */
190
diff --git a/lib/lufa/Projects/Webserver/Lib/FATFs/integer.h b/lib/lufa/Projects/Webserver/Lib/FATFs/integer.h
deleted file mode 100644
index 5408fe6b3..000000000
--- a/lib/lufa/Projects/Webserver/Lib/FATFs/integer.h
+++ /dev/null
@@ -1,38 +0,0 @@
1/*-------------------------------------------*/
2/* Integer type definitions for FatFs module */
3/*-------------------------------------------*/
4
5#ifndef _INTEGER
6#define _INTEGER
7
8#ifdef _WIN32 /* FatFs development platform */
9
10#include <windows.h>
11#include <tchar.h>
12
13#else /* Embedded platform */
14
15/* These types must be 16-bit, 32-bit or larger integer */
16typedef int INT;
17typedef unsigned int UINT;
18
19/* These types must be 8-bit integer */
20typedef char CHAR;
21typedef unsigned char UCHAR;
22typedef unsigned char BYTE;
23
24/* These types must be 16-bit integer */
25typedef short SHORT;
26typedef unsigned short USHORT;
27typedef unsigned short WORD;
28typedef unsigned short WCHAR;
29
30/* These types must be 32-bit integer */
31typedef long LONG;
32typedef unsigned long ULONG;
33typedef unsigned long DWORD;
34
35#endif
36
37#endif
38
diff --git a/lib/lufa/Projects/Webserver/Lib/HTTPServerApp.c b/lib/lufa/Projects/Webserver/Lib/HTTPServerApp.c
deleted file mode 100644
index ba5ce8b99..000000000
--- a/lib/lufa/Projects/Webserver/Lib/HTTPServerApp.c
+++ /dev/null
@@ -1,284 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * Simple HTTP Webserver Application. When connected to the uIP stack,
34 * this will serve out files to HTTP clients on port 80.
35 */
36
37#define INCLUDE_FROM_HTTPSERVERAPP_C
38#include "HTTPServerApp.h"
39
40/** HTTP server response header, for transmission before the page contents. This indicates to the host that a page exists at the
41 * given location, and gives extra connection information.
42 */
43const char PROGMEM HTTP200Header[] = "HTTP/1.1 200 OK\r\n"
44 "Server: LUFA " LUFA_VERSION_STRING "\r\n"
45 "Connection: close\r\n"
46 "MIME-version: 1.0\r\n"
47 "Content-Type: ";
48
49/** HTTP server response header, for transmission before a resource not found error. This indicates to the host that the given
50 * URL is invalid, and gives extra error information.
51 */
52const char PROGMEM HTTP404Header[] = "HTTP/1.1 404 Not Found\r\n"
53 "Server: LUFA " LUFA_VERSION_STRING "\r\n"
54 "Connection: close\r\n"
55 "MIME-version: 1.0\r\n"
56 "Content-Type: text/plain\r\n\r\n"
57 "Error 404: File Not Found: /";
58
59/** Default filename to fetch when a directory is requested */
60const char PROGMEM DefaultDirFileName[] = "index.htm";
61
62/** Default MIME type sent if no other MIME type can be determined. */
63const char PROGMEM DefaultMIMEType[] = "text/plain";
64
65/** List of MIME types for each supported file extension. */
66const MIME_Type_t MIMETypes[] =
67 {
68 {.Extension = "htm", .MIMEType = "text/html"},
69 {.Extension = "jpg", .MIMEType = "image/jpeg"},
70 {.Extension = "gif", .MIMEType = "image/gif"},
71 {.Extension = "bmp", .MIMEType = "image/bmp"},
72 {.Extension = "png", .MIMEType = "image/png"},
73 {.Extension = "ico", .MIMEType = "image/x-icon"},
74 {.Extension = "exe", .MIMEType = "application/octet-stream"},
75 {.Extension = "gz", .MIMEType = "application/x-gzip"},
76 {.Extension = "zip", .MIMEType = "application/zip"},
77 {.Extension = "pdf", .MIMEType = "application/pdf"},
78 };
79
80/** FATFs structure to hold the internal state of the FAT driver for the Dataflash contents. */
81FATFS DiskFATState;
82
83
84/** Initialization function for the simple HTTP webserver. */
85void HTTPServerApp_Init(void)
86{
87 /* Listen on port 80 for HTTP connections from hosts */
88 uip_listen(HTONS(HTTP_SERVER_PORT));
89
90 /* Mount the Dataflash disk via FatFS */
91 f_mount(0, &DiskFATState);
92}
93
94/** uIP stack application callback for the simple HTTP webserver. This function must be called each time the
95 * TCP/IP stack needs a TCP packet to be processed.
96 */
97void HTTPServerApp_Callback(void)
98{
99 uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
100
101 if (uip_aborted() || uip_timedout() || uip_closed())
102 {
103 /* Lock to the closed state so that no further processing will occur on the connection */
104 AppState->HTTPServer.CurrentState = WEBSERVER_STATE_Closing;
105 AppState->HTTPServer.NextState = WEBSERVER_STATE_Closing;
106 }
107
108 if (uip_connected())
109 {
110 /* New connection - initialize connection state values */
111 AppState->HTTPServer.CurrentState = WEBSERVER_STATE_OpenRequestedFile;
112 AppState->HTTPServer.NextState = WEBSERVER_STATE_OpenRequestedFile;
113 AppState->HTTPServer.FileOpen = false;
114 AppState->HTTPServer.ACKedFilePos = 0;
115 AppState->HTTPServer.SentChunkSize = 0;
116 }
117
118 if (uip_acked())
119 {
120 /* Add the amount of ACKed file data to the total sent file bytes counter */
121 AppState->HTTPServer.ACKedFilePos += AppState->HTTPServer.SentChunkSize;
122
123 /* Progress to the next state once the current state's data has been ACKed */
124 AppState->HTTPServer.CurrentState = AppState->HTTPServer.NextState;
125 }
126
127 if (uip_rexmit())
128 {
129 /* Return file pointer to the last ACKed position */
130 f_lseek(&AppState->HTTPServer.FileHandle, AppState->HTTPServer.ACKedFilePos);
131 }
132
133 if (uip_rexmit() || uip_acked() || uip_newdata() || uip_connected() || uip_poll())
134 {
135 switch (AppState->HTTPServer.CurrentState)
136 {
137 case WEBSERVER_STATE_OpenRequestedFile:
138 HTTPServerApp_OpenRequestedFile();
139 break;
140 case WEBSERVER_STATE_SendResponseHeader:
141 HTTPServerApp_SendResponseHeader();
142 break;
143 case WEBSERVER_STATE_SendData:
144 HTTPServerApp_SendData();
145 break;
146 case WEBSERVER_STATE_Closing:
147 /* Connection is being terminated for some reason - close file handle */
148 f_close(&AppState->HTTPServer.FileHandle);
149 AppState->HTTPServer.FileOpen = false;
150
151 /* If connection is not already closed, close it */
152 uip_close();
153
154 AppState->HTTPServer.CurrentState = WEBSERVER_STATE_Closed;
155 AppState->HTTPServer.NextState = WEBSERVER_STATE_Closed;
156 break;
157 }
158 }
159}
160
161/** HTTP Server State handler for the Request Process state. This state manages the processing of incoming HTTP
162 * GET requests to the server from the receiving HTTP client.
163 */
164static void HTTPServerApp_OpenRequestedFile(void)
165{
166 uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
167 char* const AppData = (char*)uip_appdata;
168
169 /* No HTTP header received from the client, abort processing */
170 if (!(uip_newdata()))
171 return;
172
173 char* RequestToken = strtok(AppData, " ");
174 char* RequestedFileName = strtok(NULL, " ");
175
176 /* Must be a GET request, abort otherwise */
177 if (strcmp_P(RequestToken, PSTR("GET")) != 0)
178 {
179 uip_abort();
180 return;
181 }
182
183 /* Copy over the requested filename */
184 strlcpy(AppState->HTTPServer.FileName, &RequestedFileName[1], sizeof(AppState->HTTPServer.FileName));
185
186 /* Determine the length of the URI so that it can be checked to see if it is a directory */
187 uint8_t FileNameLen = strlen(AppState->HTTPServer.FileName);
188
189 /* If the URI is a directory, append the default filename */
190 if ((AppState->HTTPServer.FileName[FileNameLen - 1] == '/') || !(FileNameLen))
191 {
192 strlcpy_P(&AppState->HTTPServer.FileName[FileNameLen], DefaultDirFileName,
193 (sizeof(AppState->HTTPServer.FileName) - FileNameLen));
194 }
195
196 /* Try to open the file from the Dataflash disk */
197 AppState->HTTPServer.FileOpen = (f_open(&AppState->HTTPServer.FileHandle, AppState->HTTPServer.FileName,
198 (FA_OPEN_EXISTING | FA_READ)) == FR_OK);
199
200 /* Lock to the SendResponseHeader state until connection terminated */
201 AppState->HTTPServer.CurrentState = WEBSERVER_STATE_SendResponseHeader;
202 AppState->HTTPServer.NextState = WEBSERVER_STATE_SendResponseHeader;
203}
204
205/** HTTP Server State handler for the HTTP Response Header Send state. This state manages the transmission of
206 * the HTTP response header to the receiving HTTP client.
207 */
208static void HTTPServerApp_SendResponseHeader(void)
209{
210 uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
211 char* const AppData = (char*)uip_appdata;
212
213 char* Extension = strpbrk(AppState->HTTPServer.FileName, ".");
214 bool FoundMIMEType = false;
215
216 /* If the file isn't already open, it wasn't found - send back a 404 error response and abort */
217 if (!(AppState->HTTPServer.FileOpen))
218 {
219 /* Copy over the HTTP 404 response header and send it to the receiving client */
220 strcpy_P(AppData, HTTP404Header);
221 strcat(AppData, AppState->HTTPServer.FileName);
222 uip_send(AppData, strlen(AppData));
223
224 AppState->HTTPServer.NextState = WEBSERVER_STATE_Closing;
225 return;
226 }
227
228 /* Copy over the HTTP 200 response header and send it to the receiving client */
229 strcpy_P(AppData, HTTP200Header);
230
231 /* Check to see if a MIME type for the requested file's extension was found */
232 if (Extension != NULL)
233 {
234 /* Look through the MIME type list, copy over the required MIME type if found */
235 for (uint8_t i = 0; i < (sizeof(MIMETypes) / sizeof(MIMETypes[0])); i++)
236 {
237 if (strcmp(&Extension[1], MIMETypes[i].Extension) == 0)
238 {
239 strcat(AppData, MIMETypes[i].MIMEType);
240 FoundMIMEType = true;
241 break;
242 }
243 }
244 }
245
246 /* Check if a MIME type was found and copied to the output buffer */
247 if (!(FoundMIMEType))
248 {
249 /* MIME type not found - copy over the default MIME type */
250 strcat_P(AppData, DefaultMIMEType);
251 }
252
253 /* Add the end-of-line terminator and end-of-headers terminator after the MIME type */
254 strcat_P(AppData, PSTR("\r\n\r\n"));
255
256 /* Send the MIME header to the receiving client */
257 uip_send(AppData, strlen(AppData));
258
259 /* When the MIME header is ACKed, progress to the data send stage */
260 AppState->HTTPServer.NextState = WEBSERVER_STATE_SendData;
261}
262
263/** HTTP Server State handler for the Data Send state. This state manages the transmission of file chunks
264 * to the receiving HTTP client.
265 */
266static void HTTPServerApp_SendData(void)
267{
268 uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
269 char* const AppData = (char*)uip_appdata;
270
271 /* Get the maximum segment size for the current packet */
272 uint16_t MaxChunkSize = uip_mss();
273
274 /* Read the next chunk of data from the open file */
275 f_read(&AppState->HTTPServer.FileHandle, AppData, MaxChunkSize, &AppState->HTTPServer.SentChunkSize);
276
277 /* Send the next file chunk to the receiving client */
278 uip_send(AppData, AppState->HTTPServer.SentChunkSize);
279
280 /* Check if we are at the last chunk of the file, if so next ACK should close the connection */
281 if (MaxChunkSize != AppState->HTTPServer.SentChunkSize)
282 AppState->HTTPServer.NextState = WEBSERVER_STATE_Closing;
283}
284
diff --git a/lib/lufa/Projects/Webserver/Lib/HTTPServerApp.h b/lib/lufa/Projects/Webserver/Lib/HTTPServerApp.h
deleted file mode 100644
index 11c39d87e..000000000
--- a/lib/lufa/Projects/Webserver/Lib/HTTPServerApp.h
+++ /dev/null
@@ -1,84 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * Header file for HTTPServerApp.c.
34 */
35
36#ifndef _HTTPSERVER_APP_H_
37#define _HTTPSERVER_APP_H_
38
39 /* Includes: */
40 #include <avr/pgmspace.h>
41 #include <string.h>
42
43 #include <LUFA/Version.h>
44
45 #include "Config/AppConfig.h"
46
47 #include <uip.h>
48 #include <ff.h>
49
50 /* Enums: */
51 /** States for each HTTP connection to the webserver. */
52 enum Webserver_States_t
53 {
54 WEBSERVER_STATE_OpenRequestedFile, /**< Currently opening requested file */
55 WEBSERVER_STATE_SendResponseHeader, /**< Currently sending HTTP response headers to the client */
56 WEBSERVER_STATE_SendData, /**< Currently sending HTTP page data to the client */
57 WEBSERVER_STATE_Closing, /**< Ready to close the connection to the client */
58 WEBSERVER_STATE_Closed, /**< Connection closed after all data sent */
59 };
60
61 /* Type Defines: */
62 /** Type define for a MIME type handler. */
63 typedef struct
64 {
65 char* Extension; /**< File extension (no leading '.' character) */
66 char* MIMEType; /**< Appropriate MIME type to send when the extension is encountered */
67 } MIME_Type_t;
68
69 /* Macros: */
70 /** TCP listen port for incoming HTTP traffic. */
71 #define HTTP_SERVER_PORT 80
72
73 /* Function Prototypes: */
74 void HTTPServerApp_Init(void);
75 void HTTPServerApp_Callback(void);
76
77 #if defined(INCLUDE_FROM_HTTPSERVERAPP_C)
78 static void HTTPServerApp_OpenRequestedFile(void);
79 static void HTTPServerApp_SendResponseHeader(void);
80 static void HTTPServerApp_SendData(void);
81 #endif
82
83#endif
84
diff --git a/lib/lufa/Projects/Webserver/Lib/SCSI.c b/lib/lufa/Projects/Webserver/Lib/SCSI.c
deleted file mode 100644
index 4fbbfd60e..000000000
--- a/lib/lufa/Projects/Webserver/Lib/SCSI.c
+++ /dev/null
@@ -1,344 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * SCSI command processing routines, for SCSI commands issued by the host. Mass Storage
34 * devices use a thin "Bulk-Only Transport" protocol for issuing commands and status information,
35 * which wrap around standard SCSI device commands for controlling the actual storage medium.
36 */
37
38#define INCLUDE_FROM_SCSI_C
39#include "SCSI.h"
40
41/** Structure to hold the SCSI response data to a SCSI INQUIRY command. This gives information about the device's
42 * features and capabilities.
43 */
44static const SCSI_Inquiry_Response_t InquiryData =
45 {
46 .DeviceType = DEVICE_TYPE_BLOCK,
47 .PeripheralQualifier = 0,
48
49 .Removable = true,
50
51 .Version = 0,
52
53 .ResponseDataFormat = 2,
54 .NormACA = false,
55 .TrmTsk = false,
56 .AERC = false,
57
58 .AdditionalLength = 0x1F,
59
60 .SoftReset = false,
61 .CmdQue = false,
62 .Linked = false,
63 .Sync = false,
64 .WideBus16Bit = false,
65 .WideBus32Bit = false,
66 .RelAddr = false,
67
68 .VendorID = "LUFA",
69 .ProductID = "Dataflash Disk",
70 .RevisionID = {'0','.','0','0'},
71 };
72
73/** Structure to hold the sense data for the last issued SCSI command, which is returned to the host after a SCSI REQUEST SENSE
74 * command is issued. This gives information on exactly why the last command failed to complete.
75 */
76static SCSI_Request_Sense_Response_t SenseData =
77 {
78 .ResponseCode = 0x70,
79 .AdditionalLength = 0x0A,
80 };
81
82
83/** Main routine to process the SCSI command located in the Command Block Wrapper read from the host. This dispatches
84 * to the appropriate SCSI command handling routine if the issued command is supported by the device, else it returns
85 * a command failure due to a ILLEGAL REQUEST.
86 *
87 * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
88 *
89 * \return Boolean \c true if the command completed successfully, \c false otherwise
90 */
91bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
92{
93 bool CommandSuccess = false;
94
95 /* Run the appropriate SCSI command hander function based on the passed command */
96 switch (MSInterfaceInfo->State.CommandBlock.SCSICommandData[0])
97 {
98 case SCSI_CMD_INQUIRY:
99 CommandSuccess = SCSI_Command_Inquiry(MSInterfaceInfo);
100 break;
101 case SCSI_CMD_REQUEST_SENSE:
102 CommandSuccess = SCSI_Command_Request_Sense(MSInterfaceInfo);
103 break;
104 case SCSI_CMD_READ_CAPACITY_10:
105 CommandSuccess = SCSI_Command_Read_Capacity_10(MSInterfaceInfo);
106 break;
107 case SCSI_CMD_SEND_DIAGNOSTIC:
108 CommandSuccess = SCSI_Command_Send_Diagnostic(MSInterfaceInfo);
109 break;
110 case SCSI_CMD_WRITE_10:
111 CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_WRITE);
112 break;
113 case SCSI_CMD_READ_10:
114 CommandSuccess = SCSI_Command_ReadWrite_10(MSInterfaceInfo, DATA_READ);
115 break;
116 case SCSI_CMD_MODE_SENSE_6:
117 CommandSuccess = SCSI_Command_ModeSense_6(MSInterfaceInfo);
118 break;
119 case SCSI_CMD_START_STOP_UNIT:
120 case SCSI_CMD_TEST_UNIT_READY:
121 case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
122 case SCSI_CMD_VERIFY_10:
123 /* These commands should just succeed, no handling required */
124 CommandSuccess = true;
125 MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0;
126 break;
127 default:
128 /* Update the SENSE key to reflect the invalid command */
129 SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
130 SCSI_ASENSE_INVALID_COMMAND,
131 SCSI_ASENSEQ_NO_QUALIFIER);
132 break;
133 }
134
135 /* Check if command was successfully processed */
136 if (CommandSuccess)
137 {
138 SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD,
139 SCSI_ASENSE_NO_ADDITIONAL_INFORMATION,
140 SCSI_ASENSEQ_NO_QUALIFIER);
141
142 return true;
143 }
144
145 return false;
146}
147
148/** Command processing for an issued SCSI INQUIRY command. This command returns information about the device's features
149 * and capabilities to the host.
150 *
151 * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
152 *
153 * \return Boolean \c true if the command completed successfully, \c false otherwise.
154 */
155static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
156{
157 uint16_t AllocationLength = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[3]);
158 uint16_t BytesTransferred = MIN(AllocationLength, sizeof(InquiryData));
159
160 /* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */
161 if ((MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) ||
162 MSInterfaceInfo->State.CommandBlock.SCSICommandData[2])
163 {
164 /* Optional but unsupported bits set - update the SENSE key and fail the request */
165 SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
166 SCSI_ASENSE_INVALID_FIELD_IN_CDB,
167 SCSI_ASENSEQ_NO_QUALIFIER);
168
169 return false;
170 }
171
172 Endpoint_Write_Stream_LE(&InquiryData, BytesTransferred, NULL);
173
174 /* Pad out remaining bytes with 0x00 */
175 Endpoint_Null_Stream((AllocationLength - BytesTransferred), NULL);
176
177 /* Finalize the stream transfer to send the last packet */
178 Endpoint_ClearIN();
179
180 /* Succeed the command and update the bytes transferred counter */
181 MSInterfaceInfo->State.CommandBlock.DataTransferLength -= BytesTransferred;
182
183 return true;
184}
185
186/** Command processing for an issued SCSI REQUEST SENSE command. This command returns information about the last issued command,
187 * including the error code and additional error information so that the host can determine why a command failed to complete.
188 *
189 * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
190 *
191 * \return Boolean \c true if the command completed successfully, \c false otherwise.
192 */
193static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
194{
195 uint8_t AllocationLength = MSInterfaceInfo->State.CommandBlock.SCSICommandData[4];
196 uint8_t BytesTransferred = MIN(AllocationLength, sizeof(SenseData));
197
198 Endpoint_Write_Stream_LE(&SenseData, BytesTransferred, NULL);
199 Endpoint_Null_Stream((AllocationLength - BytesTransferred), NULL);
200 Endpoint_ClearIN();
201
202 /* Succeed the command and update the bytes transferred counter */
203 MSInterfaceInfo->State.CommandBlock.DataTransferLength -= BytesTransferred;
204
205 return true;
206}
207
208/** Command processing for an issued SCSI READ CAPACITY (10) command. This command returns information about the device's capacity
209 * on the selected Logical Unit (drive), as a number of OS-sized blocks.
210 *
211 * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
212 *
213 * \return Boolean \c true if the command completed successfully, \c false otherwise.
214 */
215static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
216{
217 uint32_t LastBlockAddressInLUN = (VIRTUAL_MEMORY_BLOCKS - 1);
218 uint32_t MediaBlockSize = VIRTUAL_MEMORY_BLOCK_SIZE;
219
220 Endpoint_Write_Stream_BE(&LastBlockAddressInLUN, sizeof(LastBlockAddressInLUN), NULL);
221 Endpoint_Write_Stream_BE(&MediaBlockSize, sizeof(MediaBlockSize), NULL);
222 Endpoint_ClearIN();
223
224 /* Succeed the command and update the bytes transferred counter */
225 MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 8;
226
227 return true;
228}
229
230/** Command processing for an issued SCSI SEND DIAGNOSTIC command. This command performs a quick check of the Dataflash ICs on the
231 * board, and indicates if they are present and functioning correctly. Only the Self-Test portion of the diagnostic command is
232 * supported.
233 *
234 * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
235 *
236 * \return Boolean \c true if the command completed successfully, \c false otherwise.
237 */
238static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
239{
240 /* Check to see if the SELF TEST bit is not set */
241 if (!(MSInterfaceInfo->State.CommandBlock.SCSICommandData[1] & (1 << 2)))
242 {
243 /* Only self-test supported - update SENSE key and fail the command */
244 SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
245 SCSI_ASENSE_INVALID_FIELD_IN_CDB,
246 SCSI_ASENSEQ_NO_QUALIFIER);
247
248 return false;
249 }
250
251 /* Check to see if all attached Dataflash ICs are functional */
252 if (!(DataflashManager_CheckDataflashOperation()))
253 {
254 /* Update SENSE key with a hardware error condition and return command fail */
255 SCSI_SET_SENSE(SCSI_SENSE_KEY_HARDWARE_ERROR,
256 SCSI_ASENSE_NO_ADDITIONAL_INFORMATION,
257 SCSI_ASENSEQ_NO_QUALIFIER);
258
259 return false;
260 }
261
262 /* Succeed the command and update the bytes transferred counter */
263 MSInterfaceInfo->State.CommandBlock.DataTransferLength = 0;
264
265 return true;
266}
267
268/** Command processing for an issued SCSI READ (10) or WRITE (10) command. This command reads in the block start address
269 * and total number of blocks to process, then calls the appropriate low-level Dataflash routine to handle the actual
270 * reading and writing of the data.
271 *
272 * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
273 * \param[in] IsDataRead Indicates if the command is a READ (10) command or WRITE (10) command (DATA_READ or DATA_WRITE)
274 *
275 * \return Boolean \c true if the command completed successfully, \c false otherwise.
276 */
277static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
278 const bool IsDataRead)
279{
280 uint32_t BlockAddress;
281 uint16_t TotalBlocks;
282
283 /* Check if the disk is write protected or not */
284 if ((IsDataRead == DATA_WRITE) && DISK_READ_ONLY)
285 {
286 /* Block address is invalid, update SENSE key and return command fail */
287 SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT,
288 SCSI_ASENSE_WRITE_PROTECTED,
289 SCSI_ASENSEQ_NO_QUALIFIER);
290
291 return false;
292 }
293
294 /* Load in the 32-bit block address (SCSI uses big-endian, so have to reverse the byte order) */
295 BlockAddress = SwapEndian_32(*(uint32_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[2]);
296
297 /* Load in the 16-bit total blocks (SCSI uses big-endian, so have to reverse the byte order) */
298 TotalBlocks = SwapEndian_16(*(uint16_t*)&MSInterfaceInfo->State.CommandBlock.SCSICommandData[7]);
299
300 /* Check if the block address is outside the maximum allowable value for the LUN */
301 if (BlockAddress >= VIRTUAL_MEMORY_BLOCKS)
302 {
303 /* Block address is invalid, update SENSE key and return command fail */
304 SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST,
305 SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE,
306 SCSI_ASENSEQ_NO_QUALIFIER);
307
308 return false;
309 }
310
311 /* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
312 if (IsDataRead == DATA_READ)
313 DataflashManager_ReadBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
314 else
315 DataflashManager_WriteBlocks(MSInterfaceInfo, BlockAddress, TotalBlocks);
316
317 /* Update the bytes transferred counter and succeed the command */
318 MSInterfaceInfo->State.CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * VIRTUAL_MEMORY_BLOCK_SIZE);
319
320 return true;
321}
322
323/** Command processing for an issued SCSI MODE SENSE (6) command. This command returns various informational pages about
324 * the SCSI device, as well as the device's Write Protect status.
325 *
326 * \param[in] MSInterfaceInfo Pointer to the Mass Storage class interface structure that the command is associated with
327 *
328 * \return Boolean \c true if the command completed successfully, \c false otherwise.
329 */
330static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo)
331{
332 /* Send an empty header response with the Write Protect flag status */
333 Endpoint_Write_8(0x00);
334 Endpoint_Write_8(0x00);
335 Endpoint_Write_8(DISK_READ_ONLY ? 0x80 : 0x00);
336 Endpoint_Write_8(0x00);
337 Endpoint_ClearIN();
338
339 /* Update the bytes transferred counter and succeed the command */
340 MSInterfaceInfo->State.CommandBlock.DataTransferLength -= 4;
341
342 return true;
343}
344
diff --git a/lib/lufa/Projects/Webserver/Lib/SCSI.h b/lib/lufa/Projects/Webserver/Lib/SCSI.h
deleted file mode 100644
index 8f41f63b4..000000000
--- a/lib/lufa/Projects/Webserver/Lib/SCSI.h
+++ /dev/null
@@ -1,87 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * Header file for SCSI.c.
34 */
35
36#ifndef _SCSI_H_
37#define _SCSI_H_
38
39 /* Includes: */
40 #include <avr/io.h>
41 #include <avr/pgmspace.h>
42
43 #include <LUFA/Drivers/USB/USB.h>
44
45 #include "../Descriptors.h"
46 #include "DataflashManager.h"
47
48 /* Macros: */
49 /** Macro to set the current SCSI sense data to the given key, additional sense code and additional sense qualifier. This
50 * is for convenience, as it allows for all three sense values (returned upon request to the host to give information about
51 * the last command failure) in a quick and easy manner.
52 *
53 * \param[in] Key New SCSI sense key to set the sense code to
54 * \param[in] Acode New SCSI additional sense key to set the additional sense code to
55 * \param[in] Aqual New SCSI additional sense key qualifier to set the additional sense qualifier code to
56 */
57 #define SCSI_SET_SENSE(Key, Acode, Aqual) do { SenseData.SenseKey = (Key); \
58 SenseData.AdditionalSenseCode = (Acode); \
59 SenseData.AdditionalSenseQualifier = (Aqual); } while (0)
60
61 /** Macro for the \ref SCSI_Command_ReadWrite_10() function, to indicate that data is to be read from the storage medium. */
62 #define DATA_READ true
63
64 /** Macro for the \ref SCSI_Command_ReadWrite_10() function, to indicate that data is to be written to the storage medium. */
65 #define DATA_WRITE false
66
67 /** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a Block Media device. */
68 #define DEVICE_TYPE_BLOCK 0x00
69
70 /** Value for the DeviceType entry in the SCSI_Inquiry_Response_t enum, indicating a CD-ROM device. */
71 #define DEVICE_TYPE_CDROM 0x05
72
73 /* Function Prototypes: */
74 bool SCSI_DecodeSCSICommand(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
75
76 #if defined(INCLUDE_FROM_SCSI_C)
77 static bool SCSI_Command_Inquiry(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
78 static bool SCSI_Command_Request_Sense(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
79 static bool SCSI_Command_Read_Capacity_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
80 static bool SCSI_Command_Send_Diagnostic(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
81 static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
82 const bool IsDataRead);
83 static bool SCSI_Command_ModeSense_6(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo);
84 #endif
85
86#endif
87
diff --git a/lib/lufa/Projects/Webserver/Lib/TELNETServerApp.c b/lib/lufa/Projects/Webserver/Lib/TELNETServerApp.c
deleted file mode 100644
index 4500a4b78..000000000
--- a/lib/lufa/Projects/Webserver/Lib/TELNETServerApp.c
+++ /dev/null
@@ -1,163 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * TELNET Webserver Application. When connected to the uIP stack,
34 * this will serve out raw TELNET to the client on port 23.
35 */
36
37#define INCLUDE_FROM_TELNETSERVERAPP_C
38#include "TELNETServerApp.h"
39
40#if defined(ENABLE_TELNET_SERVER) || defined(__DOXYGEN__)
41
42/** Welcome message to send to a TELNET client when a connection is first made. */
43const char PROGMEM WelcomeHeader[] = "********************************************\r\n"
44 "* LUFA uIP Webserver (TELNET) *\r\n"
45 "********************************************\r\n";
46
47/** Main TELNET menu, giving the user the list of available commands they may issue */
48const char PROGMEM TELNETMenu[] = "\r\n"
49 " == Available Commands: ==\r\n"
50 " c) List Active TCP Connections\r\n"
51 " =========================\r\n"
52 "\r\n>";
53
54/** Header to print before the current connections are printed to the client */
55const char PROGMEM CurrentConnectionsHeader[] = "\r\n* Current TCP Connections: *\r\n";
56
57/** Initialization function for the simple TELNET webserver. */
58void TELNETServerApp_Init(void)
59{
60 /* Listen on port 23 for TELNET connections from hosts */
61 uip_listen(HTONS(TELNET_SERVER_PORT));
62}
63
64/** uIP stack application callback for the TELNET server. This function must be called each time the
65 * TCP/IP stack needs a TCP packet to be processed.
66 */
67void TELNETServerApp_Callback(void)
68{
69 uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
70 char* const AppData = (char*)uip_appdata;
71
72 if (uip_connected())
73 {
74 /* New connection - initialize connection state values */
75 AppState->TELNETServer.CurrentState = TELNET_STATE_SendHeader;
76 }
77
78 if (uip_acked())
79 {
80 /* Progress to the next state once the current state's data has been ACKed */
81 AppState->TELNETServer.CurrentState = AppState->TELNETServer.NextState;
82 }
83
84 if (uip_rexmit() || uip_acked() || uip_newdata() || uip_connected() || uip_poll())
85 {
86 switch (AppState->TELNETServer.CurrentState)
87 {
88 case TELNET_STATE_SendHeader:
89 /* Copy over and send the TELNET welcome message upon first connection */
90 strcpy_P(AppData, WelcomeHeader);
91 uip_send(AppData, strlen(AppData));
92
93 AppState->TELNETServer.NextState = TELNET_STATE_SendMenu;
94 break;
95 case TELNET_STATE_SendMenu:
96 /* Copy over and send the TELNET menu to the client */
97 strcpy_P(AppData, TELNETMenu);
98 uip_send(AppData, strlen(AppData));
99
100 AppState->TELNETServer.NextState = TELNET_STATE_GetCommand;
101 break;
102 case TELNET_STATE_GetCommand:
103 if (!(uip_datalen()))
104 break;
105
106 /* Save the issued command for later processing */
107 AppState->TELNETServer.IssuedCommand = AppData[0];
108
109 AppState->TELNETServer.CurrentState = TELNET_STATE_SendResponse;
110 break;
111 case TELNET_STATE_SendResponse:
112 /* Determine which command was issued, perform command processing */
113 switch (AppState->TELNETServer.IssuedCommand)
114 {
115 case 'c':
116 TELNETServerApp_DisplayTCPConnections();
117 break;
118 default:
119 strcpy_P(AppData, PSTR("Invalid Command.\r\n"));
120 uip_send(AppData, strlen(AppData));
121 break;
122 }
123
124 AppState->TELNETServer.NextState = TELNET_STATE_SendMenu;
125 break;
126 }
127 }
128}
129
130/** Sends a list of active TCP connections to the TELNET client. */
131static void TELNETServerApp_DisplayTCPConnections(void)
132{
133 char* const AppData = (char*)uip_appdata;
134
135 strcpy_P(AppData, CurrentConnectionsHeader);
136
137 uint16_t ResponseLen = strlen(AppData);
138 uint8_t ActiveConnCount = 0;
139
140 /* Loop through the complete uIP TCP connections list, looking for active connections */
141 for (uint8_t i = 0; i < UIP_CONNS; i++)
142 {
143 struct uip_conn* CurrConnection = &uip_conns[i];
144
145 /* If the connection is not closed, it is active and must be added to the out buffer */
146 if (CurrConnection->tcpstateflags != UIP_CLOSED)
147 {
148 /* Add the current connection's details to the out buffer */
149 ResponseLen += sprintf_P(&AppData[ResponseLen], PSTR("%u) %d.%d.%d.%d (Local Port %u <=> Remote Port %u)\r\n"),
150 ++ActiveConnCount,
151 CurrConnection->ripaddr.u8[0],
152 CurrConnection->ripaddr.u8[1],
153 CurrConnection->ripaddr.u8[2],
154 CurrConnection->ripaddr.u8[3],
155 HTONS(CurrConnection->lport), HTONS(CurrConnection->rport));
156 }
157 }
158
159 uip_send(AppData, ResponseLen);
160}
161
162#endif
163
diff --git a/lib/lufa/Projects/Webserver/Lib/TELNETServerApp.h b/lib/lufa/Projects/Webserver/Lib/TELNETServerApp.h
deleted file mode 100644
index 67301ba09..000000000
--- a/lib/lufa/Projects/Webserver/Lib/TELNETServerApp.h
+++ /dev/null
@@ -1,71 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * Header file for TELNETServerApp.c.
34 */
35
36#ifndef _TELNETSERVER_APP_H_
37#define _TELNETSERVER_APP_H_
38
39 /* Includes: */
40 #include <avr/pgmspace.h>
41 #include <string.h>
42 #include <stdio.h>
43
44 #include <uip.h>
45
46 #include "Config/AppConfig.h"
47
48 /* Macros: */
49 /** TCP listen port for incoming TELNET traffic. */
50 #define TELNET_SERVER_PORT 23
51
52 /* Enums: */
53 /** States for each TELNET connection to the server. */
54 enum TELNET_States_t
55 {
56 TELNET_STATE_SendHeader, /**< Currently sending welcome header to the client */
57 TELNET_STATE_SendMenu, /**< Currently sending the command list menu to the client */
58 TELNET_STATE_GetCommand, /**< Currently waiting for a command from the client */
59 TELNET_STATE_SendResponse, /**< Processing the issued command and sending a response */
60 };
61
62 /* Function Prototypes: */
63 void TELNETServerApp_Init(void);
64 void TELNETServerApp_Callback(void);
65
66 #if defined(INCLUDE_FROM_TELNETSERVERAPP_C)
67 static void TELNETServerApp_DisplayTCPConnections(void);
68 #endif
69
70#endif
71
diff --git a/lib/lufa/Projects/Webserver/Lib/uIPManagement.c b/lib/lufa/Projects/Webserver/Lib/uIPManagement.c
deleted file mode 100644
index 12f6c8f9e..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uIPManagement.c
+++ /dev/null
@@ -1,298 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * uIP Management functions. This file contains the functions and globals needed to maintain the uIP
34 * stack once an RNDIS device has been attached to the system.
35 */
36
37#define INCLUDE_FROM_UIPMANAGEMENT_C
38#include "uIPManagement.h"
39
40/** Connection timer, to retain the time elapsed since the last time the uIP connections were managed. */
41static struct timer ConnectionTimer;
42
43/** ARP timer, to retain the time elapsed since the ARP cache was last updated. */
44static struct timer ARPTimer;
45
46/** MAC address of the RNDIS device, when enumerated. */
47struct uip_eth_addr MACAddress;
48
49
50/** Configures the uIP stack ready for network traffic processing. */
51void uIPManagement_Init(void)
52{
53 /* uIP Timing Initialization */
54 clock_init();
55 timer_set(&ConnectionTimer, CLOCK_SECOND / 2);
56 timer_set(&ARPTimer, CLOCK_SECOND * 10);
57
58 /* uIP Stack Initialization */
59 uip_init();
60 uip_arp_init();
61
62 /* DHCP/Server IP Settings Initialization */
63 if (USB_CurrentMode == USB_MODE_Device)
64 {
65 MACAddress.addr[0] = SERVER_MAC_ADDRESS[0];
66 MACAddress.addr[1] = SERVER_MAC_ADDRESS[1];
67 MACAddress.addr[2] = SERVER_MAC_ADDRESS[2];
68 MACAddress.addr[3] = SERVER_MAC_ADDRESS[3];
69 MACAddress.addr[4] = SERVER_MAC_ADDRESS[4];
70 MACAddress.addr[5] = SERVER_MAC_ADDRESS[5];
71
72 #if defined(ENABLE_DHCP_SERVER)
73 DHCPServerApp_Init();
74 #endif
75
76 uip_ipaddr_t IPAddress, Netmask, GatewayIPAddress;
77 uip_ipaddr(&IPAddress, DEVICE_IP_ADDRESS[0], DEVICE_IP_ADDRESS[1], DEVICE_IP_ADDRESS[2], DEVICE_IP_ADDRESS[3]);
78 uip_ipaddr(&Netmask, DEVICE_NETMASK[0], DEVICE_NETMASK[1], DEVICE_NETMASK[2], DEVICE_NETMASK[3]);
79 uip_ipaddr(&GatewayIPAddress, DEVICE_GATEWAY[0], DEVICE_GATEWAY[1], DEVICE_GATEWAY[2], DEVICE_GATEWAY[3]);
80 uip_sethostaddr(&IPAddress);
81 uip_setnetmask(&Netmask);
82 uip_setdraddr(&GatewayIPAddress);
83 }
84 else
85 {
86 #if defined(ENABLE_DHCP_CLIENT)
87 DHCPClientApp_Init();
88 #else
89 uip_ipaddr_t IPAddress, Netmask, GatewayIPAddress;
90 uip_ipaddr(&IPAddress, DEVICE_IP_ADDRESS[0], DEVICE_IP_ADDRESS[1], DEVICE_IP_ADDRESS[2], DEVICE_IP_ADDRESS[3]);
91 uip_ipaddr(&Netmask, DEVICE_NETMASK[0], DEVICE_NETMASK[1], DEVICE_NETMASK[2], DEVICE_NETMASK[3]);
92 uip_ipaddr(&GatewayIPAddress, DEVICE_GATEWAY[0], DEVICE_GATEWAY[1], DEVICE_GATEWAY[2], DEVICE_GATEWAY[3]);
93 uip_sethostaddr(&IPAddress);
94 uip_setnetmask(&Netmask);
95 uip_setdraddr(&GatewayIPAddress);
96 #endif
97 }
98
99 /* Virtual Webserver Ethernet Address Configuration */
100 uip_setethaddr(MACAddress);
101
102 /* HTTP Webserver Initialization */
103 HTTPServerApp_Init();
104
105 /* TELNET Server Initialization */
106 #if defined(ENABLE_TELNET_SERVER)
107 TELNETServerApp_Init();
108 #endif
109}
110
111/** uIP Management function. This function manages the uIP stack when called while an RNDIS device has been
112 * attached to the system.
113 */
114void uIPManagement_ManageNetwork(void)
115{
116 if (((USB_CurrentMode == USB_MODE_Host) && (USB_HostState == HOST_STATE_Configured)) ||
117 ((USB_CurrentMode == USB_MODE_Device) && (USB_DeviceState == DEVICE_STATE_Configured)))
118 {
119 uIPManagement_ProcessIncomingPacket();
120 uIPManagement_ManageConnections();
121 }
122}
123
124/** uIP TCP/IP network stack callback function for the processing of a given TCP connection. This routine dispatches
125 * to the appropriate TCP protocol application based on the connection's listen port number.
126 */
127void uIPManagement_TCPCallback(void)
128{
129 /* Call the correct TCP application based on the port number the connection is listening on */
130 switch (uip_conn->lport)
131 {
132 case HTONS(HTTP_SERVER_PORT):
133 HTTPServerApp_Callback();
134 break;
135 #if defined(ENABLE_TELNET_SERVER)
136 case HTONS(TELNET_SERVER_PORT):
137 TELNETServerApp_Callback();
138 break;
139 #endif
140 }
141}
142
143/** uIP TCP/IP network stack callback function for the processing of a given UDP connection. This routine dispatches
144 * to the appropriate UDP protocol application based on the connection's listen port number.
145 */
146void uIPManagement_UDPCallback(void)
147{
148 /* Call the correct UDP application based on the port number the connection is listening on */
149 switch (uip_udp_conn->lport)
150 {
151 #if defined(ENABLE_DHCP_CLIENT)
152 case HTONS(DHCP_CLIENT_PORT):
153 DHCPClientApp_Callback();
154 break;
155 #endif
156 #if defined(ENABLE_DHCP_SERVER)
157 case HTONS(DHCP_SERVER_PORT):
158 DHCPServerApp_Callback();
159 break;
160 #endif
161 }
162}
163
164/** Processes Incoming packets to the server from the connected RNDIS device, creating responses as needed. */
165static void uIPManagement_ProcessIncomingPacket(void)
166{
167 /* Determine which USB mode the system is currently initialized in */
168 if (USB_CurrentMode == USB_MODE_Device)
169 {
170 /* If no packet received, exit processing routine */
171 if (!(RNDIS_Device_IsPacketReceived(&Ethernet_RNDIS_Interface_Device)))
172 return;
173
174 LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
175
176 /* Read the Incoming packet straight into the UIP packet buffer */
177 RNDIS_Device_ReadPacket(&Ethernet_RNDIS_Interface_Device, uip_buf, &uip_len);
178 }
179 else
180 {
181 /* If no packet received, exit processing routine */
182 if (!(RNDIS_Host_IsPacketReceived(&Ethernet_RNDIS_Interface_Host)))
183 return;
184
185 LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
186
187 /* Read the Incoming packet straight into the UIP packet buffer */
188 RNDIS_Host_ReadPacket(&Ethernet_RNDIS_Interface_Host, uip_buf, &uip_len);
189 }
190
191 /* If the packet contains an Ethernet frame, process it */
192 if (uip_len > 0)
193 {
194 switch (((struct uip_eth_hdr*)uip_buf)->type)
195 {
196 case HTONS(UIP_ETHTYPE_IP):
197 /* Filter packet by MAC destination */
198 uip_arp_ipin();
199
200 /* Process Incoming packet */
201 uip_input();
202
203 /* If a response was generated, send it */
204 if (uip_len > 0)
205 {
206 /* Add destination MAC to outgoing packet */
207 uip_arp_out();
208
209 uip_split_output();
210 }
211
212 break;
213 case HTONS(UIP_ETHTYPE_ARP):
214 /* Process ARP packet */
215 uip_arp_arpin();
216
217 /* If a response was generated, send it */
218 if (uip_len > 0)
219 uip_split_output();
220
221 break;
222 }
223 }
224
225 LEDs_SetAllLEDs(LEDMASK_USB_READY);
226}
227
228/** Manages the currently open network connections, including TCP and (if enabled) UDP. */
229static void uIPManagement_ManageConnections(void)
230{
231 /* Poll TCP connections for more data to send back to the host */
232 for (uint8_t i = 0; i < UIP_CONNS; i++)
233 {
234 uip_poll_conn(&uip_conns[i]);
235
236 /* If a response was generated, send it */
237 if (uip_len > 0)
238 {
239 /* Add destination MAC to outgoing packet */
240 uip_arp_out();
241
242 /* Split and send the outgoing packet */
243 uip_split_output();
244 }
245 }
246
247 /* Manage open connections for timeouts */
248 if (timer_expired(&ConnectionTimer))
249 {
250 timer_reset(&ConnectionTimer);
251
252 LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
253
254 for (uint8_t i = 0; i < UIP_CONNS; i++)
255 {
256 /* Run periodic connection management for each TCP connection */
257 uip_periodic(i);
258
259 /* If a response was generated, send it */
260 if (uip_len > 0)
261 {
262 /* Add destination MAC to outgoing packet */
263 uip_arp_out();
264
265 /* Split and send the outgoing packet */
266 uip_split_output();
267 }
268 }
269
270 #if defined(ENABLE_DHCP_CLIENT)
271 for (uint8_t i = 0; i < UIP_UDP_CONNS; i++)
272 {
273 /* Run periodic connection management for each UDP connection */
274 uip_udp_periodic(i);
275
276 /* If a response was generated, send it */
277 if (uip_len > 0)
278 {
279 /* Add destination MAC to outgoing packet */
280 uip_arp_out();
281
282 /* Split and send the outgoing packet */
283 uip_split_output();
284 }
285 }
286 #endif
287
288 LEDs_SetAllLEDs(LEDMASK_USB_READY);
289 }
290
291 /* Manage ARP cache refreshing */
292 if (timer_expired(&ARPTimer))
293 {
294 timer_reset(&ARPTimer);
295 uip_arp_timer();
296 }
297}
298
diff --git a/lib/lufa/Projects/Webserver/Lib/uIPManagement.h b/lib/lufa/Projects/Webserver/Lib/uIPManagement.h
deleted file mode 100644
index 3bdc5c96b..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uIPManagement.h
+++ /dev/null
@@ -1,69 +0,0 @@
1/*
2 LUFA Library
3 Copyright (C) Dean Camera, 2017.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7*/
8
9/*
10 Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29*/
30
31/** \file
32 *
33 * Header file for uIPManagement.c.
34 */
35
36#ifndef _UIP_MANAGEMENT_H_
37#define _UIP_MANAGEMENT_H_
38
39 /* Includes: */
40 #include <LUFA/Drivers/USB/USB.h>
41
42 #include <uip.h>
43 #include <uip_arp.h>
44 #include <uip-split.h>
45 #include <timer.h>
46
47 #include "Config/AppConfig.h"
48
49 #include "DHCPClientApp.h"
50 #include "DHCPServerApp.h"
51 #include "HTTPServerApp.h"
52 #include "TELNETServerApp.h"
53
54 /* External Variables: */
55 extern struct uip_eth_addr MACAddress;
56
57 /* Function Prototypes: */
58 void uIPManagement_Init(void);
59 void uIPManagement_ManageNetwork(void);
60 void uIPManagement_TCPCallback(void);
61 void uIPManagement_UDPCallback(void);
62
63 #if defined(INCLUDE_FROM_UIPMANAGEMENT_C)
64 static void uIPManagement_ProcessIncomingPacket(void);
65 static void uIPManagement_ManageConnections(void);
66 #endif
67
68#endif
69
diff --git a/lib/lufa/Projects/Webserver/Lib/uip/clock.c b/lib/lufa/Projects/Webserver/Lib/uip/clock.c
deleted file mode 100644
index e71f7209d..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uip/clock.c
+++ /dev/null
@@ -1,37 +0,0 @@
1#include <stdint.h>
2#include <stdlib.h>
3#include <stdio.h>
4
5#include <LUFA/Common/Common.h>
6
7#include "clock.h"
8
9//Counted time
10volatile clock_time_t clock_datetime = 0;
11
12//Overflow interrupt
13ISR(TIMER1_COMPA_vect, ISR_BLOCK)
14{
15 clock_datetime += 1;
16}
17
18//Initialise the clock
19void clock_init()
20{
21 OCR1A = (((F_CPU / 1024) / 100) - 1);
22 TCCR1B = ((1 << WGM12) | (1 << CS12) | (1 << CS10));
23 TIMSK1 = (1 << OCIE1A);
24}
25
26//Return time
27clock_time_t clock_time()
28{
29 clock_time_t time;
30
31 GlobalInterruptDisable();
32 time = clock_datetime;
33 GlobalInterruptEnable();
34
35 return time;
36}
37
diff --git a/lib/lufa/Projects/Webserver/Lib/uip/clock.h b/lib/lufa/Projects/Webserver/Lib/uip/clock.h
deleted file mode 100644
index bbfa4ac0e..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uip/clock.h
+++ /dev/null
@@ -1,13 +0,0 @@
1#ifndef __CLOCK_ARCH_H__
2#define __CLOCK_ARCH_H__
3
4#include <stdint.h>
5#include <util/atomic.h>
6
7typedef uint16_t clock_time_t;
8#define CLOCK_SECOND 100
9void clock_init(void);
10clock_time_t clock_time(void);
11
12#endif /* __CLOCK_ARCH_H__ */
13
diff --git a/lib/lufa/Projects/Webserver/Lib/uip/timer.c b/lib/lufa/Projects/Webserver/Lib/uip/timer.c
deleted file mode 100644
index eae06f43b..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uip/timer.c
+++ /dev/null
@@ -1,128 +0,0 @@
1/**
2 * \addtogroup timer
3 * @{
4 */
5
6/**
7 * \file
8 * Timer library implementation.
9 * \author
10 * Adam Dunkels <adam@sics.se>
11 */
12
13/*
14 * Copyright (c) 2004, Swedish Institute of Computer Science.
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. Neither the name of the Institute nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 *
41 * This file is part of the uIP TCP/IP stack
42 *
43 * Author: Adam Dunkels <adam@sics.se>
44 *
45 * $Id: timer.c,v 1.2 2006/06/12 08:00:30 adam Exp $
46 */
47
48#include "clock.h"
49#include "timer.h"
50
51/*---------------------------------------------------------------------------*/
52/**
53 * Set a timer.
54 *
55 * This function is used to set a timer for a time sometime in the
56 * future. The function timer_expired() will evaluate to true after
57 * the timer has expired.
58 *
59 * \param t A pointer to the timer
60 * \param interval The interval before the timer expires.
61 *
62 */
63void
64timer_set(struct timer *t, clock_time_t interval)
65{
66 t->interval = interval;
67 t->start = clock_time();
68}
69/*---------------------------------------------------------------------------*/
70/**
71 * Reset the timer with the same interval.
72 *
73 * This function resets the timer with the same interval that was
74 * given to the timer_set() function. The start point of the interval
75 * is the exact time that the timer last expired. Therefore, this
76 * function will cause the timer to be stable over time, unlike the
77 * timer_restart() function.
78 *
79 * \param t A pointer to the timer.
80 *
81 * \sa timer_restart()
82 */
83void
84timer_reset(struct timer *t)
85{
86 t->start += t->interval;
87}
88/*---------------------------------------------------------------------------*/
89/**
90 * Restart the timer from the current point in time
91 *
92 * This function restarts a timer with the same interval that was
93 * given to the timer_set() function. The timer will start at the
94 * current time.
95 *
96 * \note A periodic timer will drift if this function is used to reset
97 * it. For periodic timers, use the timer_reset() function instead.
98 *
99 * \param t A pointer to the timer.
100 *
101 * \sa timer_reset()
102 */
103void
104timer_restart(struct timer *t)
105{
106 t->start = clock_time();
107}
108/*---------------------------------------------------------------------------*/
109/**
110 * Check if a timer has expired.
111 *
112 * This function tests if a timer has expired and returns true or
113 * false depending on its status.
114 *
115 * \param t A pointer to the timer
116 *
117 * \return Non-zero if the timer has expired, zero otherwise.
118 *
119 */
120int
121timer_expired(struct timer *t)
122{
123 return (clock_time_t)(clock_time() - t->start) >= (clock_time_t)t->interval;
124}
125/*---------------------------------------------------------------------------*/
126
127/** @} */
128
diff --git a/lib/lufa/Projects/Webserver/Lib/uip/timer.h b/lib/lufa/Projects/Webserver/Lib/uip/timer.h
deleted file mode 100644
index 04917e4c5..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uip/timer.h
+++ /dev/null
@@ -1,87 +0,0 @@
1/**
2 * \defgroup timer Timer library
3 *
4 * The timer library provides functions for setting, resetting and
5 * restarting timers, and for checking if a timer has expired. An
6 * application must "manually" check if its timers have expired; this
7 * is not done automatically.
8 *
9 * A timer is declared as a \c struct \c timer and all access to the
10 * timer is made by a pointer to the declared timer.
11 *
12 * \note The timer library uses the \ref clock "Clock library" to
13 * measure time. Intervals should be specified in the format used by
14 * the clock library.
15 *
16 * @{
17 */
18
19
20/**
21 * \file
22 * Timer library header file.
23 * \author
24 * Adam Dunkels <adam@sics.se>
25 */
26
27/*
28 * Copyright (c) 2004, Swedish Institute of Computer Science.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. Neither the name of the Institute nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 * This file is part of the uIP TCP/IP stack
56 *
57 * Author: Adam Dunkels <adam@sics.se>
58 *
59 * $Id: timer.h,v 1.3 2006/06/11 21:46:39 adam Exp $
60 */
61#ifndef __TIMER_H__
62#define __TIMER_H__
63
64#include "clock.h"
65
66/**
67 * A timer.
68 *
69 * This structure is used for declaring a timer. The timer must be set
70 * with timer_set() before it can be used.
71 *
72 * \hideinitializer
73 */
74struct timer {
75 clock_time_t start;
76 clock_time_t interval;
77};
78
79void timer_set(struct timer *t, clock_time_t interval);
80void timer_reset(struct timer *t);
81void timer_restart(struct timer *t);
82int timer_expired(struct timer *t);
83
84#endif /* __TIMER_H__ */
85
86/** @} */
87
diff --git a/lib/lufa/Projects/Webserver/Lib/uip/uip-split.c b/lib/lufa/Projects/Webserver/Lib/uip/uip-split.c
deleted file mode 100644
index 5222a05b6..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uip/uip-split.c
+++ /dev/null
@@ -1,151 +0,0 @@
1/*
2 * Copyright (c) 2004, Swedish Institute of Computer Science.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 * Author: Adam Dunkels <adam@sics.se>
32 *
33 * $Id: uip-split.c,v 1.2 2008/10/14 13:39:12 julienabeille Exp $
34 */
35
36#include "uip-split.h"
37
38
39#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
40
41/*-----------------------------------------------------------------------------*/
42void
43uip_split_output(void)
44{
45#if UIP_TCP
46 u16_t tcplen, len1, len2;
47
48 /* We only try to split maximum sized TCP segments. */
49 if(BUF->proto == UIP_PROTO_TCP && uip_len == UIP_BUFSIZE) {
50
51 tcplen = uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN;
52 /* Split the segment in two. If the original packet length was
53 odd, we make the second packet one byte larger. */
54 len1 = len2 = tcplen / 2;
55 if(len1 + len2 < tcplen) {
56 ++len2;
57 }
58
59 /* Create the first packet. This is done by altering the length
60 field of the IP header and updating the checksums. */
61 uip_len = len1 + UIP_TCPIP_HLEN + UIP_LLH_LEN;
62#if UIP_CONF_IPV6
63 /* For IPv6, the IP length field does not include the IPv6 IP header
64 length. */
65 BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
66 BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
67#else /* UIP_CONF_IPV6 */
68 BUF->len[0] = (uip_len - UIP_LLH_LEN) >> 8;
69 BUF->len[1] = (uip_len - UIP_LLH_LEN) & 0xff;
70#endif /* UIP_CONF_IPV6 */
71
72 /* Recalculate the TCP checksum. */
73 BUF->tcpchksum = 0;
74 BUF->tcpchksum = ~(uip_tcpchksum());
75
76#if !UIP_CONF_IPV6
77 /* Recalculate the IP checksum. */
78 BUF->ipchksum = 0;
79 BUF->ipchksum = ~(uip_ipchksum());
80#endif /* UIP_CONF_IPV6 */
81
82 /* Transmit the first packet. */
83#if UIP_CONF_IPV6
84 tcpip_ipv6_output();
85#else
86 if (USB_CurrentMode == USB_MODE_Device)
87 RNDIS_Device_SendPacket(&Ethernet_RNDIS_Interface_Device, uip_buf, uip_len);
88 else
89 RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface_Host, uip_buf, uip_len);
90#endif /* UIP_CONF_IPV6 */
91
92 /* Now, create the second packet. To do this, it is not enough to
93 just alter the length field, but we must also update the TCP
94 sequence number and point the uip_appdata to a new place in
95 memory. This place is determined by the length of the first
96 packet (len1). */
97 uip_len = len2 + UIP_TCPIP_HLEN + UIP_LLH_LEN;
98#if UIP_CONF_IPV6
99 /* For IPv6, the IP length field does not include the IPv6 IP header
100 length. */
101 BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
102 BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
103#else /* UIP_CONF_IPV6 */
104 BUF->len[0] = (uip_len - UIP_LLH_LEN) >> 8;
105 BUF->len[1] = (uip_len - UIP_LLH_LEN) & 0xff;
106#endif /* UIP_CONF_IPV6 */
107
108 memcpy(uip_appdata, (u8_t *)uip_appdata + len1, len2);
109
110 uip_add32(BUF->seqno, len1);
111 BUF->seqno[0] = uip_acc32[0];
112 BUF->seqno[1] = uip_acc32[1];
113 BUF->seqno[2] = uip_acc32[2];
114 BUF->seqno[3] = uip_acc32[3];
115
116 /* Recalculate the TCP checksum. */
117 BUF->tcpchksum = 0;
118 BUF->tcpchksum = ~(uip_tcpchksum());
119
120#if !UIP_CONF_IPV6
121 /* Recalculate the IP checksum. */
122 BUF->ipchksum = 0;
123 BUF->ipchksum = ~(uip_ipchksum());
124#endif /* UIP_CONF_IPV6 */
125
126 /* Transmit the second packet. */
127#if UIP_CONF_IPV6
128 tcpip_ipv6_output();
129#else
130 if (USB_CurrentMode == USB_MODE_Device)
131 RNDIS_Device_SendPacket(&Ethernet_RNDIS_Interface_Device, uip_buf, uip_len);
132 else
133 RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface_Host, uip_buf, uip_len);
134#endif /* UIP_CONF_IPV6 */
135 return;
136 }
137#endif /* UIP_TCP */
138
139 /* uip_fw_output();*/
140#if UIP_CONF_IPV6
141 tcpip_ipv6_output();
142#else
143 if (USB_CurrentMode == USB_MODE_Device)
144 RNDIS_Device_SendPacket(&Ethernet_RNDIS_Interface_Device, uip_buf, uip_len);
145 else
146 RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface_Host, uip_buf, uip_len);
147#endif /* UIP_CONF_IPV6 */
148}
149
150/*-----------------------------------------------------------------------------*/
151
diff --git a/lib/lufa/Projects/Webserver/Lib/uip/uip-split.h b/lib/lufa/Projects/Webserver/Lib/uip/uip-split.h
deleted file mode 100644
index 0c768ce40..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uip/uip-split.h
+++ /dev/null
@@ -1,104 +0,0 @@
1/*
2 * Copyright (c) 2004, Swedish Institute of Computer Science.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 * Author: Adam Dunkels <adam@sics.se>
32 *
33 * $Id: uip-split.h,v 1.1 2006/06/17 22:41:19 adamdunkels Exp $
34 */
35/**
36 * \addtogroup uip
37 * @{
38 */
39
40/**
41 * \defgroup uipsplit uIP TCP throughput booster hack
42 * @{
43 *
44 * The basic uIP TCP implementation only allows each TCP connection to
45 * have a single TCP segment in flight at any given time. Because of
46 * the delayed ACK algorithm employed by most TCP receivers, uIP's
47 * limit on the amount of in-flight TCP segments seriously reduces the
48 * maximum achievable throughput for sending data from uIP.
49 *
50 * The uip-split module is a hack which tries to remedy this
51 * situation. By splitting maximum sized outgoing TCP segments into
52 * two, the delayed ACK algorithm is not invoked at TCP
53 * receivers. This improves the throughput when sending data from uIP
54 * by orders of magnitude.
55 *
56 * The uip-split module uses the uip-fw module (uIP IP packet
57 * forwarding) for sending packets. Therefore, the uip-fw module must
58 * be set up with the appropriate network interfaces for this module
59 * to work.
60 */
61
62
63/**
64 * \file
65 * Module for splitting outbound TCP segments in two to avoid the
66 * delayed ACK throughput degradation.
67 * \author
68 * Adam Dunkels <adam@sics.se>
69 *
70 */
71
72#ifndef __UIP_SPLIT_H__
73#define __UIP_SPLIT_H__
74
75#include <string.h>
76#include <uip.h>
77
78#include "../../USBHostMode.h"
79
80#include <LUFA/Drivers/USB/USB.h>
81
82/**
83 * Handle outgoing packets.
84 *
85 * This function inspects an outgoing packet in the uip_buf buffer and
86 * sends it out using the uip_fw_output() function. If the packet is a
87 * full-sized TCP segment it will be split into two segments and
88 * transmitted separately. This function should be called instead of
89 * the actual device driver output function, or the uip_fw_output()
90 * function.
91 *
92 * The headers of the outgoing packet is assumed to be in the uip_buf
93 * buffer and the payload is assumed to be wherever uip_appdata
94 * points. The length of the outgoing packet is assumed to be in the
95 * uip_len variable.
96 *
97 */
98void uip_split_output(void);
99void uip_add32(u8_t *op32, u16_t op16);
100#endif /* __UIP_SPLIT_H__ */
101
102/** @} */
103/** @} */
104
diff --git a/lib/lufa/Projects/Webserver/Lib/uip/uip.c b/lib/lufa/Projects/Webserver/Lib/uip/uip.c
deleted file mode 100644
index fead75775..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uip/uip.c
+++ /dev/null
@@ -1,1941 +0,0 @@
1#define DEBUG_PRINTF(...) /*printf(__VA_ARGS__)*/
2
3/**
4 * \addtogroup uip
5 * @{
6 */
7
8/**
9 * \file
10 * The uIP TCP/IP stack code.
11 * \author Adam Dunkels <adam@dunkels.com>
12 */
13
14/*
15 * Copyright (c) 2001-2003, Adam Dunkels.
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. The name of the author may not be used to endorse or promote
27 * products derived from this software without specific prior
28 * written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
31 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
34 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
36 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
38 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
39 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 * This file is part of the uIP TCP/IP stack.
43 *
44 * $Id: uip.c,v 1.15 2008/10/15 08:08:32 adamdunkels Exp $
45 *
46 */
47
48/*
49 * uIP is a small implementation of the IP, UDP and TCP protocols (as
50 * well as some basic ICMP stuff). The implementation couples the IP,
51 * UDP, TCP and the application layers very tightly. To keep the size
52 * of the compiled code down, this code frequently uses the goto
53 * statement. While it would be possible to break the uip_process()
54 * function into many smaller functions, this would increase the code
55 * size because of the overhead of parameter passing and the fact that
56 * the optimizer would not be as efficient.
57 *
58 * The principle is that we have a small buffer, called the uip_buf,
59 * in which the device driver puts an incoming packet. The TCP/IP
60 * stack parses the headers in the packet, and calls the
61 * application. If the remote host has sent data to the application,
62 * this data is present in the uip_buf and the application read the
63 * data from there. It is up to the application to put this data into
64 * a byte stream if needed. The application will not be fed with data
65 * that is out of sequence.
66 *
67 * If the application whishes to send data to the peer, it should put
68 * its data into the uip_buf. The uip_appdata pointer points to the
69 * first available byte. The TCP/IP stack will calculate the
70 * checksums, and fill in the necessary header fields and finally send
71 * the packet back to the peer.
72*/
73
74#include "uip.h"
75#include "uipopt.h"
76#include "uip_arp.h"
77
78#if !UIP_CONF_IPV6 /* If UIP_CONF_IPV6 is defined, we compile the
79 uip6.c file instead of this one. Therefore
80 this #ifndef removes the entire compilation
81 output of the uip.c file */
82
83
84#if UIP_CONF_IPV6
85#include "net/uip-neighbor.h"
86#endif /* UIP_CONF_IPV6 */
87
88#include <string.h>
89
90/*---------------------------------------------------------------------------*/
91/* Variable definitions. */
92
93
94/* The IP address of this host. If it is defined to be fixed (by
95 setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set
96 here. Otherwise, the address */
97#if UIP_FIXEDADDR > 0
98const uip_ipaddr_t uip_hostaddr =
99 { UIP_IPADDR0, UIP_IPADDR1, UIP_IPADDR2, UIP_IPADDR3 };
100const uip_ipaddr_t uip_draddr =
101 { UIP_DRIPADDR0, UIP_DRIPADDR1, UIP_DRIPADDR2, UIP_DRIPADDR3 };
102const uip_ipaddr_t uip_netmask =
103 { UIP_NETMASK0, UIP_NETMASK1, UIP_NETMASK2, UIP_NETMASK3 };
104#else
105uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
106#endif /* UIP_FIXEDADDR */
107
108const uip_ipaddr_t uip_broadcast_addr =
109#if UIP_CONF_IPV6
110 { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
111 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
112#else /* UIP_CONF_IPV6 */
113 { { 0xff, 0xff, 0xff, 0xff } };
114#endif /* UIP_CONF_IPV6 */
115const uip_ipaddr_t uip_all_zeroes_addr = { { 0x0, /* rest is 0 */ } };
116
117#if UIP_FIXEDETHADDR
118const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0,
119 UIP_ETHADDR1,
120 UIP_ETHADDR2,
121 UIP_ETHADDR3,
122 UIP_ETHADDR4,
123 UIP_ETHADDR5}};
124#else
125struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}};
126#endif
127
128#ifndef UIP_CONF_EXTERNAL_BUFFER
129u8_t uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains
130 incoming packets. */
131#endif /* UIP_CONF_EXTERNAL_BUFFER */
132
133void *uip_appdata; /* The uip_appdata pointer points to
134 application data. */
135void *uip_sappdata; /* The uip_appdata pointer points to
136 the application data which is to
137 be sent. */
138#if UIP_URGDATA > 0
139void *uip_urgdata; /* The uip_urgdata pointer points to
140 urgent data (out-of-band data), if
141 present. */
142u16_t uip_urglen, uip_surglen;
143#endif /* UIP_URGDATA > 0 */
144
145u16_t uip_len, uip_slen;
146 /* The uip_len is either 8 or 16 bits,
147 depending on the maximum packet
148 size. */
149
150u8_t uip_flags; /* The uip_flags variable is used for
151 communication between the TCP/IP stack
152 and the application program. */
153struct uip_conn *uip_conn; /* uip_conn always points to the current
154 connection. */
155
156struct uip_conn uip_conns[UIP_CONNS];
157 /* The uip_conns array holds all TCP
158 connections. */
159u16_t uip_listenports[UIP_LISTENPORTS];
160 /* The uip_listenports list all currently
161 listening ports. */
162#if UIP_UDP
163struct uip_udp_conn *uip_udp_conn;
164struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
165#endif /* UIP_UDP */
166
167static u16_t ipid; /* Ths ipid variable is an increasing
168 number that is used for the IP ID
169 field. */
170
171void uip_setipid(u16_t id) { ipid = id; }
172
173static u8_t iss[4]; /* The iss variable is used for the TCP
174 initial sequence number. */
175
176#if UIP_ACTIVE_OPEN
177static u16_t lastport; /* Keeps track of the last port used for
178 a new connection. */
179#endif /* UIP_ACTIVE_OPEN */
180
181/* Temporary variables. */
182u8_t uip_acc32[4];
183static u8_t c, opt;
184static u16_t tmp16;
185
186/* Structures and definitions. */
187#define TCP_FIN 0x01
188#define TCP_SYN 0x02
189#define TCP_RST 0x04
190#define TCP_PSH 0x08
191#define TCP_ACK 0x10
192#define TCP_URG 0x20
193#define TCP_CTL 0x3f
194
195#define TCP_OPT_END 0 /* End of TCP options list */
196#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */
197#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */
198
199#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */
200
201#define ICMP_ECHO_REPLY 0
202#define ICMP_ECHO 8
203
204#define ICMP_DEST_UNREACHABLE 3
205#define ICMP_PORT_UNREACHABLE 3
206
207#define ICMP6_ECHO_REPLY 129
208#define ICMP6_ECHO 128
209#define ICMP6_NEIGHBOR_SOLICITATION 135
210#define ICMP6_NEIGHBOR_ADVERTISEMENT 136
211
212#define ICMP6_FLAG_S (1 << 6)
213
214#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1
215#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2
216
217
218/* Macros. */
219#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
220#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0])
221#define ICMPBUF ((struct uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
222#define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
223
224
225#if UIP_STATISTICS == 1
226struct uip_stats uip_stat;
227#define UIP_STAT(s) s
228#else
229#define UIP_STAT(s)
230#endif /* UIP_STATISTICS == 1 */
231
232#if UIP_LOGGING == 1
233#include <stdio.h>
234void uip_log(char *msg);
235#define UIP_LOG(m) uip_log(m)
236#else
237#define UIP_LOG(m)
238#endif /* UIP_LOGGING == 1 */
239
240#if ! UIP_ARCH_ADD32
241void
242uip_add32(u8_t *op32, u16_t op16)
243{
244 uip_acc32[3] = op32[3] + (op16 & 0xff);
245 uip_acc32[2] = op32[2] + (op16 >> 8);
246 uip_acc32[1] = op32[1];
247 uip_acc32[0] = op32[0];
248
249 if(uip_acc32[2] < (op16 >> 8)) {
250 ++uip_acc32[1];
251 if(uip_acc32[1] == 0) {
252 ++uip_acc32[0];
253 }
254 }
255
256
257 if(uip_acc32[3] < (op16 & 0xff)) {
258 ++uip_acc32[2];
259 if(uip_acc32[2] == 0) {
260 ++uip_acc32[1];
261 if(uip_acc32[1] == 0) {
262 ++uip_acc32[0];
263 }
264 }
265 }
266}
267
268#endif /* UIP_ARCH_ADD32 */
269
270#if ! UIP_ARCH_CHKSUM
271/*---------------------------------------------------------------------------*/
272static u16_t
273chksum(u16_t sum, const u8_t *data, u16_t len)
274{
275 u16_t t;
276 const u8_t *dataptr;
277 const u8_t *last_byte;
278
279 dataptr = data;
280 last_byte = data + len - 1;
281
282 while(dataptr < last_byte) { /* At least two more bytes */
283 t = (dataptr[0] << 8) + dataptr[1];
284 sum += t;
285 if(sum < t) {
286 sum++; /* carry */
287 }
288 dataptr += 2;
289 }
290
291 if(dataptr == last_byte) {
292 t = (dataptr[0] << 8) + 0;
293 sum += t;
294 if(sum < t) {
295 sum++; /* carry */
296 }
297 }
298
299 /* Return sum in host byte order. */
300 return sum;
301}
302/*---------------------------------------------------------------------------*/
303u16_t
304uip_chksum(u16_t *data, u16_t len)
305{
306 return htons(chksum(0, (u8_t *)data, len));
307}
308/*---------------------------------------------------------------------------*/
309#ifndef UIP_ARCH_IPCHKSUM
310u16_t
311uip_ipchksum(void)
312{
313 u16_t sum;
314
315 sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN);
316 DEBUG_PRINTF("uip_ipchksum: sum 0x%04x\n", sum);
317 return (sum == 0) ? 0xffff : htons(sum);
318}
319#endif
320/*---------------------------------------------------------------------------*/
321static u16_t
322upper_layer_chksum(u8_t proto)
323{
324 u16_t upper_layer_len;
325 u16_t sum;
326
327#if UIP_CONF_IPV6
328 upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]);
329#else /* UIP_CONF_IPV6 */
330 upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN;
331#endif /* UIP_CONF_IPV6 */
332
333 /* First sum pseudo-header. */
334
335 /* IP protocol and length fields. This addition cannot carry. */
336 sum = upper_layer_len + proto;
337 /* Sum IP source and destination addresses. */
338 sum = chksum(sum, (u8_t *)&BUF->srcipaddr, 2 * sizeof(uip_ipaddr_t));
339
340 /* Sum TCP header and data. */
341 sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN],
342 upper_layer_len);
343
344 return (sum == 0) ? 0xffff : htons(sum);
345}
346/*---------------------------------------------------------------------------*/
347#if UIP_CONF_IPV6
348u16_t
349uip_icmp6chksum(void)
350{
351 return upper_layer_chksum(UIP_PROTO_ICMP6);
352
353}
354#endif /* UIP_CONF_IPV6 */
355/*---------------------------------------------------------------------------*/
356u16_t
357uip_tcpchksum(void)
358{
359 return upper_layer_chksum(UIP_PROTO_TCP);
360}
361/*---------------------------------------------------------------------------*/
362#if UIP_UDP_CHECKSUMS
363u16_t
364uip_udpchksum(void)
365{
366 return upper_layer_chksum(UIP_PROTO_UDP);
367}
368#endif /* UIP_UDP_CHECKSUMS */
369#endif /* UIP_ARCH_CHKSUM */
370/*---------------------------------------------------------------------------*/
371void
372uip_init(void)
373{
374 for(c = 0; c < UIP_LISTENPORTS; ++c) {
375 uip_listenports[c] = 0;
376 }
377 for(c = 0; c < UIP_CONNS; ++c) {
378 uip_conns[c].tcpstateflags = UIP_CLOSED;
379 }
380#if UIP_ACTIVE_OPEN
381 lastport = 1024;
382#endif /* UIP_ACTIVE_OPEN */
383
384#if UIP_UDP
385 for(c = 0; c < UIP_UDP_CONNS; ++c) {
386 uip_udp_conns[c].lport = 0;
387 }
388#endif /* UIP_UDP */
389
390
391 /* IPv4 initialization. */
392#if UIP_FIXEDADDR == 0
393 /* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/
394#endif /* UIP_FIXEDADDR */
395
396}
397/*---------------------------------------------------------------------------*/
398#if UIP_ACTIVE_OPEN
399struct uip_conn *
400uip_connect(uip_ipaddr_t *ripaddr, u16_t rport)
401{
402 register struct uip_conn *conn, *cconn;
403
404 /* Find an unused local port. */
405 again:
406 ++lastport;
407
408 if(lastport >= 32000) {
409 lastport = 4096;
410 }
411
412 /* Check if this port is already in use, and if so try to find
413 another one. */
414 for(c = 0; c < UIP_CONNS; ++c) {
415 conn = &uip_conns[c];
416 if(conn->tcpstateflags != UIP_CLOSED &&
417 conn->lport == htons(lastport)) {
418 goto again;
419 }
420 }
421
422 conn = 0;
423 for(c = 0; c < UIP_CONNS; ++c) {
424 cconn = &uip_conns[c];
425 if(cconn->tcpstateflags == UIP_CLOSED) {
426 conn = cconn;
427 break;
428 }
429 if(cconn->tcpstateflags == UIP_TIME_WAIT) {
430 if(conn == 0 ||
431 cconn->timer > conn->timer) {
432 conn = cconn;
433 }
434 }
435 }
436
437 if(conn == 0) {
438 return 0;
439 }
440
441 conn->tcpstateflags = UIP_SYN_SENT;
442
443 conn->snd_nxt[0] = iss[0];
444 conn->snd_nxt[1] = iss[1];
445 conn->snd_nxt[2] = iss[2];
446 conn->snd_nxt[3] = iss[3];
447
448 conn->initialmss = conn->mss = UIP_TCP_MSS;
449
450 conn->len = 1; /* TCP length of the SYN is one. */
451 conn->nrtx = 0;
452 conn->timer = 1; /* Send the SYN next time around. */
453 conn->rto = UIP_RTO;
454 conn->sa = 0;
455 conn->sv = 16; /* Initial value of the RTT variance. */
456 conn->lport = htons(lastport);
457 conn->rport = rport;
458 uip_ipaddr_copy(&conn->ripaddr, ripaddr);
459
460 return conn;
461}
462#endif /* UIP_ACTIVE_OPEN */
463/*---------------------------------------------------------------------------*/
464#if UIP_UDP
465struct uip_udp_conn *
466uip_udp_new(const uip_ipaddr_t *ripaddr, u16_t rport)
467{
468 register struct uip_udp_conn *conn;
469
470 /* Find an unused local port. */
471 again:
472 ++lastport;
473
474 if(lastport >= 32000) {
475 lastport = 4096;
476 }
477
478 for(c = 0; c < UIP_UDP_CONNS; ++c) {
479 if(uip_udp_conns[c].lport == htons(lastport)) {
480 goto again;
481 }
482 }
483
484
485 conn = 0;
486 for(c = 0; c < UIP_UDP_CONNS; ++c) {
487 if(uip_udp_conns[c].lport == 0) {
488 conn = &uip_udp_conns[c];
489 break;
490 }
491 }
492
493 if(conn == 0) {
494 return 0;
495 }
496
497 conn->lport = HTONS(lastport);
498 conn->rport = rport;
499 if(ripaddr == NULL) {
500 memset(&conn->ripaddr, 0, sizeof(uip_ipaddr_t));
501 } else {
502 uip_ipaddr_copy(&conn->ripaddr, ripaddr);
503 }
504 conn->ttl = UIP_TTL;
505
506 return conn;
507}
508#endif /* UIP_UDP */
509/*---------------------------------------------------------------------------*/
510void
511uip_unlisten(u16_t port)
512{
513 for(c = 0; c < UIP_LISTENPORTS; ++c) {
514 if(uip_listenports[c] == port) {
515 uip_listenports[c] = 0;
516 return;
517 }
518 }
519}
520/*---------------------------------------------------------------------------*/
521void
522uip_listen(u16_t port)
523{
524 for(c = 0; c < UIP_LISTENPORTS; ++c) {
525 if(uip_listenports[c] == 0) {
526 uip_listenports[c] = port;
527 return;
528 }
529 }
530}
531/*---------------------------------------------------------------------------*/
532/* XXX: IP fragment reassembly: not well-tested. */
533
534#if UIP_REASSEMBLY && !UIP_CONF_IPV6
535#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
536static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
537static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
538static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
539 0x0f, 0x07, 0x03, 0x01};
540static u16_t uip_reasslen;
541static u8_t uip_reassflags;
542#define UIP_REASS_FLAG_LASTFRAG 0x01
543static u8_t uip_reasstmr;
544
545#define IP_MF 0x20
546
547static u8_t
548uip_reass(void)
549{
550 u16_t offset, len;
551 u16_t i;
552
553 /* If ip_reasstmr is zero, no packet is present in the buffer, so we
554 write the IP header of the fragment into the reassembly
555 buffer. The timer is updated with the maximum age. */
556 if(uip_reasstmr == 0) {
557 memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN);
558 uip_reasstmr = UIP_REASS_MAXAGE;
559 uip_reassflags = 0;
560 /* Clear the bitmap. */
561 memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap));
562 }
563
564 /* Check if the incoming fragment matches the one currently present
565 in the reasembly buffer. If so, we proceed with copying the
566 fragment into the buffer. */
567 if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
568 BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&
569 BUF->destipaddr[0] == FBUF->destipaddr[0] &&
570 BUF->destipaddr[1] == FBUF->destipaddr[1] &&
571 BUF->ipid[0] == FBUF->ipid[0] &&
572 BUF->ipid[1] == FBUF->ipid[1]) {
573
574 len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;
575 offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8;
576
577 /* If the offset or the offset + fragment length overflows the
578 reassembly buffer, we discard the entire packet. */
579 if(offset > UIP_REASS_BUFSIZE ||
580 offset + len > UIP_REASS_BUFSIZE) {
581 uip_reasstmr = 0;
582 goto nullreturn;
583 }
584
585 /* Copy the fragment into the reassembly buffer, at the right
586 offset. */
587 memcpy(&uip_reassbuf[UIP_IPH_LEN + offset],
588 (char *)BUF + (int)((BUF->vhl & 0x0f) * 4),
589 len);
590
591 /* Update the bitmap. */
592 if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
593 /* If the two endpoints are in the same byte, we only update
594 that byte. */
595
596 uip_reassbitmap[offset / (8 * 8)] |=
597 bitmap_bits[(offset / 8 ) & 7] &
598 ~bitmap_bits[((offset + len) / 8 ) & 7];
599 } else {
600 /* If the two endpoints are in different bytes, we update the
601 bytes in the endpoints and fill the stuff in-between with
602 0xff. */
603 uip_reassbitmap[offset / (8 * 8)] |=
604 bitmap_bits[(offset / 8 ) & 7];
605 for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
606 uip_reassbitmap[i] = 0xff;
607 }
608 uip_reassbitmap[(offset + len) / (8 * 8)] |=
609 ~bitmap_bits[((offset + len) / 8 ) & 7];
610 }
611
612 /* If this fragment has the More Fragments flag set to zero, we
613 know that this is the last fragment, so we can calculate the
614 size of the entire packet. We also set the
615 IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
616 the final fragment. */
617
618 if((BUF->ipoffset[0] & IP_MF) == 0) {
619 uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
620 uip_reasslen = offset + len;
621 }
622
623 /* Finally, we check if we have a full packet in the buffer. We do
624 this by checking if we have the last fragment and if all bits
625 in the bitmap are set. */
626 if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
627 /* Check all bytes up to and including all but the last byte in
628 the bitmap. */
629 for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
630 if(uip_reassbitmap[i] != 0xff) {
631 goto nullreturn;
632 }
633 }
634 /* Check the last byte in the bitmap. It should contain just the
635 right amount of bits. */
636 if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
637 (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
638 goto nullreturn;
639 }
640
641 /* If we have come this far, we have a full packet in the
642 buffer, so we allocate a pbuf and copy the packet into it. We
643 also reset the timer. */
644 uip_reasstmr = 0;
645 memcpy(BUF, FBUF, uip_reasslen);
646
647 /* Pretend to be a "normal" (i.e., not fragmented) IP packet
648 from now on. */
649 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
650 BUF->len[0] = uip_reasslen >> 8;
651 BUF->len[1] = uip_reasslen & 0xff;
652 BUF->ipchksum = 0;
653 BUF->ipchksum = ~(uip_ipchksum());
654
655 return uip_reasslen;
656 }
657 }
658
659 nullreturn:
660 return 0;
661}
662#endif /* UIP_REASSEMBLY */
663/*---------------------------------------------------------------------------*/
664static void
665uip_add_rcv_nxt(u16_t n)
666{
667 uip_add32(uip_conn->rcv_nxt, n);
668 uip_conn->rcv_nxt[0] = uip_acc32[0];
669 uip_conn->rcv_nxt[1] = uip_acc32[1];
670 uip_conn->rcv_nxt[2] = uip_acc32[2];
671 uip_conn->rcv_nxt[3] = uip_acc32[3];
672}
673/*---------------------------------------------------------------------------*/
674void
675uip_process(u8_t flag)
676{
677 register struct uip_conn *uip_connr = uip_conn;
678
679#if UIP_UDP
680 if(flag == UIP_UDP_SEND_CONN) {
681 goto udp_send;
682 }
683#endif /* UIP_UDP */
684
685 uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN];
686
687 /* Check if we were invoked because of a poll request for a
688 particular connection. */
689 if(flag == UIP_POLL_REQUEST) {
690 if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED &&
691 !uip_outstanding(uip_connr)) {
692 uip_len = uip_slen = 0;
693 uip_flags = UIP_POLL;
694 UIP_APPCALL();
695 goto appsend;
696 }
697 goto drop;
698
699 /* Check if we were invoked because of the periodic timer firing. */
700 } else if(flag == UIP_TIMER) {
701#if UIP_REASSEMBLY
702 if(uip_reasstmr != 0) {
703 --uip_reasstmr;
704 }
705#endif /* UIP_REASSEMBLY */
706 /* Increase the initial sequence number. */
707 if(++iss[3] == 0) {
708 if(++iss[2] == 0) {
709 if(++iss[1] == 0) {
710 ++iss[0];
711 }
712 }
713 }
714
715 /* Reset the length variables. */
716 uip_len = 0;
717 uip_slen = 0;
718
719 /* Check if the connection is in a state in which we simply wait
720 for the connection to time out. If so, we increase the
721 connection's timer and remove the connection if it times
722 out. */
723 if(uip_connr->tcpstateflags == UIP_TIME_WAIT ||
724 uip_connr->tcpstateflags == UIP_FIN_WAIT_2) {
725 ++(uip_connr->timer);
726 if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
727 uip_connr->tcpstateflags = UIP_CLOSED;
728 }
729 } else if(uip_connr->tcpstateflags != UIP_CLOSED) {
730 /* If the connection has outstanding data, we increase the
731 connection's timer and see if it has reached the RTO value
732 in which case we retransmit. */
733 if(uip_outstanding(uip_connr)) {
734 if(uip_connr->timer-- == 0) {
735 if(uip_connr->nrtx == UIP_MAXRTX ||
736 ((uip_connr->tcpstateflags == UIP_SYN_SENT ||
737 uip_connr->tcpstateflags == UIP_SYN_RCVD) &&
738 uip_connr->nrtx == UIP_MAXSYNRTX)) {
739 uip_connr->tcpstateflags = UIP_CLOSED;
740
741 /* We call UIP_APPCALL() with uip_flags set to
742 UIP_TIMEDOUT to inform the application that the
743 connection has timed out. */
744 uip_flags = UIP_TIMEDOUT;
745 UIP_APPCALL();
746
747 /* We also send a reset packet to the remote host. */
748 BUF->flags = TCP_RST | TCP_ACK;
749 goto tcp_send_nodata;
750 }
751
752 /* Exponential back-off. */
753 uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
754 4:
755 uip_connr->nrtx);
756 ++(uip_connr->nrtx);
757
758 /* Ok, so we need to retransmit. We do this differently
759 depending on which state we are in. In ESTABLISHED, we
760 call upon the application so that it may prepare the
761 data for the retransmit. In SYN_RCVD, we resend the
762 SYNACK that we sent earlier and in LAST_ACK we have to
763 retransmit our FINACK. */
764 UIP_STAT(++uip_stat.tcp.rexmit);
765 switch(uip_connr->tcpstateflags & UIP_TS_MASK) {
766 case UIP_SYN_RCVD:
767 /* In the SYN_RCVD state, we should retransmit our
768 SYNACK. */
769 goto tcp_send_synack;
770
771#if UIP_ACTIVE_OPEN
772 case UIP_SYN_SENT:
773 /* In the SYN_SENT state, we retransmit out SYN. */
774 BUF->flags = 0;
775 goto tcp_send_syn;
776#endif /* UIP_ACTIVE_OPEN */
777
778 case UIP_ESTABLISHED:
779 /* In the ESTABLISHED state, we call upon the application
780 to do the actual retransmit after which we jump into
781 the code for sending out the packet (the apprexmit
782 label). */
783 uip_flags = UIP_REXMIT;
784 UIP_APPCALL();
785 goto apprexmit;
786
787 case UIP_FIN_WAIT_1:
788 case UIP_CLOSING:
789 case UIP_LAST_ACK:
790 /* In all these states we should retransmit a FINACK. */
791 goto tcp_send_finack;
792
793 }
794 }
795 } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) {
796 /* If there was no need for a retransmission, we poll the
797 application for new data. */
798 uip_len = uip_slen = 0;
799 uip_flags = UIP_POLL;
800 UIP_APPCALL();
801 goto appsend;
802 }
803 }
804 goto drop;
805 }
806#if UIP_UDP
807 if(flag == UIP_UDP_TIMER) {
808 if(uip_udp_conn->lport != 0) {
809 uip_conn = NULL;
810 uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
811 uip_len = uip_slen = 0;
812 uip_flags = UIP_POLL;
813 UIP_UDP_APPCALL();
814 goto udp_send;
815 } else {
816 goto drop;
817 }
818 }
819#endif
820
821 /* This is where the input processing starts. */
822 UIP_STAT(++uip_stat.ip.recv);
823
824 /* Start of IP input header processing code. */
825
826#if UIP_CONF_IPV6
827 /* Check validity of the IP header. */
828 if((BUF->vtc & 0xf0) != 0x60) { /* IP version and header length. */
829 UIP_STAT(++uip_stat.ip.drop);
830 UIP_STAT(++uip_stat.ip.vhlerr);
831 UIP_LOG("ipv6: invalid version.");
832 goto drop;
833 }
834#else /* UIP_CONF_IPV6 */
835 /* Check validity of the IP header. */
836 if(BUF->vhl != 0x45) { /* IP version and header length. */
837 UIP_STAT(++uip_stat.ip.drop);
838 UIP_STAT(++uip_stat.ip.vhlerr);
839 UIP_LOG("ip: invalid version or header length.");
840 goto drop;
841 }
842#endif /* UIP_CONF_IPV6 */
843
844 /* Check the size of the packet. If the size reported to us in
845 uip_len is smaller the size reported in the IP header, we assume
846 that the packet has been corrupted in transit. If the size of
847 uip_len is larger than the size reported in the IP packet header,
848 the packet has been padded and we set uip_len to the correct
849 value.. */
850
851 if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) {
852 uip_len = (BUF->len[0] << 8) + BUF->len[1];
853#if UIP_CONF_IPV6
854 uip_len += 40; /* The length reported in the IPv6 header is the
855 length of the payload that follows the
856 header. However, uIP uses the uip_len variable
857 for holding the size of the entire packet,
858 including the IP header. For IPv4 this is not a
859 problem as the length field in the IPv4 header
860 contains the length of the entire packet. But
861 for IPv6 we need to add the size of the IPv6
862 header (40 bytes). */
863#endif /* UIP_CONF_IPV6 */
864 } else {
865 UIP_LOG("ip: packet shorter than reported in IP header.");
866 goto drop;
867 }
868
869#if !UIP_CONF_IPV6
870 /* Check the fragment flag. */
871 if((BUF->ipoffset[0] & 0x3f) != 0 ||
872 BUF->ipoffset[1] != 0) {
873#if UIP_REASSEMBLY
874 uip_len = uip_reass();
875 if(uip_len == 0) {
876 goto drop;
877 }
878#else /* UIP_REASSEMBLY */
879 UIP_STAT(++uip_stat.ip.drop);
880 UIP_STAT(++uip_stat.ip.fragerr);
881 UIP_LOG("ip: fragment dropped.");
882 goto drop;
883#endif /* UIP_REASSEMBLY */
884 }
885#endif /* UIP_CONF_IPV6 */
886
887 if(uip_ipaddr_cmp(&uip_hostaddr, &uip_all_zeroes_addr)) {
888 /* If we are configured to use ping IP address configuration and
889 hasn't been assigned an IP address yet, we accept all ICMP
890 packets. */
891#if UIP_PINGADDRCONF && !UIP_CONF_IPV6
892 if(BUF->proto == UIP_PROTO_ICMP) {
893 UIP_LOG("ip: possible ping config packet received.");
894 goto icmp_input;
895 } else {
896 UIP_LOG("ip: packet dropped since no address assigned.");
897 goto drop;
898 }
899#endif /* UIP_PINGADDRCONF */
900
901 } else {
902 /* If IP broadcast support is configured, we check for a broadcast
903 UDP packet, which may be destined to us. */
904#if UIP_BROADCAST
905 DEBUG_PRINTF("UDP IP checksum 0x%04x\n", uip_ipchksum());
906 if(BUF->proto == UIP_PROTO_UDP &&
907 uip_ipaddr_cmp(&BUF->destipaddr, &uip_broadcast_addr))
908 {
909 if (uip_ipaddr_cmp(&BUF->srcipaddr, &uip_all_zeroes_addr))
910 uip_ipaddr_copy(&BUF->srcipaddr, &uip_broadcast_addr);
911
912 goto udp_input;
913 }
914#endif /* UIP_BROADCAST */
915
916 /* Check if the packet is destined for our IP address. */
917#if !UIP_CONF_IPV6
918 if(!uip_ipaddr_cmp(&BUF->destipaddr, &uip_hostaddr)) {
919 UIP_STAT(++uip_stat.ip.drop);
920 goto drop;
921 }
922#else /* UIP_CONF_IPV6 */
923 /* For IPv6, packet reception is a little trickier as we need to
924 make sure that we listen to certain multicast addresses (all
925 hosts multicast address, and the solicited-node multicast
926 address) as well. However, we will cheat here and accept all
927 multicast packets that are sent to the ff02::/16 addresses. */
928 if(!uip_ipaddr_cmp(&BUF->destipaddr, &uip_hostaddr) &&
929 BUF->destipaddr.u16[0] != HTONS(0xff02)) {
930 UIP_STAT(++uip_stat.ip.drop);
931 goto drop;
932 }
933#endif /* UIP_CONF_IPV6 */
934 }
935
936#if !UIP_CONF_IPV6
937 if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
938 checksum. */
939 UIP_STAT(++uip_stat.ip.drop);
940 UIP_STAT(++uip_stat.ip.chkerr);
941 UIP_LOG("ip: bad checksum.");
942 goto drop;
943 }
944#endif /* UIP_CONF_IPV6 */
945
946 if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so,
947 proceed with TCP input
948 processing. */
949 goto tcp_input;
950 }
951
952#if UIP_UDP
953 if(BUF->proto == UIP_PROTO_UDP) {
954 goto udp_input;
955 }
956#endif /* UIP_UDP */
957
958#if !UIP_CONF_IPV6
959 /* ICMPv4 processing code follows. */
960 if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
961 here. */
962 UIP_STAT(++uip_stat.ip.drop);
963 UIP_STAT(++uip_stat.ip.protoerr);
964 UIP_LOG("ip: neither tcp nor icmp.");
965 goto drop;
966 }
967
968#if UIP_PINGADDRCONF
969 icmp_input:
970#endif /* UIP_PINGADDRCONF */
971 UIP_STAT(++uip_stat.icmp.recv);
972
973 /* ICMP echo (i.e., ping) processing. This is simple, we only change
974 the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
975 checksum before we return the packet. */
976 if(ICMPBUF->type != ICMP_ECHO) {
977 UIP_STAT(++uip_stat.icmp.drop);
978 UIP_STAT(++uip_stat.icmp.typeerr);
979 UIP_LOG("icmp: not icmp echo.");
980 goto drop;
981 }
982
983 /* If we are configured to use ping IP address assignment, we use
984 the destination IP address of this ping packet and assign it to
985 yourself. */
986#if UIP_PINGADDRCONF
987 if(uip_ipaddr_cmp(&uip_hostaddr, &uip_all_zeroes_addr)) {
988 uip_hostaddr = BUF->destipaddr;
989 }
990#endif /* UIP_PINGADDRCONF */
991
992 ICMPBUF->type = ICMP_ECHO_REPLY;
993
994 if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
995 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
996 } else {
997 ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
998 }
999
1000 /* Swap IP addresses. */
1001 uip_ipaddr_copy(&BUF->destipaddr, &BUF->srcipaddr);
1002 uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr);
1003
1004 UIP_STAT(++uip_stat.icmp.sent);
1005 BUF->ttl = UIP_TTL;
1006 goto ip_send_nolen;
1007
1008 /* End of IPv4 input header processing code. */
1009#else /* !UIP_CONF_IPV6 */
1010
1011 /* This is IPv6 ICMPv6 processing code. */
1012 DEBUG_PRINTF("icmp6_input: length %d\n", uip_len);
1013
1014 if(BUF->proto != UIP_PROTO_ICMP6) { /* We only allow ICMPv6 packets from
1015 here. */
1016 UIP_STAT(++uip_stat.ip.drop);
1017 UIP_STAT(++uip_stat.ip.protoerr);
1018 UIP_LOG("ip: neither tcp nor icmp6.");
1019 goto drop;
1020 }
1021
1022 UIP_STAT(++uip_stat.icmp.recv);
1023
1024 /* If we get a neighbor solicitation for our address we should send
1025 a neighbor advertisement message back. */
1026 if(ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION) {
1027 if(uip_ipaddr_cmp(&ICMPBUF->icmp6data, &uip_hostaddr)) {
1028
1029 if(ICMPBUF->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) {
1030 /* Save the sender's address in our neighbor list. */
1031 uip_neighbor_add(&ICMPBUF->srcipaddr, &(ICMPBUF->options[2]));
1032 }
1033
1034 /* We should now send a neighbor advertisement back to where the
1035 neighbor solicitation came from. */
1036 ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT;
1037 ICMPBUF->flags = ICMP6_FLAG_S; /* Solicited flag. */
1038
1039 ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0;
1040
1041 uip_ipaddr_copy(&ICMPBUF->destipaddr, &ICMPBUF->srcipaddr);
1042 uip_ipaddr_copy(&ICMPBUF->srcipaddr, &uip_hostaddr);
1043 ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS;
1044 ICMPBUF->options[1] = 1; /* Options length, 1 = 8 bytes. */
1045 memcpy(&(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr));
1046 ICMPBUF->icmpchksum = 0;
1047 ICMPBUF->icmpchksum = ~uip_icmp6chksum();
1048
1049 goto send;
1050
1051 }
1052 goto drop;
1053 } else if(ICMPBUF->type == ICMP6_ECHO) {
1054 /* ICMP echo (i.e., ping) processing. This is simple, we only
1055 change the ICMP type from ECHO to ECHO_REPLY and update the
1056 ICMP checksum before we return the packet. */
1057
1058 ICMPBUF->type = ICMP6_ECHO_REPLY;
1059
1060 uip_ipaddr_copy(&BUF->destipaddr, &BUF->srcipaddr);
1061 uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr);
1062 ICMPBUF->icmpchksum = 0;
1063 ICMPBUF->icmpchksum = ~uip_icmp6chksum();
1064
1065 UIP_STAT(++uip_stat.icmp.sent);
1066 goto send;
1067 } else {
1068 DEBUG_PRINTF("Unknown icmp6 message type %d\n", ICMPBUF->type);
1069 UIP_STAT(++uip_stat.icmp.drop);
1070 UIP_STAT(++uip_stat.icmp.typeerr);
1071 UIP_LOG("icmp: unknown ICMP message.");
1072 goto drop;
1073 }
1074
1075 /* End of IPv6 ICMP processing. */
1076
1077#endif /* !UIP_CONF_IPV6 */
1078
1079#if UIP_UDP
1080 /* UDP input processing. */
1081 udp_input:
1082 /* UDP processing is really just a hack. We don't do anything to the
1083 UDP/IP headers, but let the UDP application do all the hard
1084 work. If the application sets uip_slen, it has a packet to
1085 send. */
1086#if UIP_UDP_CHECKSUMS
1087 uip_len = uip_len - UIP_IPUDPH_LEN;
1088 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
1089 if(UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff) {
1090 UIP_STAT(++uip_stat.udp.drop);
1091 UIP_STAT(++uip_stat.udp.chkerr);
1092 UIP_LOG("udp: bad checksum.");
1093 goto drop;
1094 }
1095#else /* UIP_UDP_CHECKSUMS */
1096 uip_len = uip_len - UIP_IPUDPH_LEN;
1097#endif /* UIP_UDP_CHECKSUMS */
1098
1099 /* Demultiplex this UDP packet between the UDP "connections". */
1100 for(uip_udp_conn = &uip_udp_conns[0];
1101 uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
1102 ++uip_udp_conn) {
1103 /* If the local UDP port is non-zero, the connection is considered
1104 to be used. If so, the local port number is checked against the
1105 destination port number in the received packet. If the two port
1106 numbers match, the remote port number is checked if the
1107 connection is bound to a remote port. Finally, if the
1108 connection is bound to a remote IP address, the source IP
1109 address of the packet is checked. */
1110 if(uip_udp_conn->lport != 0 &&
1111 UDPBUF->destport == uip_udp_conn->lport &&
1112 (uip_udp_conn->rport == 0 ||
1113 UDPBUF->srcport == uip_udp_conn->rport) &&
1114 (uip_ipaddr_cmp(&uip_udp_conn->ripaddr, &uip_all_zeroes_addr) ||
1115 uip_ipaddr_cmp(&uip_udp_conn->ripaddr, &uip_broadcast_addr) ||
1116 uip_ipaddr_cmp(&BUF->srcipaddr, &uip_udp_conn->ripaddr))) {
1117 goto udp_found;
1118 }
1119 }
1120 UIP_LOG("udp: no matching connection found");
1121#if UIP_CONF_ICMP_DEST_UNREACH && !UIP_CONF_IPV6
1122 /* Copy fields from packet header into payload of this ICMP packet. */
1123 memcpy(&(ICMPBUF->payload[0]), ICMPBUF, UIP_IPH_LEN + 8);
1124
1125 /* Set the ICMP type and code. */
1126 ICMPBUF->type = ICMP_DEST_UNREACHABLE;
1127 ICMPBUF->icode = ICMP_PORT_UNREACHABLE;
1128
1129 /* Calculate the ICMP checksum. */
1130 ICMPBUF->icmpchksum = 0;
1131 ICMPBUF->icmpchksum = ~uip_chksum((u16_t *)&(ICMPBUF->type), 36);
1132
1133 /* Set the IP destination address to be the source address of the
1134 original packet. */
1135 uip_ipaddr_copy(&BUF->destipaddr, &BUF->srcipaddr);
1136
1137 /* Set our IP address as the source address. */
1138 uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr);
1139
1140 /* The size of the ICMP destination unreachable packet is 36 + the
1141 size of the IP header (20) = 56. */
1142 uip_len = 36 + UIP_IPH_LEN;
1143 ICMPBUF->len[0] = 0;
1144 ICMPBUF->len[1] = (u8_t)uip_len;
1145 ICMPBUF->ttl = UIP_TTL;
1146 ICMPBUF->proto = UIP_PROTO_ICMP;
1147
1148 goto ip_send_nolen;
1149#else /* UIP_CONF_ICMP_DEST_UNREACH */
1150 goto drop;
1151#endif /* UIP_CONF_ICMP_DEST_UNREACH */
1152
1153 udp_found:
1154 uip_conn = NULL;
1155 uip_flags = UIP_NEWDATA;
1156 uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN];
1157 uip_slen = 0;
1158 UIP_UDP_APPCALL();
1159
1160 udp_send:
1161 if(uip_slen == 0) {
1162 goto drop;
1163 }
1164 uip_len = uip_slen + UIP_IPUDPH_LEN;
1165
1166#if UIP_CONF_IPV6
1167 /* For IPv6, the IP length field does not include the IPv6 IP header
1168 length. */
1169 BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
1170 BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
1171#else /* UIP_CONF_IPV6 */
1172 BUF->len[0] = (uip_len >> 8);
1173 BUF->len[1] = (uip_len & 0xff);
1174#endif /* UIP_CONF_IPV6 */
1175
1176 BUF->ttl = uip_udp_conn->ttl;
1177 BUF->proto = UIP_PROTO_UDP;
1178
1179 UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN);
1180 UDPBUF->udpchksum = 0;
1181
1182 BUF->srcport = uip_udp_conn->lport;
1183 BUF->destport = uip_udp_conn->rport;
1184
1185 uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr);
1186 uip_ipaddr_copy(&BUF->destipaddr, &uip_udp_conn->ripaddr);
1187
1188 uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN];
1189
1190#if UIP_UDP_CHECKSUMS
1191 /* Calculate UDP checksum. */
1192 UDPBUF->udpchksum = ~(uip_udpchksum());
1193 if(UDPBUF->udpchksum == 0) {
1194 UDPBUF->udpchksum = 0xffff;
1195 }
1196#endif /* UIP_UDP_CHECKSUMS */
1197
1198 goto ip_send_nolen;
1199#endif /* UIP_UDP */
1200
1201 /* TCP input processing. */
1202 tcp_input:
1203 UIP_STAT(++uip_stat.tcp.recv);
1204
1205 /* Start of TCP input header processing code. */
1206
1207 if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
1208 checksum. */
1209 UIP_STAT(++uip_stat.tcp.drop);
1210 UIP_STAT(++uip_stat.tcp.chkerr);
1211 UIP_LOG("tcp: bad checksum.");
1212 goto drop;
1213 }
1214
1215 /* Demultiplex this segment. */
1216 /* First check any active connections. */
1217 for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1];
1218 ++uip_connr) {
1219 if(uip_connr->tcpstateflags != UIP_CLOSED &&
1220 BUF->destport == uip_connr->lport &&
1221 BUF->srcport == uip_connr->rport &&
1222 uip_ipaddr_cmp(&BUF->srcipaddr, &uip_connr->ripaddr)) {
1223 goto found;
1224 }
1225 }
1226
1227 /* If we didn't find and active connection that expected the packet,
1228 either this packet is an old duplicate, or this is a SYN packet
1229 destined for a connection in LISTEN. If the SYN flag isn't set,
1230 it is an old packet and we send a RST. */
1231 if((BUF->flags & TCP_CTL) != TCP_SYN) {
1232 goto reset;
1233 }
1234
1235 tmp16 = BUF->destport;
1236 /* Next, check listening connections. */
1237 for(c = 0; c < UIP_LISTENPORTS; ++c) {
1238 if(tmp16 == uip_listenports[c]) {
1239 goto found_listen;
1240 }
1241 }
1242
1243 /* No matching connection found, so we send a RST packet. */
1244 UIP_STAT(++uip_stat.tcp.synrst);
1245
1246 reset:
1247 /* We do not send resets in response to resets. */
1248 if(BUF->flags & TCP_RST) {
1249 goto drop;
1250 }
1251
1252 UIP_STAT(++uip_stat.tcp.rst);
1253
1254 BUF->flags = TCP_RST | TCP_ACK;
1255 uip_len = UIP_IPTCPH_LEN;
1256 BUF->tcpoffset = 5 << 4;
1257
1258 /* Flip the seqno and ackno fields in the TCP header. */
1259 c = BUF->seqno[3];
1260 BUF->seqno[3] = BUF->ackno[3];
1261 BUF->ackno[3] = c;
1262
1263 c = BUF->seqno[2];
1264 BUF->seqno[2] = BUF->ackno[2];
1265 BUF->ackno[2] = c;
1266
1267 c = BUF->seqno[1];
1268 BUF->seqno[1] = BUF->ackno[1];
1269 BUF->ackno[1] = c;
1270
1271 c = BUF->seqno[0];
1272 BUF->seqno[0] = BUF->ackno[0];
1273 BUF->ackno[0] = c;
1274
1275 /* We also have to increase the sequence number we are
1276 acknowledging. If the least significant byte overflowed, we need
1277 to propagate the carry to the other bytes as well. */
1278 if(++BUF->ackno[3] == 0) {
1279 if(++BUF->ackno[2] == 0) {
1280 if(++BUF->ackno[1] == 0) {
1281 ++BUF->ackno[0];
1282 }
1283 }
1284 }
1285
1286 /* Swap port numbers. */
1287 tmp16 = BUF->srcport;
1288 BUF->srcport = BUF->destport;
1289 BUF->destport = tmp16;
1290
1291 /* Swap IP addresses. */
1292 uip_ipaddr_copy(&BUF->destipaddr, &BUF->srcipaddr);
1293 uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr);
1294
1295 /* And send out the RST packet! */
1296 goto tcp_send_noconn;
1297
1298 /* This label will be jumped to if we matched the incoming packet
1299 with a connection in LISTEN. In that case, we should create a new
1300 connection and send a SYNACK in return. */
1301 found_listen:
1302 /* First we check if there are any connections available. Unused
1303 connections are kept in the same table as used connections, but
1304 unused ones have the tcpstate set to CLOSED. Also, connections in
1305 TIME_WAIT are kept track of and we'll use the oldest one if no
1306 CLOSED connections are found. Thanks to Eddie C. Dost for a very
1307 nice algorithm for the TIME_WAIT search. */
1308 uip_connr = 0;
1309 for(c = 0; c < UIP_CONNS; ++c) {
1310 if(uip_conns[c].tcpstateflags == UIP_CLOSED) {
1311 uip_connr = &uip_conns[c];
1312 break;
1313 }
1314 if(uip_conns[c].tcpstateflags == UIP_TIME_WAIT) {
1315 if(uip_connr == 0 ||
1316 uip_conns[c].timer > uip_connr->timer) {
1317 uip_connr = &uip_conns[c];
1318 }
1319 }
1320 }
1321
1322 if(uip_connr == 0) {
1323 /* All connections are used already, we drop packet and hope that
1324 the remote end will retransmit the packet at a time when we
1325 have more spare connections. */
1326 UIP_STAT(++uip_stat.tcp.syndrop);
1327 UIP_LOG("tcp: found no unused connections.");
1328 goto drop;
1329 }
1330 uip_conn = uip_connr;
1331
1332 /* Fill in the necessary fields for the new connection. */
1333 uip_connr->rto = uip_connr->timer = UIP_RTO;
1334 uip_connr->sa = 0;
1335 uip_connr->sv = 4;
1336 uip_connr->nrtx = 0;
1337 uip_connr->lport = BUF->destport;
1338 uip_connr->rport = BUF->srcport;
1339 uip_ipaddr_copy(&uip_connr->ripaddr, &BUF->srcipaddr);
1340 uip_connr->tcpstateflags = UIP_SYN_RCVD;
1341
1342 uip_connr->snd_nxt[0] = iss[0];
1343 uip_connr->snd_nxt[1] = iss[1];
1344 uip_connr->snd_nxt[2] = iss[2];
1345 uip_connr->snd_nxt[3] = iss[3];
1346 uip_connr->len = 1;
1347
1348 /* rcv_nxt should be the seqno from the incoming packet + 1. */
1349 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1350 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1351 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1352 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1353 uip_add_rcv_nxt(1);
1354
1355 /* Parse the TCP MSS option, if present. */
1356 if((BUF->tcpoffset & 0xf0) > 0x50) {
1357 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
1358 opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
1359 if(opt == TCP_OPT_END) {
1360 /* End of options. */
1361 break;
1362 } else if(opt == TCP_OPT_NOOP) {
1363 ++c;
1364 /* NOP option. */
1365 } else if(opt == TCP_OPT_MSS &&
1366 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
1367 /* An MSS option with the right option length. */
1368 tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
1369 (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c];
1370 uip_connr->initialmss = uip_connr->mss =
1371 tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
1372
1373 /* And we are done processing options. */
1374 break;
1375 } else {
1376 /* All other options have a length field, so that we easily
1377 can skip past them. */
1378 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1379 /* If the length field is zero, the options are malformed
1380 and we don't process them further. */
1381 break;
1382 }
1383 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1384 }
1385 }
1386 }
1387
1388 /* Our response will be a SYNACK. */
1389#if UIP_ACTIVE_OPEN
1390 tcp_send_synack:
1391 BUF->flags = TCP_ACK;
1392
1393 tcp_send_syn:
1394 BUF->flags |= TCP_SYN;
1395#else /* UIP_ACTIVE_OPEN */
1396 tcp_send_synack:
1397 BUF->flags = TCP_SYN | TCP_ACK;
1398#endif /* UIP_ACTIVE_OPEN */
1399
1400 /* We send out the TCP Maximum Segment Size option with our
1401 SYNACK. */
1402 BUF->optdata[0] = TCP_OPT_MSS;
1403 BUF->optdata[1] = TCP_OPT_MSS_LEN;
1404 BUF->optdata[2] = (UIP_TCP_MSS) / 256;
1405 BUF->optdata[3] = (UIP_TCP_MSS) & 255;
1406 uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN;
1407 BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4;
1408 goto tcp_send;
1409
1410 /* This label will be jumped to if we found an active connection. */
1411 found:
1412 uip_conn = uip_connr;
1413 uip_flags = 0;
1414 /* We do a very naive form of TCP reset processing; we just accept
1415 any RST and kill our connection. We should in fact check if the
1416 sequence number of this reset is within our advertised window
1417 before we accept the reset. */
1418 if(BUF->flags & TCP_RST) {
1419 uip_connr->tcpstateflags = UIP_CLOSED;
1420 UIP_LOG("tcp: got reset, aborting connection.");
1421 uip_flags = UIP_ABORT;
1422 UIP_APPCALL();
1423 goto drop;
1424 }
1425 /* Calculate the length of the data, if the application has sent
1426 any data to us. */
1427 c = (BUF->tcpoffset >> 4) << 2;
1428 /* uip_len will contain the length of the actual TCP data. This is
1429 calculated by subtracing the length of the TCP header (in
1430 c) and the length of the IP header (20 bytes). */
1431 uip_len = uip_len - c - UIP_IPH_LEN;
1432
1433 /* First, check if the sequence number of the incoming packet is
1434 what we're expecting next. If not, we send out an ACK with the
1435 correct numbers in. */
1436 if(!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) &&
1437 ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) {
1438 if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) &&
1439 (BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
1440 BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
1441 BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
1442 BUF->seqno[3] != uip_connr->rcv_nxt[3])) {
1443 goto tcp_send_ack;
1444 }
1445 }
1446
1447 /* Next, check if the incoming segment acknowledges any outstanding
1448 data. If so, we update the sequence number, reset the length of
1449 the outstanding data, calculate RTT estimations, and reset the
1450 retransmission timer. */
1451 if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
1452 uip_add32(uip_connr->snd_nxt, uip_connr->len);
1453
1454 if(BUF->ackno[0] == uip_acc32[0] &&
1455 BUF->ackno[1] == uip_acc32[1] &&
1456 BUF->ackno[2] == uip_acc32[2] &&
1457 BUF->ackno[3] == uip_acc32[3]) {
1458 /* Update sequence number. */
1459 uip_connr->snd_nxt[0] = uip_acc32[0];
1460 uip_connr->snd_nxt[1] = uip_acc32[1];
1461 uip_connr->snd_nxt[2] = uip_acc32[2];
1462 uip_connr->snd_nxt[3] = uip_acc32[3];
1463
1464 /* Do RTT estimation, unless we have done retransmissions. */
1465 if(uip_connr->nrtx == 0) {
1466 signed char m;
1467 m = uip_connr->rto - uip_connr->timer;
1468 /* This is taken directly from VJs original code in his paper */
1469 m = m - (uip_connr->sa >> 3);
1470 uip_connr->sa += m;
1471 if(m < 0) {
1472 m = -m;
1473 }
1474 m = m - (uip_connr->sv >> 2);
1475 uip_connr->sv += m;
1476 uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
1477
1478 }
1479 /* Set the acknowledged flag. */
1480 uip_flags = UIP_ACKDATA;
1481 /* Reset the retransmission timer. */
1482 uip_connr->timer = uip_connr->rto;
1483
1484 /* Reset length of outstanding data. */
1485 uip_connr->len = 0;
1486 }
1487
1488 }
1489
1490 /* Do different things depending on in what state the connection is. */
1491 switch(uip_connr->tcpstateflags & UIP_TS_MASK) {
1492 /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
1493 implemented, since we force the application to close when the
1494 peer sends a FIN (hence the application goes directly from
1495 ESTABLISHED to LAST_ACK). */
1496 case UIP_SYN_RCVD:
1497 /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
1498 we are waiting for an ACK that acknowledges the data we sent
1499 out the last time. Therefore, we want to have the UIP_ACKDATA
1500 flag set. If so, we enter the ESTABLISHED state. */
1501 if(uip_flags & UIP_ACKDATA) {
1502 uip_connr->tcpstateflags = UIP_ESTABLISHED;
1503 uip_flags = UIP_CONNECTED;
1504 uip_connr->len = 0;
1505 if(uip_len > 0) {
1506 uip_flags |= UIP_NEWDATA;
1507 uip_add_rcv_nxt(uip_len);
1508 }
1509 uip_slen = 0;
1510 UIP_APPCALL();
1511 goto appsend;
1512 }
1513 goto drop;
1514#if UIP_ACTIVE_OPEN
1515 case UIP_SYN_SENT:
1516 /* In SYN_SENT, we wait for a SYNACK that is sent in response to
1517 our SYN. The rcv_nxt is set to sequence number in the SYNACK
1518 plus one, and we send an ACK. We move into the ESTABLISHED
1519 state. */
1520 if((uip_flags & UIP_ACKDATA) &&
1521 (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) {
1522
1523 /* Parse the TCP MSS option, if present. */
1524 if((BUF->tcpoffset & 0xf0) > 0x50) {
1525 for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
1526 opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c];
1527 if(opt == TCP_OPT_END) {
1528 /* End of options. */
1529 break;
1530 } else if(opt == TCP_OPT_NOOP) {
1531 ++c;
1532 /* NOP option. */
1533 } else if(opt == TCP_OPT_MSS &&
1534 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) {
1535 /* An MSS option with the right option length. */
1536 tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
1537 uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
1538 uip_connr->initialmss =
1539 uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
1540
1541 /* And we are done processing options. */
1542 break;
1543 } else {
1544 /* All other options have a length field, so that we easily
1545 can skip past them. */
1546 if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
1547 /* If the length field is zero, the options are malformed
1548 and we don't process them further. */
1549 break;
1550 }
1551 c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
1552 }
1553 }
1554 }
1555 uip_connr->tcpstateflags = UIP_ESTABLISHED;
1556 uip_connr->rcv_nxt[0] = BUF->seqno[0];
1557 uip_connr->rcv_nxt[1] = BUF->seqno[1];
1558 uip_connr->rcv_nxt[2] = BUF->seqno[2];
1559 uip_connr->rcv_nxt[3] = BUF->seqno[3];
1560 uip_add_rcv_nxt(1);
1561 uip_flags = UIP_CONNECTED | UIP_NEWDATA;
1562 uip_connr->len = 0;
1563 uip_len = 0;
1564 uip_slen = 0;
1565 UIP_APPCALL();
1566 goto appsend;
1567 }
1568 /* Inform the application that the connection failed */
1569 uip_flags = UIP_ABORT;
1570 UIP_APPCALL();
1571 /* The connection is closed after we send the RST */
1572 uip_conn->tcpstateflags = UIP_CLOSED;
1573 goto reset;
1574#endif /* UIP_ACTIVE_OPEN */
1575
1576 case UIP_ESTABLISHED:
1577 /* In the ESTABLISHED state, we call upon the application to feed
1578 data into the uip_buf. If the UIP_ACKDATA flag is set, the
1579 application should put new data into the buffer, otherwise we are
1580 retransmitting an old segment, and the application should put that
1581 data into the buffer.
1582
1583 If the incoming packet is a FIN, we should close the connection on
1584 this side as well, and we send out a FIN and enter the LAST_ACK
1585 state. We require that there is no outstanding data; otherwise the
1586 sequence numbers will be screwed up. */
1587
1588 if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
1589 if(uip_outstanding(uip_connr)) {
1590 goto drop;
1591 }
1592 uip_add_rcv_nxt(1 + uip_len);
1593 uip_flags |= UIP_CLOSE;
1594 if(uip_len > 0) {
1595 uip_flags |= UIP_NEWDATA;
1596 }
1597 UIP_APPCALL();
1598 uip_connr->len = 1;
1599 uip_connr->tcpstateflags = UIP_LAST_ACK;
1600 uip_connr->nrtx = 0;
1601 tcp_send_finack:
1602 BUF->flags = TCP_FIN | TCP_ACK;
1603 goto tcp_send_nodata;
1604 }
1605
1606 /* Check the URG flag. If this is set, the segment carries urgent
1607 data that we must pass to the application. */
1608 if((BUF->flags & TCP_URG) != 0) {
1609#if UIP_URGDATA > 0
1610 uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
1611 if(uip_urglen > uip_len) {
1612 /* There is more urgent data in the next segment to come. */
1613 uip_urglen = uip_len;
1614 }
1615 uip_add_rcv_nxt(uip_urglen);
1616 uip_len -= uip_urglen;
1617 uip_urgdata = uip_appdata;
1618 uip_appdata += uip_urglen;
1619 } else {
1620 uip_urglen = 0;
1621#else /* UIP_URGDATA > 0 */
1622 uip_appdata = ((char *)uip_appdata) + ((BUF->urgp[0] << 8) | BUF->urgp[1]);
1623 uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
1624#endif /* UIP_URGDATA > 0 */
1625 }
1626
1627 /* If uip_len > 0 we have TCP data in the packet, and we flag this
1628 by setting the UIP_NEWDATA flag and update the sequence number
1629 we acknowledge. If the application has stopped the dataflow
1630 using uip_stop(), we must not accept any data packets from the
1631 remote host. */
1632 if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
1633 uip_flags |= UIP_NEWDATA;
1634 uip_add_rcv_nxt(uip_len);
1635 }
1636
1637 /* Check if the available buffer space advertised by the other end
1638 is smaller than the initial MSS for this connection. If so, we
1639 set the current MSS to the window size to ensure that the
1640 application does not send more data than the other end can
1641 handle.
1642
1643 If the remote host advertises a zero window, we set the MSS to
1644 the initial MSS so that the application will send an entire MSS
1645 of data. This data will not be acknowledged by the receiver,
1646 and the application will retransmit it. This is called the
1647 "persistent timer" and uses the retransmission mechanism.
1648 */
1649 tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1];
1650 if(tmp16 > uip_connr->initialmss ||
1651 tmp16 == 0) {
1652 tmp16 = uip_connr->initialmss;
1653 }
1654 uip_connr->mss = tmp16;
1655
1656 /* If this packet constitutes an ACK for outstanding data (flagged
1657 by the UIP_ACKDATA flag, we should call the application since it
1658 might want to send more data. If the incoming packet had data
1659 from the peer (as flagged by the UIP_NEWDATA flag), the
1660 application must also be notified.
1661
1662 When the application is called, the global variable uip_len
1663 contains the length of the incoming data. The application can
1664 access the incoming data through the global pointer
1665 uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN
1666 bytes into the uip_buf array.
1667
1668 If the application wishes to send any data, this data should be
1669 put into the uip_appdata and the length of the data should be
1670 put into uip_len. If the application don't have any data to
1671 send, uip_len must be set to 0. */
1672 if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
1673 uip_slen = 0;
1674 UIP_APPCALL();
1675
1676 appsend:
1677
1678 if(uip_flags & UIP_ABORT) {
1679 uip_slen = 0;
1680 uip_connr->tcpstateflags = UIP_CLOSED;
1681 BUF->flags = TCP_RST | TCP_ACK;
1682 goto tcp_send_nodata;
1683 }
1684
1685 if(uip_flags & UIP_CLOSE) {
1686 uip_slen = 0;
1687 uip_connr->len = 1;
1688 uip_connr->tcpstateflags = UIP_FIN_WAIT_1;
1689 uip_connr->nrtx = 0;
1690 BUF->flags = TCP_FIN | TCP_ACK;
1691 goto tcp_send_nodata;
1692 }
1693
1694 /* If uip_slen > 0, the application has data to be sent. */
1695 if(uip_slen > 0) {
1696
1697 /* If the connection has acknowledged data, the contents of
1698 the ->len variable should be discarded. */
1699 if((uip_flags & UIP_ACKDATA) != 0) {
1700 uip_connr->len = 0;
1701 }
1702
1703 /* If the ->len variable is non-zero the connection has
1704 already data in transit and cannot send anymore right
1705 now. */
1706 if(uip_connr->len == 0) {
1707
1708 /* The application cannot send more than what is allowed by
1709 the mss (the minumum of the MSS and the available
1710 window). */
1711 if(uip_slen > uip_connr->mss) {
1712 uip_slen = uip_connr->mss;
1713 }
1714
1715 /* Remember how much data we send out now so that we know
1716 when everything has been acknowledged. */
1717 uip_connr->len = uip_slen;
1718 } else {
1719
1720 /* If the application already had unacknowledged data, we
1721 make sure that the application does not send (i.e.,
1722 retransmit) out more than it previously sent out. */
1723 uip_slen = uip_connr->len;
1724 }
1725 }
1726 uip_connr->nrtx = 0;
1727 apprexmit:
1728 uip_appdata = uip_sappdata;
1729
1730 /* If the application has data to be sent, or if the incoming
1731 packet had new data in it, we must send out a packet. */
1732 if(uip_slen > 0 && uip_connr->len > 0) {
1733 /* Add the length of the IP and TCP headers. */
1734 uip_len = uip_connr->len + UIP_TCPIP_HLEN;
1735 /* We always set the ACK flag in response packets. */
1736 BUF->flags = TCP_ACK | TCP_PSH;
1737 /* Send the packet. */
1738 goto tcp_send_noopts;
1739 }
1740 /* If there is no data to send, just send out a pure ACK if
1741 there is newdata. */
1742 if(uip_flags & UIP_NEWDATA) {
1743 uip_len = UIP_TCPIP_HLEN;
1744 BUF->flags = TCP_ACK;
1745 goto tcp_send_noopts;
1746 }
1747 }
1748 goto drop;
1749 case UIP_LAST_ACK:
1750 /* We can close this connection if the peer has acknowledged our
1751 FIN. This is indicated by the UIP_ACKDATA flag. */
1752 if(uip_flags & UIP_ACKDATA) {
1753 uip_connr->tcpstateflags = UIP_CLOSED;
1754 uip_flags = UIP_CLOSE;
1755 UIP_APPCALL();
1756 }
1757 break;
1758
1759 case UIP_FIN_WAIT_1:
1760 /* The application has closed the connection, but the remote host
1761 hasn't closed its end yet. Thus we do nothing but wait for a
1762 FIN from the other side. */
1763 if(uip_len > 0) {
1764 uip_add_rcv_nxt(uip_len);
1765 }
1766 if(BUF->flags & TCP_FIN) {
1767 if(uip_flags & UIP_ACKDATA) {
1768 uip_connr->tcpstateflags = UIP_TIME_WAIT;
1769 uip_connr->timer = 0;
1770 uip_connr->len = 0;
1771 } else {
1772 uip_connr->tcpstateflags = UIP_CLOSING;
1773 }
1774 uip_add_rcv_nxt(1);
1775 uip_flags = UIP_CLOSE;
1776 UIP_APPCALL();
1777 goto tcp_send_ack;
1778 } else if(uip_flags & UIP_ACKDATA) {
1779 uip_connr->tcpstateflags = UIP_FIN_WAIT_2;
1780 uip_connr->len = 0;
1781 goto drop;
1782 }
1783 if(uip_len > 0) {
1784 goto tcp_send_ack;
1785 }
1786 goto drop;
1787
1788 case UIP_FIN_WAIT_2:
1789 if(uip_len > 0) {
1790 uip_add_rcv_nxt(uip_len);
1791 }
1792 if(BUF->flags & TCP_FIN) {
1793 uip_connr->tcpstateflags = UIP_TIME_WAIT;
1794 uip_connr->timer = 0;
1795 uip_add_rcv_nxt(1);
1796 uip_flags = UIP_CLOSE;
1797 UIP_APPCALL();
1798 goto tcp_send_ack;
1799 }
1800 if(uip_len > 0) {
1801 goto tcp_send_ack;
1802 }
1803 goto drop;
1804
1805 case UIP_TIME_WAIT:
1806 goto tcp_send_ack;
1807
1808 case UIP_CLOSING:
1809 if(uip_flags & UIP_ACKDATA) {
1810 uip_connr->tcpstateflags = UIP_TIME_WAIT;
1811 uip_connr->timer = 0;
1812 }
1813 }
1814 goto drop;
1815
1816 /* We jump here when we are ready to send the packet, and just want
1817 to set the appropriate TCP sequence numbers in the TCP header. */
1818 tcp_send_ack:
1819 BUF->flags = TCP_ACK;
1820
1821 tcp_send_nodata:
1822 uip_len = UIP_IPTCPH_LEN;
1823
1824 tcp_send_noopts:
1825 BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4;
1826
1827 /* We're done with the input processing. We are now ready to send a
1828 reply. Our job is to fill in all the fields of the TCP and IP
1829 headers before calculating the checksum and finally send the
1830 packet. */
1831 tcp_send:
1832 BUF->ackno[0] = uip_connr->rcv_nxt[0];
1833 BUF->ackno[1] = uip_connr->rcv_nxt[1];
1834 BUF->ackno[2] = uip_connr->rcv_nxt[2];
1835 BUF->ackno[3] = uip_connr->rcv_nxt[3];
1836
1837 BUF->seqno[0] = uip_connr->snd_nxt[0];
1838 BUF->seqno[1] = uip_connr->snd_nxt[1];
1839 BUF->seqno[2] = uip_connr->snd_nxt[2];
1840 BUF->seqno[3] = uip_connr->snd_nxt[3];
1841
1842 BUF->proto = UIP_PROTO_TCP;
1843
1844 BUF->srcport = uip_connr->lport;
1845 BUF->destport = uip_connr->rport;
1846
1847 uip_ipaddr_copy(&BUF->srcipaddr, &uip_hostaddr);
1848 uip_ipaddr_copy(&BUF->destipaddr, &uip_connr->ripaddr);
1849
1850 if(uip_connr->tcpstateflags & UIP_STOPPED) {
1851 /* If the connection has issued uip_stop(), we advertise a zero
1852 window so that the remote host will stop sending data. */
1853 BUF->wnd[0] = BUF->wnd[1] = 0;
1854 } else {
1855 BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
1856 BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff);
1857 }
1858
1859 tcp_send_noconn:
1860 BUF->ttl = UIP_TTL;
1861#if UIP_CONF_IPV6
1862 /* For IPv6, the IP length field does not include the IPv6 IP header
1863 length. */
1864 BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
1865 BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
1866#else /* UIP_CONF_IPV6 */
1867 BUF->len[0] = (uip_len >> 8);
1868 BUF->len[1] = (uip_len & 0xff);
1869#endif /* UIP_CONF_IPV6 */
1870
1871 BUF->urgp[0] = BUF->urgp[1] = 0;
1872
1873 /* Calculate TCP checksum. */
1874 BUF->tcpchksum = 0;
1875 BUF->tcpchksum = ~(uip_tcpchksum());
1876
1877 ip_send_nolen:
1878#if UIP_CONF_IPV6
1879 BUF->vtc = 0x60;
1880 BUF->tcflow = 0x00;
1881 BUF->flow = 0x00;
1882#else /* UIP_CONF_IPV6 */
1883 BUF->vhl = 0x45;
1884 BUF->tos = 0;
1885 BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
1886 ++ipid;
1887 BUF->ipid[0] = ipid >> 8;
1888 BUF->ipid[1] = ipid & 0xff;
1889 /* Calculate IP checksum. */
1890 BUF->ipchksum = 0;
1891 BUF->ipchksum = ~(uip_ipchksum());
1892 DEBUG_PRINTF("uip ip_send_nolen: checksum 0x%04x\n", uip_ipchksum());
1893#endif /* UIP_CONF_IPV6 */
1894 UIP_STAT(++uip_stat.tcp.sent);
1895#if UIP_CONF_IPV6
1896 send:
1897#endif /* UIP_CONF_IPV6 */
1898 DEBUG_PRINTF("Sending packet with length %d (%d)\n", uip_len,
1899 (BUF->len[0] << 8) | BUF->len[1]);
1900
1901 UIP_STAT(++uip_stat.ip.sent);
1902 /* Return and let the caller do the actual transmission. */
1903 uip_flags = 0;
1904 return;
1905
1906 drop:
1907 uip_len = 0;
1908 uip_flags = 0;
1909 return;
1910}
1911/*---------------------------------------------------------------------------*/
1912u16_t
1913htons(u16_t val)
1914{
1915 return HTONS(val);
1916}
1917
1918u32_t
1919htonl(u32_t val)
1920{
1921 return HTONL(val);
1922}
1923/*---------------------------------------------------------------------------*/
1924void
1925uip_send(const void *data, int len)
1926{
1927 int copylen;
1928#define MIN(a,b) ((a) < (b)? (a): (b))
1929 copylen = MIN(len, UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN -
1930 (int)((char *)uip_sappdata - (char *)&uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN]));
1931 if(copylen > 0) {
1932 uip_slen = copylen;
1933 if(data != uip_sappdata) {
1934 memcpy(uip_sappdata, (data), uip_slen);
1935 }
1936 }
1937}
1938/*---------------------------------------------------------------------------*/
1939/** @} */
1940#endif /* UIP_CONF_IPV6 */
1941
diff --git a/lib/lufa/Projects/Webserver/Lib/uip/uip.h b/lib/lufa/Projects/Webserver/Lib/uip/uip.h
deleted file mode 100644
index 7b87a2c77..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uip/uip.h
+++ /dev/null
@@ -1,2130 +0,0 @@
1
2/**
3 * \addtogroup uip
4 * @{
5 */
6
7/**
8 * \file
9 * Header file for the uIP TCP/IP stack.
10 * \author Adam Dunkels <adam@dunkels.com>
11 * \author Julien Abeille <jabeille@cisco.com> (IPv6 related code)
12 * \author Mathilde Durvy <mdurvy@cisco.com> (IPv6 related code)
13 *
14 * The uIP TCP/IP stack header file contains definitions for a number
15 * of C macros that are used by uIP programs as well as internal uIP
16 * structures, TCP/IP header structures and function declarations.
17 *
18 */
19
20/*
21 * Copyright (c) 2001-2003, Adam Dunkels.
22 * All rights reserved.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 * 3. The name of the author may not be used to endorse or promote
33 * products derived from this software without specific prior
34 * written permission.
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
37 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
40 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
42 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
43 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
45 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 *
48 * This file is part of the uIP TCP/IP stack.
49 *
50 * $Id: uip.h,v 1.24 2009/04/06 13:18:50 nvt-se Exp $
51 *
52 */
53
54#ifndef __UIP_H__
55#define __UIP_H__
56
57#include "uipopt.h"
58
59/**
60 * Representation of an IP address.
61 *
62 */
63#if UIP_CONF_IPV6
64typedef union uip_ip6addr_t {
65 u8_t u8[16]; /* Initialiser, must come first!!! */
66 u16_t u16[8];
67} uip_ip6addr_t;
68
69typedef uip_ip6addr_t uip_ipaddr_t;
70#else /* UIP_CONF_IPV6 */
71typedef union uip_ip4addr_t {
72 u8_t u8[4]; /* Initialiser, must come first!!! */
73 u16_t u16[2];
74#if 0
75 u32_t u32;
76#endif
77} uip_ip4addr_t;
78typedef uip_ip4addr_t uip_ipaddr_t;
79#endif /* UIP_CONF_IPV6 */
80
81
82/*---------------------------------------------------------------------------*/
83
84/** \brief 16 bit 802.15.4 address */
85struct uip_802154_shortaddr {
86 u8_t addr[2];
87};
88/** \brief 64 bit 802.15.4 address */
89struct uip_802154_longaddr {
90 u8_t addr[8];
91};
92
93/** \brief 802.11 address */
94struct uip_80211_addr {
95 u8_t addr[6];
96};
97
98/** \brief 802.3 address */
99struct uip_eth_addr {
100 u8_t addr[6];
101};
102
103#if UIP_CONF_LL_802154
104/** \brief 802.15.4 address */
105typedef struct uip_802154_longaddr uip_lladdr_t;
106#define UIP_802154_SHORTADDR_LEN 2
107#define UIP_802154_LONGADDR_LEN 8
108#define UIP_LLADDR_LEN UIP_802154_LONGADDR_LEN
109#else /*UIP_CONF_LL_802154*/
110#if UIP_CONF_LL_80211
111/** \brief 802.11 address */
112typedef struct uip_80211_addr uip_lladdr_t;
113#define UIP_LLADDR_LEN 6
114#else /*UIP_CONF_LL_80211*/
115/** \brief Ethernet address */
116typedef struct uip_eth_addr uip_lladdr_t;
117#define UIP_LLADDR_LEN 6
118#endif /*UIP_CONF_LL_80211*/
119#endif /*UIP_CONF_LL_802154*/
120
121/*---------------------------------------------------------------------------*/
122/* First, the functions that should be called from the
123 * system. Initialization, the periodic timer, and incoming packets are
124 * handled by the following three functions.
125 */
126/**
127 * \defgroup uipconffunc uIP configuration functions
128 * @{
129 *
130 * The uIP configuration functions are used for setting run-time
131 * parameters in uIP such as IP addresses.
132 */
133
134/**
135 * Set the IP address of this host.
136 *
137 * The IP address is represented as a 4-byte array where the first
138 * octet of the IP address is put in the first member of the 4-byte
139 * array.
140 *
141 * Example:
142 \code
143
144 uip_ipaddr_t addr;
145
146 uip_ipaddr(&addr, 192,168,1,2);
147 uip_sethostaddr(&addr);
148
149 \endcode
150 * \param addr A pointer to an IP address of type uip_ipaddr_t;
151 *
152 * \sa uip_ipaddr()
153 *
154 * \hideinitializer
155 */
156#define uip_sethostaddr(addr) uip_ipaddr_copy(&uip_hostaddr, (addr))
157
158/**
159 * Get the IP address of this host.
160 *
161 * The IP address is represented as a 4-byte array where the first
162 * octet of the IP address is put in the first member of the 4-byte
163 * array.
164 *
165 * Example:
166 \code
167 uip_ipaddr_t hostaddr;
168
169 uip_gethostaddr(&hostaddr);
170 \endcode
171 * \param addr A pointer to a uip_ipaddr_t variable that will be
172 * filled in with the currently configured IP address.
173 *
174 * \hideinitializer
175 */
176#define uip_gethostaddr(addr) uip_ipaddr_copy((addr), &uip_hostaddr)
177
178/**
179 * Set the default router's IP address.
180 *
181 * \param addr A pointer to a uip_ipaddr_t variable containing the IP
182 * address of the default router.
183 *
184 * \sa uip_ipaddr()
185 *
186 * \hideinitializer
187 */
188#define uip_setdraddr(addr) uip_ipaddr_copy(&uip_draddr, (addr))
189
190/**
191 * Set the netmask.
192 *
193 * \param addr A pointer to a uip_ipaddr_t variable containing the IP
194 * address of the netmask.
195 *
196 * \sa uip_ipaddr()
197 *
198 * \hideinitializer
199 */
200#define uip_setnetmask(addr) uip_ipaddr_copy(&uip_netmask, (addr))
201
202
203/**
204 * Get the default router's IP address.
205 *
206 * \param addr A pointer to a uip_ipaddr_t variable that will be
207 * filled in with the IP address of the default router.
208 *
209 * \hideinitializer
210 */
211#define uip_getdraddr(addr) uip_ipaddr_copy((addr), &uip_draddr)
212
213/**
214 * Get the netmask.
215 *
216 * \param addr A pointer to a uip_ipaddr_t variable that will be
217 * filled in with the value of the netmask.
218 *
219 * \hideinitializer
220 */
221#define uip_getnetmask(addr) uip_ipaddr_copy((addr), &uip_netmask)
222
223/** @} */
224
225/**
226 * \defgroup uipinit uIP initialization functions
227 * @{
228 *
229 * The uIP initialization functions are used for booting uIP.
230 */
231
232/**
233 * uIP initialization function.
234 *
235 * This function should be called at boot up to initialize the uIP
236 * TCP/IP stack.
237 */
238void uip_init(void);
239
240/**
241 * uIP initialization function.
242 *
243 * This function may be used at boot time to set the initial ip_id.
244 */
245void uip_setipid(u16_t id);
246
247/** @} */
248
249/**
250 * \defgroup uipdevfunc uIP device driver functions
251 * @{
252 *
253 * These functions are used by a network device driver for interacting
254 * with uIP.
255 */
256
257/**
258 * Process an incoming packet.
259 *
260 * This function should be called when the device driver has received
261 * a packet from the network. The packet from the device driver must
262 * be present in the uip_buf buffer, and the length of the packet
263 * should be placed in the uip_len variable.
264 *
265 * When the function returns, there may be an outbound packet placed
266 * in the uip_buf packet buffer. If so, the uip_len variable is set to
267 * the length of the packet. If no packet is to be sent out, the
268 * uip_len variable is set to 0.
269 *
270 * The usual way of calling the function is presented by the source
271 * code below.
272 \code
273 uip_len = devicedriver_poll();
274 if(uip_len > 0) {
275 uip_input();
276 if(uip_len > 0) {
277 devicedriver_send();
278 }
279 }
280 \endcode
281 *
282 * \note If you are writing a uIP device driver that needs ARP
283 * (Address Resolution Protocol), e.g., when running uIP over
284 * Ethernet, you will need to call the uIP ARP code before calling
285 * this function:
286 \code
287 #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
288 uip_len = ethernet_devicedrver_poll();
289 if(uip_len > 0) {
290 if(BUF->type == HTONS(UIP_ETHTYPE_IP)) {
291 uip_arp_ipin();
292 uip_input();
293 if(uip_len > 0) {
294 uip_arp_out();
295 ethernet_devicedriver_send();
296 }
297 } else if(BUF->type == HTONS(UIP_ETHTYPE_ARP)) {
298 uip_arp_arpin();
299 if(uip_len > 0) {
300 ethernet_devicedriver_send();
301 }
302 }
303 \endcode
304 *
305 * \hideinitializer
306 */
307#define uip_input() uip_process(UIP_DATA)
308
309
310/**
311 * Periodic processing for a connection identified by its number.
312 *
313 * This function does the necessary periodic processing (timers,
314 * polling) for a uIP TCP connection, and should be called when the
315 * periodic uIP timer goes off. It should be called for every
316 * connection, regardless of whether they are open of closed.
317 *
318 * When the function returns, it may have an outbound packet waiting
319 * for service in the uIP packet buffer, and if so the uip_len
320 * variable is set to a value larger than zero. The device driver
321 * should be called to send out the packet.
322 *
323 * The usual way of calling the function is through a for() loop like
324 * this:
325 \code
326 for(i = 0; i < UIP_CONNS; ++i) {
327 uip_periodic(i);
328 if(uip_len > 0) {
329 devicedriver_send();
330 }
331 }
332 \endcode
333 *
334 * \note If you are writing a uIP device driver that needs ARP
335 * (Address Resolution Protocol), e.g., when running uIP over
336 * Ethernet, you will need to call the uip_arp_out() function before
337 * calling the device driver:
338 \code
339 for(i = 0; i < UIP_CONNS; ++i) {
340 uip_periodic(i);
341 if(uip_len > 0) {
342 uip_arp_out();
343 ethernet_devicedriver_send();
344 }
345 }
346 \endcode
347 *
348 * \param conn The number of the connection which is to be periodically polled.
349 *
350 * \hideinitializer
351 */
352#if UIP_TCP
353#define uip_periodic(conn) do { uip_conn = &uip_conns[conn]; \
354 uip_process(UIP_TIMER); } while (0)
355
356/**
357 *
358 *
359 */
360#define uip_conn_active(conn) (uip_conns[conn].tcpstateflags != UIP_CLOSED)
361
362/**
363 * Perform periodic processing for a connection identified by a pointer
364 * to its structure.
365 *
366 * Same as uip_periodic() but takes a pointer to the actual uip_conn
367 * struct instead of an integer as its argument. This function can be
368 * used to force periodic processing of a specific connection.
369 *
370 * \param conn A pointer to the uip_conn struct for the connection to
371 * be processed.
372 *
373 * \hideinitializer
374 */
375#define uip_periodic_conn(conn) do { uip_conn = conn; \
376 uip_process(UIP_TIMER); } while (0)
377
378/**
379 * Request that a particular connection should be polled.
380 *
381 * Similar to uip_periodic_conn() but does not perform any timer
382 * processing. The application is polled for new data.
383 *
384 * \param conn A pointer to the uip_conn struct for the connection to
385 * be processed.
386 *
387 * \hideinitializer
388 */
389#define uip_poll_conn(conn) do { uip_conn = conn; \
390 uip_process(UIP_POLL_REQUEST); } while (0)
391
392#endif /* UIP_TCP */
393
394#if UIP_UDP
395/**
396 * Periodic processing for a UDP connection identified by its number.
397 *
398 * This function is essentially the same as uip_periodic(), but for
399 * UDP connections. It is called in a similar fashion as the
400 * uip_periodic() function:
401 \code
402 for(i = 0; i < UIP_UDP_CONNS; i++) {
403 uip_udp_periodic(i);
404 if(uip_len > 0) {
405 devicedriver_send();
406 }
407 }
408 \endcode
409 *
410 * \note As for the uip_periodic() function, special care has to be
411 * taken when using uIP together with ARP and Ethernet:
412 \code
413 for(i = 0; i < UIP_UDP_CONNS; i++) {
414 uip_udp_periodic(i);
415 if(uip_len > 0) {
416 uip_arp_out();
417 ethernet_devicedriver_send();
418 }
419 }
420 \endcode
421 *
422 * \param conn The number of the UDP connection to be processed.
423 *
424 * \hideinitializer
425 */
426#define uip_udp_periodic(conn) do { uip_udp_conn = &uip_udp_conns[conn]; \
427 uip_process(UIP_UDP_TIMER); } while(0)
428
429/**
430 * Periodic processing for a UDP connection identified by a pointer to
431 * its structure.
432 *
433 * Same as uip_udp_periodic() but takes a pointer to the actual
434 * uip_conn struct instead of an integer as its argument. This
435 * function can be used to force periodic processing of a specific
436 * connection.
437 *
438 * \param conn A pointer to the uip_udp_conn struct for the connection
439 * to be processed.
440 *
441 * \hideinitializer
442 */
443#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \
444 uip_process(UIP_UDP_TIMER); } while(0)
445#endif /* UIP_UDP */
446
447/** \brief Abandon the reassembly of the current packet */
448void uip_reass_over(void);
449
450/**
451 * The uIP packet buffer.
452 *
453 * The uip_buf array is used to hold incoming and outgoing
454 * packets. The device driver should place incoming data into this
455 * buffer. When sending data, the device driver should read the link
456 * level headers and the TCP/IP headers from this buffer. The size of
457 * the link level headers is configured by the UIP_LLH_LEN define.
458 *
459 * \note The application data need not be placed in this buffer, so
460 * the device driver must read it from the place pointed to by the
461 * uip_appdata pointer as illustrated by the following example:
462 \code
463 void
464 devicedriver_send(void)
465 {
466 hwsend(&uip_buf[0], UIP_LLH_LEN);
467 if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) {
468 hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN);
469 } else {
470 hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN);
471 hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN);
472 }
473 }
474 \endcode
475*/
476extern u8_t uip_buf[UIP_BUFSIZE+2];
477
478
479
480/** @} */
481
482/*---------------------------------------------------------------------------*/
483/* Functions that are used by the uIP application program. Opening and
484 * closing connections, sending and receiving data, etc. is all
485 * handled by the functions below.
486 */
487/**
488 * \defgroup uipappfunc uIP application functions
489 * @{
490 *
491 * Functions used by an application running of top of uIP.
492 */
493
494/**
495 * Start listening to the specified port.
496 *
497 * \note Since this function expects the port number in network byte
498 * order, a conversion using HTONS() or htons() is necessary.
499 *
500 \code
501 uip_listen(HTONS(80));
502 \endcode
503 *
504 * \param port A 16-bit port number in network byte order.
505 */
506void uip_listen(u16_t port);
507
508/**
509 * Stop listening to the specified port.
510 *
511 * \note Since this function expects the port number in network byte
512 * order, a conversion using HTONS() or htons() is necessary.
513 *
514 \code
515 uip_unlisten(HTONS(80));
516 \endcode
517 *
518 * \param port A 16-bit port number in network byte order.
519 */
520void uip_unlisten(u16_t port);
521
522/**
523 * Connect to a remote host using TCP.
524 *
525 * This function is used to start a new connection to the specified
526 * port on the specified host. It allocates a new connection identifier,
527 * sets the connection to the SYN_SENT state and sets the
528 * retransmission timer to 0. This will cause a TCP SYN segment to be
529 * sent out the next time this connection is periodically processed,
530 * which usually is done within 0.5 seconds after the call to
531 * uip_connect().
532 *
533 * \note This function is available only if support for active open
534 * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h.
535 *
536 * \note Since this function requires the port number to be in network
537 * byte order, a conversion using HTONS() or htons() is necessary.
538 *
539 \code
540 uip_ipaddr_t ipaddr;
541
542 uip_ipaddr(&ipaddr, 192,168,1,2);
543 uip_connect(&ipaddr, HTONS(80));
544 \endcode
545 *
546 * \param ripaddr The IP address of the remote host.
547 *
548 * \param port A 16-bit port number in network byte order.
549 *
550 * \return A pointer to the uIP connection identifier for the new connection,
551 * or NULL if no connection could be allocated.
552 *
553 */
554struct uip_conn *uip_connect(uip_ipaddr_t *ripaddr, u16_t port);
555
556
557
558/**
559 * \internal
560 *
561 * Check if a connection has outstanding (i.e., unacknowledged) data.
562 *
563 * \param conn A pointer to the uip_conn structure for the connection.
564 *
565 * \hideinitializer
566 */
567#define uip_outstanding(conn) ((conn)->len)
568
569/**
570 * Send data on the current connection.
571 *
572 * This function is used to send out a single segment of TCP
573 * data. Only applications that have been invoked by uIP for event
574 * processing can send data.
575 *
576 * The amount of data that actually is sent out after a call to this
577 * function is determined by the maximum amount of data TCP allows. uIP
578 * will automatically crop the data so that only the appropriate
579 * amount of data is sent. The function uip_mss() can be used to query
580 * uIP for the amount of data that actually will be sent.
581 *
582 * \note This function does not guarantee that the sent data will
583 * arrive at the destination. If the data is lost in the network, the
584 * application will be invoked with the uip_rexmit() event being
585 * set. The application will then have to resend the data using this
586 * function.
587 *
588 * \param data A pointer to the data which is to be sent.
589 *
590 * \param len The maximum amount of data bytes to be sent.
591 *
592 * \hideinitializer
593 */
594void uip_send(const void *data, int len);
595
596/**
597 * The length of any incoming data that is currently available (if available)
598 * in the uip_appdata buffer.
599 *
600 * The test function uip_data() must first be used to check if there
601 * is any data available at all.
602 *
603 * \hideinitializer
604 */
605/*void uip_datalen(void);*/
606#define uip_datalen() uip_len
607
608/**
609 * The length of any out-of-band data (urgent data) that has arrived
610 * on the connection.
611 *
612 * \note The configuration parameter UIP_URGDATA must be set for this
613 * function to be enabled.
614 *
615 * \hideinitializer
616 */
617#define uip_urgdatalen() uip_urglen
618
619/**
620 * Close the current connection.
621 *
622 * This function will close the current connection in a nice way.
623 *
624 * \hideinitializer
625 */
626#define uip_close() (uip_flags = UIP_CLOSE)
627
628/**
629 * Abort the current connection.
630 *
631 * This function will abort (reset) the current connection, and is
632 * usually used when an error has occurred that prevents using the
633 * uip_close() function.
634 *
635 * \hideinitializer
636 */
637#define uip_abort() (uip_flags = UIP_ABORT)
638
639/**
640 * Tell the sending host to stop sending data.
641 *
642 * This function will close our receiver's window so that we stop
643 * receiving data for the current connection.
644 *
645 * \hideinitializer
646 */
647#define uip_stop() (uip_conn->tcpstateflags |= UIP_STOPPED)
648
649/**
650 * Find out if the current connection has been previously stopped with
651 * uip_stop().
652 *
653 * \hideinitializer
654 */
655#define uip_stopped(conn) ((conn)->tcpstateflags & UIP_STOPPED)
656
657/**
658 * Restart the current connection, if is has previously been stopped
659 * with uip_stop().
660 *
661 * This function will open the receiver's window again so that we
662 * start receiving data for the current connection.
663 *
664 * \hideinitializer
665 */
666#define uip_restart() do { uip_flags |= UIP_NEWDATA; \
667 uip_conn->tcpstateflags &= ~UIP_STOPPED; \
668 } while(0)
669
670
671/* uIP tests that can be made to determine in what state the current
672 connection is, and what the application function should do. */
673
674/**
675 * Is the current connection a UDP connection?
676 *
677 * This function checks whether the current connection is a UDP connection.
678 *
679 * \hideinitializer
680 *
681 */
682#define uip_udpconnection() (uip_conn == NULL)
683
684/**
685 * Is new incoming data available?
686 *
687 * Will reduce to non-zero if there is new data for the application
688 * present at the uip_appdata pointer. The size of the data is
689 * available through the uip_len variable.
690 *
691 * \hideinitializer
692 */
693#define uip_newdata() (uip_flags & UIP_NEWDATA)
694
695/**
696 * Has previously sent data been acknowledged?
697 *
698 * Will reduce to non-zero if the previously sent data has been
699 * acknowledged by the remote host. This means that the application
700 * can send new data.
701 *
702 * \hideinitializer
703 */
704#define uip_acked() (uip_flags & UIP_ACKDATA)
705
706/**
707 * Has the connection just been connected?
708 *
709 * Reduces to non-zero if the current connection has been connected to
710 * a remote host. This will happen both if the connection has been
711 * actively opened (with uip_connect()) or passively opened (with
712 * uip_listen()).
713 *
714 * \hideinitializer
715 */
716#define uip_connected() (uip_flags & UIP_CONNECTED)
717
718/**
719 * Has the connection been closed by the other end?
720 *
721 * Is non-zero if the connection has been closed by the remote
722 * host. The application may then do the necessary clean-ups.
723 *
724 * \hideinitializer
725 */
726#define uip_closed() (uip_flags & UIP_CLOSE)
727
728/**
729 * Has the connection been aborted by the other end?
730 *
731 * Non-zero if the current connection has been aborted (reset) by the
732 * remote host.
733 *
734 * \hideinitializer
735 */
736#define uip_aborted() (uip_flags & UIP_ABORT)
737
738/**
739 * Has the connection timed out?
740 *
741 * Non-zero if the current connection has been aborted due to too many
742 * retransmissions.
743 *
744 * \hideinitializer
745 */
746#define uip_timedout() (uip_flags & UIP_TIMEDOUT)
747
748/**
749 * Do we need to retransmit previously data?
750 *
751 * Reduces to non-zero if the previously sent data has been lost in
752 * the network, and the application should retransmit it. The
753 * application should send the exact same data as it did the last
754 * time, using the uip_send() function.
755 *
756 * \hideinitializer
757 */
758#define uip_rexmit() (uip_flags & UIP_REXMIT)
759
760/**
761 * Is the connection being polled by uIP?
762 *
763 * Is non-zero if the reason the application is invoked is that the
764 * current connection has been idle for a while and should be
765 * polled.
766 *
767 * The polling event can be used for sending data without having to
768 * wait for the remote host to send data.
769 *
770 * \hideinitializer
771 */
772#define uip_poll() (uip_flags & UIP_POLL)
773
774/**
775 * Get the initial maximum segment size (MSS) of the current
776 * connection.
777 *
778 * \hideinitializer
779 */
780#define uip_initialmss() (uip_conn->initialmss)
781
782/**
783 * Get the current maximum segment size that can be sent on the current
784 * connection.
785 *
786 * The current maximum segment size that can be sent on the
787 * connection is computed from the receiver's window and the MSS of
788 * the connection (which also is available by calling
789 * uip_initialmss()).
790 *
791 * \hideinitializer
792 */
793#define uip_mss() (uip_conn->mss)
794
795/**
796 * Set up a new UDP connection.
797 *
798 * This function sets up a new UDP connection. The function will
799 * automatically allocate an unused local port for the new
800 * connection. However, another port can be chosen by using the
801 * uip_udp_bind() call, after the uip_udp_new() function has been
802 * called.
803 *
804 * Example:
805 \code
806 uip_ipaddr_t addr;
807 struct uip_udp_conn *c;
808
809 uip_ipaddr(&addr, 192,168,2,1);
810 c = uip_udp_new(&addr, HTONS(12345));
811 if(c != NULL) {
812 uip_udp_bind(c, HTONS(12344));
813 }
814 \endcode
815 * \param ripaddr The IP address of the remote host.
816 *
817 * \param rport The remote port number in network byte order.
818 *
819 * \return The uip_udp_conn structure for the new connection or NULL
820 * if no connection could be allocated.
821 */
822struct uip_udp_conn *uip_udp_new(const uip_ipaddr_t *ripaddr, u16_t rport);
823
824/**
825 * Removed a UDP connection.
826 *
827 * \param conn A pointer to the uip_udp_conn structure for the connection.
828 *
829 * \hideinitializer
830 */
831#define uip_udp_remove(conn) (conn)->lport = 0
832
833/**
834 * Bind a UDP connection to a local port.
835 *
836 * \param conn A pointer to the uip_udp_conn structure for the
837 * connection.
838 *
839 * \param port The local port number, in network byte order.
840 *
841 * \hideinitializer
842 */
843#define uip_udp_bind(conn, port) (conn)->lport = port
844
845/**
846 * Send a UDP datagram of length len on the current connection.
847 *
848 * This function can only be called in response to a UDP event (poll
849 * or newdata). The data must be present in the uip_buf buffer, at the
850 * place pointed to by the uip_appdata pointer.
851 *
852 * \param len The length of the data in the uip_buf buffer.
853 *
854 * \hideinitializer
855 */
856#define uip_udp_send(len) uip_send((char *)uip_appdata, len)
857
858/** @} */
859
860/* uIP convenience and converting functions. */
861
862/**
863 * \defgroup uipconvfunc uIP conversion functions
864 * @{
865 *
866 * These functions can be used for converting between different data
867 * formats used by uIP.
868 */
869
870/**
871 * Convert an IP address to four bytes separated by commas.
872 *
873 * Example:
874 \code
875 uip_ipaddr_t ipaddr;
876 printf("ipaddr=%d.%d.%d.%d\n", uip_ipaddr_to_quad(&ipaddr));
877 \endcode
878 *
879 * \param a A pointer to a uip_ipaddr_t.
880 * \hideinitializer
881 */
882#define uip_ipaddr_to_quad(a) (a)->u8[0],(a)->u8[1],(a)->u8[2],(a)->u8[3]
883
884/**
885 * Construct an IP address from four bytes.
886 *
887 * This function constructs an IP address of the type that uIP handles
888 * internally from four bytes. The function is handy for specifying IP
889 * addresses to use with e.g. the uip_connect() function.
890 *
891 * Example:
892 \code
893 uip_ipaddr_t ipaddr;
894 struct uip_conn *c;
895
896 uip_ipaddr(&ipaddr, 192,168,1,2);
897 c = uip_connect(&ipaddr, HTONS(80));
898 \endcode
899 *
900 * \param addr A pointer to a uip_ipaddr_t variable that will be
901 * filled in with the IP address.
902 *
903 * \param addr0 The first octet of the IP address.
904 * \param addr1 The second octet of the IP address.
905 * \param addr2 The third octet of the IP address.
906 * \param addr3 The forth octet of the IP address.
907 *
908 * \hideinitializer
909 */
910#define uip_ipaddr(addr, addr0,addr1,addr2,addr3) do { \
911 (addr)->u8[0] = addr0; \
912 (addr)->u8[1] = addr1; \
913 (addr)->u8[2] = addr2; \
914 (addr)->u8[3] = addr3; \
915 } while(0)
916
917/**
918 * Construct an IPv6 address from eight 16-bit words.
919 *
920 * This function constructs an IPv6 address.
921 *
922 * \hideinitializer
923 */
924#define uip_ip6addr(addr, addr0,addr1,addr2,addr3,addr4,addr5,addr6,addr7) do { \
925 (addr)->u16[0] = HTONS(addr0); \
926 (addr)->u16[1] = HTONS(addr1); \
927 (addr)->u16[2] = HTONS(addr2); \
928 (addr)->u16[3] = HTONS(addr3); \
929 (addr)->u16[4] = HTONS(addr4); \
930 (addr)->u16[5] = HTONS(addr5); \
931 (addr)->u16[6] = HTONS(addr6); \
932 (addr)->u16[7] = HTONS(addr7); \
933 } while(0)
934
935/**
936 * Construct an IPv6 address from sixteen 8-bit words.
937 *
938 * This function constructs an IPv6 address.
939 *
940 * \hideinitializer
941 */
942#define uip_ip6addr_u8(addr, addr0,addr1,addr2,addr3,addr4,addr5,addr6,addr7,addr8,addr9,addr10,addr11,addr12,addr13,addr14,addr15) do { \
943 (addr)->u8[0] = addr0; \
944 (addr)->u8[1] = addr1; \
945 (addr)->u8[2] = addr2; \
946 (addr)->u8[3] = addr3; \
947 (addr)->u8[4] = addr4; \
948 (addr)->u8[5] = addr5; \
949 (addr)->u8[6] = addr6; \
950 (addr)->u8[7] = addr7; \
951 (addr)->u8[8] = addr8; \
952 (addr)->u8[9] = addr9; \
953 (addr)->u8[10] = addr10; \
954 (addr)->u8[11] = addr11; \
955 (addr)->u8[12] = addr12; \
956 (addr)->u8[13] = addr13; \
957 (addr)->u8[14] = addr14; \
958 (addr)->u8[15] = addr15; \
959 } while(0)
960
961
962/**
963 * Copy an IP address to another IP address.
964 *
965 * Copies an IP address from one place to another.
966 *
967 * Example:
968 \code
969 uip_ipaddr_t ipaddr1, ipaddr2;
970
971 uip_ipaddr(&ipaddr1, 192,16,1,2);
972 uip_ipaddr_copy(&ipaddr2, &ipaddr1);
973 \endcode
974 *
975 * \param dest The destination for the copy.
976 * \param src The source from where to copy.
977 *
978 * \hideinitializer
979 */
980#ifndef uip_ipaddr_copy
981#define uip_ipaddr_copy(dest, src) (*(dest) = *(src))
982#endif
983
984/**
985 * Compare two IP addresses
986 *
987 * Compares two IP addresses.
988 *
989 * Example:
990 \code
991 uip_ipaddr_t ipaddr1, ipaddr2;
992
993 uip_ipaddr(&ipaddr1, 192,16,1,2);
994 if(uip_ipaddr_cmp(&ipaddr2, &ipaddr1)) {
995 printf("They are the same");
996 }
997 \endcode
998 *
999 * \param addr1 The first IP address.
1000 * \param addr2 The second IP address.
1001 *
1002 * \hideinitializer
1003 */
1004#if !UIP_CONF_IPV6
1005#define uip_ipaddr_cmp(addr1, addr2) ((addr1)->u16[0] == (addr2)->u16[0] && \
1006 (addr1)->u16[1] == (addr2)->u16[1])
1007#else /* !UIP_CONF_IPV6 */
1008#define uip_ipaddr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip6addr_t)) == 0)
1009#endif /* !UIP_CONF_IPV6 */
1010
1011/**
1012 * Compare two IP addresses with netmasks
1013 *
1014 * Compares two IP addresses with netmasks. The masks are used to mask
1015 * out the bits that are to be compared.
1016 *
1017 * Example:
1018 \code
1019 uip_ipaddr_t ipaddr1, ipaddr2, mask;
1020
1021 uip_ipaddr(&mask, 255,255,255,0);
1022 uip_ipaddr(&ipaddr1, 192,16,1,2);
1023 uip_ipaddr(&ipaddr2, 192,16,1,3);
1024 if(uip_ipaddr_maskcmp(&ipaddr1, &ipaddr2, &mask)) {
1025 printf("They are the same");
1026 }
1027 \endcode
1028 *
1029 * \param addr1 The first IP address.
1030 * \param addr2 The second IP address.
1031 * \param mask The netmask.
1032 *
1033 * \hideinitializer
1034 */
1035#if !UIP_CONF_IPV6
1036#define uip_ipaddr_maskcmp(addr1, addr2, mask) \
1037 (((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \
1038 (((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \
1039 ((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \
1040 (((u16_t *)addr2)[1] & ((u16_t *)mask)[1])))
1041#else
1042#define uip_ipaddr_prefixcmp(addr1, addr2, length) (memcmp(addr1, addr2, length>>3) == 0)
1043#endif
1044
1045
1046/**
1047 * Check if an address is a broadcast address for a network.
1048 *
1049 * Checks if an address is the broadcast address for a network. The
1050 * network is defined by an IP address that is on the network and the
1051 * network's netmask.
1052 *
1053 * \param addr The IP address.
1054 * \param netaddr The network's IP address.
1055 * \param netmask The network's netmask.
1056 *
1057 * \hideinitializer
1058 */
1059/*#define uip_ipaddr_isbroadcast(addr, netaddr, netmask)
1060 ((uip_ipaddr_t *)(addr)).u16 & ((uip_ipaddr_t *)(addr)).u16*/
1061
1062
1063
1064/**
1065 * Mask out the network part of an IP address.
1066 *
1067 * Masks out the network part of an IP address, given the address and
1068 * the netmask.
1069 *
1070 * Example:
1071 \code
1072 uip_ipaddr_t ipaddr1, ipaddr2, netmask;
1073
1074 uip_ipaddr(&ipaddr1, 192,16,1,2);
1075 uip_ipaddr(&netmask, 255,255,255,0);
1076 uip_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask);
1077 \endcode
1078 *
1079 * In the example above, the variable "ipaddr2" will contain the IP
1080 * address 192.168.1.0.
1081 *
1082 * \param dest Where the result is to be placed.
1083 * \param src The IP address.
1084 * \param mask The netmask.
1085 *
1086 * \hideinitializer
1087 */
1088#define uip_ipaddr_mask(dest, src, mask) do { \
1089 ((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \
1090 ((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \
1091 } while(0)
1092
1093/**
1094 * Pick the first octet of an IP address.
1095 *
1096 * Picks out the first octet of an IP address.
1097 *
1098 * Example:
1099 \code
1100 uip_ipaddr_t ipaddr;
1101 u8_t octet;
1102
1103 uip_ipaddr(&ipaddr, 1,2,3,4);
1104 octet = uip_ipaddr1(&ipaddr);
1105 \endcode
1106 *
1107 * In the example above, the variable "octet" will contain the value 1.
1108 *
1109 * \hideinitializer
1110 */
1111#define uip_ipaddr1(addr) ((addr)->u8[0])
1112
1113/**
1114 * Pick the second octet of an IP address.
1115 *
1116 * Picks out the second octet of an IP address.
1117 *
1118 * Example:
1119 \code
1120 uip_ipaddr_t ipaddr;
1121 u8_t octet;
1122
1123 uip_ipaddr(&ipaddr, 1,2,3,4);
1124 octet = uip_ipaddr2(&ipaddr);
1125 \endcode
1126 *
1127 * In the example above, the variable "octet" will contain the value 2.
1128 *
1129 * \hideinitializer
1130 */
1131#define uip_ipaddr2(addr) ((addr)->u8[1])
1132
1133/**
1134 * Pick the third octet of an IP address.
1135 *
1136 * Picks out the third octet of an IP address.
1137 *
1138 * Example:
1139 \code
1140 uip_ipaddr_t ipaddr;
1141 u8_t octet;
1142
1143 uip_ipaddr(&ipaddr, 1,2,3,4);
1144 octet = uip_ipaddr3(&ipaddr);
1145 \endcode
1146 *
1147 * In the example above, the variable "octet" will contain the value 3.
1148 *
1149 * \hideinitializer
1150 */
1151#define uip_ipaddr3(addr) ((addr)->u8[2])
1152
1153/**
1154 * Pick the fourth octet of an IP address.
1155 *
1156 * Picks out the fourth octet of an IP address.
1157 *
1158 * Example:
1159 \code
1160 uip_ipaddr_t ipaddr;
1161 u8_t octet;
1162
1163 uip_ipaddr(&ipaddr, 1,2,3,4);
1164 octet = uip_ipaddr4(&ipaddr);
1165 \endcode
1166 *
1167 * In the example above, the variable "octet" will contain the value 4.
1168 *
1169 * \hideinitializer
1170 */
1171#define uip_ipaddr4(addr) ((addr)->u8[3])
1172
1173/**
1174 * Convert 16-bit quantity from host byte order to network byte order.
1175 *
1176 * This macro is primarily used for converting constants from host
1177 * byte order to network byte order. For converting variables to
1178 * network byte order, use the htons() function instead.
1179 *
1180 * \hideinitializer
1181 */
1182#ifndef HTONS
1183# if UIP_BYTE_ORDER == UIP_BIG_ENDIAN
1184# define HTONS(n) (n)
1185# define HTONL(n) (n)
1186# else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
1187# define HTONS(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8))
1188# define HTONL(n) (((u32_t)HTONS(n) << 16) | HTONS((u32_t)(n) >> 16))
1189# endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */
1190#else
1191#error "HTONS already defined!"
1192#endif /* HTONS */
1193
1194/**
1195 * Convert 16-bit quantity from host byte order to network byte order.
1196 *
1197 * This function is primarily used for converting variables from host
1198 * byte order to network byte order. For converting constants to
1199 * network byte order, use the HTONS() macro instead.
1200 */
1201#ifndef htons
1202u16_t htons(u16_t val);
1203#endif /* htons */
1204#ifndef ntohs
1205#define ntohs htons
1206#endif
1207
1208#ifndef htonl
1209u32_t htonl(u32_t val);
1210#endif /* htonl */
1211#ifndef ntohl
1212#define ntohl htonl
1213#endif
1214
1215/** @} */
1216
1217/**
1218 * Pointer to the application data in the packet buffer.
1219 *
1220 * This pointer points to the application data when the application is
1221 * called. If the application wishes to send data, the application may
1222 * use this space to write the data into before calling uip_send().
1223 */
1224extern void *uip_appdata;
1225
1226#if UIP_URGDATA > 0
1227/* u8_t *uip_urgdata:
1228 *
1229 * This pointer points to any urgent data that has been received. Only
1230 * present if compiled with support for urgent data (UIP_URGDATA).
1231 */
1232extern void *uip_urgdata;
1233#endif /* UIP_URGDATA > 0 */
1234
1235
1236/**
1237 * \defgroup uipdrivervars Variables used in uIP device drivers
1238 * @{
1239 *
1240 * uIP has a few global variables that are used in device drivers for
1241 * uIP.
1242 */
1243
1244/**
1245 * The length of the packet in the uip_buf buffer.
1246 *
1247 * The global variable uip_len holds the length of the packet in the
1248 * uip_buf buffer.
1249 *
1250 * When the network device driver calls the uIP input function,
1251 * uip_len should be set to the length of the packet in the uip_buf
1252 * buffer.
1253 *
1254 * When sending packets, the device driver should use the contents of
1255 * the uip_len variable to determine the length of the outgoing
1256 * packet.
1257 *
1258 */
1259extern u16_t uip_len;
1260
1261/**
1262 * The length of the extension headers
1263 */
1264extern u8_t uip_ext_len;
1265/** @} */
1266
1267#if UIP_URGDATA > 0
1268extern u16_t uip_urglen, uip_surglen;
1269#endif /* UIP_URGDATA > 0 */
1270
1271
1272/**
1273 * Representation of a uIP TCP connection.
1274 *
1275 * The uip_conn structure is used for identifying a connection. All
1276 * but one field in the structure are to be considered read-only by an
1277 * application. The only exception is the appstate field whose purpose
1278 * is to let the application store application-specific state (e.g.,
1279 * file pointers) for the connection. The type of this field is
1280 * configured in the "uipopt.h" header file.
1281 */
1282struct uip_conn {
1283 uip_ipaddr_t ripaddr; /**< The IP address of the remote host. */
1284
1285 u16_t lport; /**< The local TCP port, in network byte order. */
1286 u16_t rport; /**< The local remote TCP port, in network byte
1287 order. */
1288
1289 u8_t rcv_nxt[4]; /**< The sequence number that we expect to
1290 receive next. */
1291 u8_t snd_nxt[4]; /**< The sequence number that was last sent by
1292 us. */
1293 u16_t len; /**< Length of the data that was previously sent. */
1294 u16_t mss; /**< Current maximum segment size for the
1295 connection. */
1296 u16_t initialmss; /**< Initial maximum segment size for the
1297 connection. */
1298 u8_t sa; /**< Retransmission time-out calculation state
1299 variable. */
1300 u8_t sv; /**< Retransmission time-out calculation state
1301 variable. */
1302 u8_t rto; /**< Retransmission time-out. */
1303 u8_t tcpstateflags; /**< TCP state and flags. */
1304 u8_t timer; /**< The retransmission timer. */
1305 u8_t nrtx; /**< The number of retransmissions for the last
1306 segment sent. */
1307
1308 /** The application state. */
1309 uip_tcp_appstate_t appstate;
1310};
1311
1312
1313/**
1314 * Pointer to the current TCP connection.
1315 *
1316 * The uip_conn pointer can be used to access the current TCP
1317 * connection.
1318 */
1319
1320extern struct uip_conn *uip_conn;
1321#if UIP_TCP
1322/* The array containing all uIP connections. */
1323extern struct uip_conn uip_conns[UIP_CONNS];
1324#endif
1325
1326/**
1327 * \addtogroup uiparch
1328 * @{
1329 */
1330
1331/**
1332 * 4-byte array used for the 32-bit sequence number calculations.
1333 */
1334extern u8_t uip_acc32[4];
1335/** @} */
1336
1337/**
1338 * Representation of a uIP UDP connection.
1339 */
1340struct uip_udp_conn {
1341 uip_ipaddr_t ripaddr; /**< The IP address of the remote peer. */
1342 u16_t lport; /**< The local port number in network byte order. */
1343 u16_t rport; /**< The remote port number in network byte order. */
1344 u8_t ttl; /**< Default time-to-live. */
1345
1346 /** The application state. */
1347 uip_udp_appstate_t appstate;
1348};
1349
1350/**
1351 * The current UDP connection.
1352 */
1353extern struct uip_udp_conn *uip_udp_conn;
1354extern struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
1355
1356struct uip_router {
1357 int (*activate)(void);
1358 int (*deactivate)(void);
1359 uip_ipaddr_t *(*lookup)(uip_ipaddr_t *destipaddr, uip_ipaddr_t *nexthop);
1360};
1361
1362#if UIP_CONF_ROUTER
1363extern const struct uip_router *uip_router;
1364
1365/**
1366 * uIP routing driver registration function.
1367 */
1368void uip_router_register(const struct uip_router *router);
1369#endif /*UIP_CONF_ROUTER*/
1370
1371#if UIP_CONF_ICMP6
1372struct uip_icmp6_conn {
1373 uip_icmp6_appstate_t appstate;
1374};
1375extern struct uip_icmp6_conn uip_icmp6_conns;
1376#endif /*UIP_CONF_ICMP6*/
1377
1378/**
1379 * The uIP TCP/IP statistics.
1380 *
1381 * This is the variable in which the uIP TCP/IP statistics are gathered.
1382 */
1383#if UIP_STATISTICS == 1
1384extern struct uip_stats uip_stat;
1385#define UIP_STAT(s) s
1386#else
1387#define UIP_STAT(s)
1388#endif /* UIP_STATISTICS == 1 */
1389
1390/**
1391 * The structure holding the TCP/IP statistics that are gathered if
1392 * UIP_STATISTICS is set to 1.
1393 *
1394 */
1395struct uip_stats {
1396 struct {
1397 uip_stats_t recv; /**< Number of received packets at the IP
1398 layer. */
1399 uip_stats_t sent; /**< Number of sent packets at the IP
1400 layer. */
1401 uip_stats_t forwarded;/**< Number of forwarded packets at the IP
1402 layer. */
1403 uip_stats_t drop; /**< Number of dropped packets at the IP
1404 layer. */
1405 uip_stats_t vhlerr; /**< Number of packets dropped due to wrong
1406 IP version or header length. */
1407 uip_stats_t hblenerr; /**< Number of packets dropped due to wrong
1408 IP length, high byte. */
1409 uip_stats_t lblenerr; /**< Number of packets dropped due to wrong
1410 IP length, low byte. */
1411 uip_stats_t fragerr; /**< Number of packets dropped since they
1412 were IP fragments. */
1413 uip_stats_t chkerr; /**< Number of packets dropped due to IP
1414 checksum errors. */
1415 uip_stats_t protoerr; /**< Number of packets dropped since they
1416 were neither ICMP, UDP nor TCP. */
1417 } ip; /**< IP statistics. */
1418 struct {
1419 uip_stats_t recv; /**< Number of received ICMP packets. */
1420 uip_stats_t sent; /**< Number of sent ICMP packets. */
1421 uip_stats_t drop; /**< Number of dropped ICMP packets. */
1422 uip_stats_t typeerr; /**< Number of ICMP packets with a wrong
1423 type. */
1424 uip_stats_t chkerr; /**< Number of ICMP packets with a bad
1425 checksum. */
1426 } icmp; /**< ICMP statistics. */
1427#if UIP_TCP
1428 struct {
1429 uip_stats_t recv; /**< Number of received TCP segments. */
1430 uip_stats_t sent; /**< Number of sent TCP segments. */
1431 uip_stats_t drop; /**< Number of dropped TCP segments. */
1432 uip_stats_t chkerr; /**< Number of TCP segments with a bad
1433 checksum. */
1434 uip_stats_t ackerr; /**< Number of TCP segments with a bad ACK
1435 number. */
1436 uip_stats_t rst; /**< Number of received TCP RST (reset) segments. */
1437 uip_stats_t rexmit; /**< Number of retransmitted TCP segments. */
1438 uip_stats_t syndrop; /**< Number of dropped SYNs due to too few
1439 connections was available. */
1440 uip_stats_t synrst; /**< Number of SYNs for closed ports,
1441 triggering a RST. */
1442 } tcp; /**< TCP statistics. */
1443#endif
1444#if UIP_UDP
1445 struct {
1446 uip_stats_t drop; /**< Number of dropped UDP segments. */
1447 uip_stats_t recv; /**< Number of received UDP segments. */
1448 uip_stats_t sent; /**< Number of sent UDP segments. */
1449 uip_stats_t chkerr; /**< Number of UDP segments with a bad
1450 checksum. */
1451 } udp; /**< UDP statistics. */
1452#endif /* UIP_UDP */
1453#if UIP_CONF_IPV6
1454 struct {
1455 uip_stats_t drop; /**< Number of dropped ND6 packets. */
1456 uip_stats_t recv; /**< Number of received ND6 packets */
1457 uip_stats_t sent; /**< Number of sent ND6 packets */
1458 } nd6;
1459#endif /*UIP_CONF_IPV6*/
1460};
1461
1462
1463/*---------------------------------------------------------------------------*/
1464/* All the stuff below this point is internal to uIP and should not be
1465 * used directly by an application or by a device driver.
1466 */
1467/*---------------------------------------------------------------------------*/
1468
1469
1470
1471/* u8_t uip_flags:
1472 *
1473 * When the application is called, uip_flags will contain the flags
1474 * that are defined in this file. Please read below for more
1475 * information.
1476 */
1477extern u8_t uip_flags;
1478
1479/* The following flags may be set in the global variable uip_flags
1480 before calling the application callback. The UIP_ACKDATA,
1481 UIP_NEWDATA, and UIP_CLOSE flags may both be set at the same time,
1482 whereas the others are mutually exclusive. Note that these flags
1483 should *NOT* be accessed directly, but only through the uIP
1484 functions/macros. */
1485
1486#define UIP_ACKDATA 1 /* Signifies that the outstanding data was
1487 acked and the application should send
1488 out new data instead of retransmitting
1489 the last data. */
1490#define UIP_NEWDATA 2 /* Flags the fact that the peer has sent
1491 us new data. */
1492#define UIP_REXMIT 4 /* Tells the application to retransmit the
1493 data that was last sent. */
1494#define UIP_POLL 8 /* Used for polling the application, to
1495 check if the application has data that
1496 it wants to send. */
1497#define UIP_CLOSE 16 /* The remote host has closed the
1498 connection, thus the connection has
1499 gone away. Or the application signals
1500 that it wants to close the
1501 connection. */
1502#define UIP_ABORT 32 /* The remote host has aborted the
1503 connection, thus the connection has
1504 gone away. Or the application signals
1505 that it wants to abort the
1506 connection. */
1507#define UIP_CONNECTED 64 /* We have got a connection from a remote
1508 host and have set up a new connection
1509 for it, or an active connection has
1510 been successfully established. */
1511
1512#define UIP_TIMEDOUT 128 /* The connection has been aborted due to
1513 too many retransmissions. */
1514
1515
1516/**
1517 * \brief process the options within a hop by hop or destination option header
1518 * \retval 0: nothing to send,
1519 * \retval 1: drop pkt
1520 * \retval 2: ICMP error message to send
1521*/
1522/*static u8_t
1523uip_ext_hdr_options_process(); */
1524
1525/* uip_process(flag):
1526 *
1527 * The actual uIP function which does all the work.
1528 */
1529void uip_process(u8_t flag);
1530
1531 /* The following flags are passed as an argument to the uip_process()
1532 function. They are used to distinguish between the two cases where
1533 uip_process() is called. It can be called either because we have
1534 incoming data that should be processed, or because the periodic
1535 timer has fired. These values are never used directly, but only in
1536 the macros defined in this file. */
1537
1538#define UIP_DATA 1 /* Tells uIP that there is incoming
1539 data in the uip_buf buffer. The
1540 length of the data is stored in the
1541 global variable uip_len. */
1542#define UIP_TIMER 2 /* Tells uIP that the periodic timer
1543 has fired. */
1544#define UIP_POLL_REQUEST 3 /* Tells uIP that a connection should
1545 be polled. */
1546#define UIP_UDP_SEND_CONN 4 /* Tells uIP that a UDP datagram
1547 should be constructed in the
1548 uip_buf buffer. */
1549#if UIP_UDP
1550#define UIP_UDP_TIMER 5
1551#endif /* UIP_UDP */
1552
1553/* The TCP states used in the uip_conn->tcpstateflags. */
1554#define UIP_CLOSED 0
1555#define UIP_SYN_RCVD 1
1556#define UIP_SYN_SENT 2
1557#define UIP_ESTABLISHED 3
1558#define UIP_FIN_WAIT_1 4
1559#define UIP_FIN_WAIT_2 5
1560#define UIP_CLOSING 6
1561#define UIP_TIME_WAIT 7
1562#define UIP_LAST_ACK 8
1563#define UIP_TS_MASK 15
1564
1565#define UIP_STOPPED 16
1566
1567/* The TCP and IP headers. */
1568struct uip_tcpip_hdr {
1569#if UIP_CONF_IPV6
1570 /* IPv6 header. */
1571 u8_t vtc,
1572 tcflow;
1573 u16_t flow;
1574 u8_t len[2];
1575 u8_t proto, ttl;
1576 uip_ip6addr_t srcipaddr, destipaddr;
1577#else /* UIP_CONF_IPV6 */
1578 /* IPv4 header. */
1579 u8_t vhl,
1580 tos,
1581 len[2],
1582 ipid[2],
1583 ipoffset[2],
1584 ttl,
1585 proto;
1586 u16_t ipchksum;
1587 uip_ipaddr_t srcipaddr, destipaddr;
1588#endif /* UIP_CONF_IPV6 */
1589
1590 /* TCP header. */
1591 u16_t srcport,
1592 destport;
1593 u8_t seqno[4],
1594 ackno[4],
1595 tcpoffset,
1596 flags,
1597 wnd[2];
1598 u16_t tcpchksum;
1599 u8_t urgp[2];
1600 u8_t optdata[4];
1601};
1602
1603/* The ICMP and IP headers. */
1604struct uip_icmpip_hdr {
1605#if UIP_CONF_IPV6
1606 /* IPv6 header. */
1607 u8_t vtc,
1608 tcf;
1609 u16_t flow;
1610 u8_t len[2];
1611 u8_t proto, ttl;
1612 uip_ip6addr_t srcipaddr, destipaddr;
1613#else /* UIP_CONF_IPV6 */
1614 /* IPv4 header. */
1615 u8_t vhl,
1616 tos,
1617 len[2],
1618 ipid[2],
1619 ipoffset[2],
1620 ttl,
1621 proto;
1622 u16_t ipchksum;
1623 uip_ipaddr_t srcipaddr, destipaddr;
1624#endif /* UIP_CONF_IPV6 */
1625
1626 /* ICMP header. */
1627 u8_t type, icode;
1628 u16_t icmpchksum;
1629#if !UIP_CONF_IPV6
1630 u16_t id, seqno;
1631 u8_t payload[1];
1632#endif /* !UIP_CONF_IPV6 */
1633};
1634
1635
1636/* The UDP and IP headers. */
1637struct uip_udpip_hdr {
1638#if UIP_CONF_IPV6
1639 /* IPv6 header. */
1640 u8_t vtc,
1641 tcf;
1642 u16_t flow;
1643 u8_t len[2];
1644 u8_t proto, ttl;
1645 uip_ip6addr_t srcipaddr, destipaddr;
1646#else /* UIP_CONF_IPV6 */
1647 /* IP header. */
1648 u8_t vhl,
1649 tos,
1650 len[2],
1651 ipid[2],
1652 ipoffset[2],
1653 ttl,
1654 proto;
1655 u16_t ipchksum;
1656 uip_ipaddr_t srcipaddr, destipaddr;
1657#endif /* UIP_CONF_IPV6 */
1658
1659 /* UDP header. */
1660 u16_t srcport,
1661 destport;
1662 u16_t udplen;
1663 u16_t udpchksum;
1664};
1665
1666/*
1667 * In IPv6 the length of the L3 headers before the transport header is
1668 * not fixed, due to the possibility to include extension option headers
1669 * after the IP header. hence we split here L3 and L4 headers
1670 */
1671/* The IP header */
1672struct uip_ip_hdr {
1673#if UIP_CONF_IPV6
1674 /* IPV6 header */
1675 u8_t vtc;
1676 u8_t tcflow;
1677 u16_t flow;
1678 u8_t len[2];
1679 u8_t proto, ttl;
1680 uip_ip6addr_t srcipaddr, destipaddr;
1681#else /* UIP_CONF_IPV6 */
1682 /* IPV4 header */
1683 u8_t vhl,
1684 tos,
1685 len[2],
1686 ipid[2],
1687 ipoffset[2],
1688 ttl,
1689 proto;
1690 u16_t ipchksum;
1691 uip_ipaddr_t srcipaddr, destipaddr;
1692#endif /* UIP_CONF_IPV6 */
1693};
1694
1695
1696/*
1697 * IPv6 extension option headers: we are able to process
1698 * the 4 extension headers defined in RFC2460 (IPv6):
1699 * - Hop by hop option header, destination option header:
1700 * These two are not used by any core IPv6 protocol, hence
1701 * we just read them and go to the next. They convey options,
1702 * the options defined in RFC2460 are Pad1 and PadN, which do
1703 * some padding, and that we do not need to read (the length
1704 * field in the header is enough)
1705 * - Routing header: this one is most notably used by MIPv6,
1706 * which we do not implement, hence we just read it and go
1707 * to the next
1708 * - Fragmentation header: we read this header and are able to
1709 * reassemble packets
1710 *
1711 * We do not offer any means to send packets with extension headers
1712 *
1713 * We do not implement Authentication and ESP headers, which are
1714 * used in IPSec and defined in RFC4302,4303,4305,4385
1715 */
1716/* common header part */
1717struct uip_ext_hdr {
1718 u8_t next;
1719 u8_t len;
1720};
1721
1722/* Hop by Hop option header */
1723struct uip_hbho_hdr {
1724 u8_t next;
1725 u8_t len;
1726};
1727
1728/* destination option header */
1729struct uip_desto_hdr {
1730 u8_t next;
1731 u8_t len;
1732};
1733
1734/* We do not define structures for PAD1 and PADN options */
1735
1736/*
1737 * routing header
1738 * the routing header as 4 common bytes, then routing header type
1739 * specific data there are several types of routing header. Type 0 was
1740 * deprecated as per RFC5095 most notable other type is 2, used in
1741 * RFC3775 (MIPv6) here we do not implement MIPv6, so we just need to
1742 * parse the 4 first bytes
1743 */
1744struct uip_routing_hdr {
1745 u8_t next;
1746 u8_t len;
1747 u8_t routing_type;
1748 u8_t seg_left;
1749};
1750
1751/* fragmentation header */
1752struct uip_frag_hdr {
1753 u8_t next;
1754 u8_t res;
1755 u16_t offsetresmore;
1756 u32_t id;
1757};
1758
1759/*
1760 * an option within the destination or hop by hop option headers
1761 * it contains type an length, which is true for all options but PAD1
1762 */
1763struct uip_ext_hdr_opt {
1764 u8_t type;
1765 u8_t len;
1766};
1767
1768/* PADN option */
1769struct uip_ext_hdr_opt_padn {
1770 u8_t opt_type;
1771 u8_t opt_len;
1772};
1773
1774/* TCP header */
1775struct uip_tcp_hdr {
1776 u16_t srcport;
1777 u16_t destport;
1778 u8_t seqno[4];
1779 u8_t ackno[4];
1780 u8_t tcpoffset;
1781 u8_t flags;
1782 u8_t wnd[2];
1783 u16_t tcpchksum;
1784 u8_t urgp[2];
1785 u8_t optdata[4];
1786};
1787
1788/* The ICMP headers. */
1789struct uip_icmp_hdr {
1790 u8_t type, icode;
1791 u16_t icmpchksum;
1792#if !UIP_CONF_IPV6
1793 u16_t id, seqno;
1794#endif /* !UIP_CONF_IPV6 */
1795};
1796
1797
1798/* The UDP headers. */
1799struct uip_udp_hdr {
1800 u16_t srcport;
1801 u16_t destport;
1802 u16_t udplen;
1803 u16_t udpchksum;
1804};
1805
1806
1807/**
1808 * The buffer size available for user data in the \ref uip_buf buffer.
1809 *
1810 * This macro holds the available size for user data in the \ref
1811 * uip_buf buffer. The macro is intended to be used for checking
1812 * bounds of available user data.
1813 *
1814 * Example:
1815 \code
1816 snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i);
1817 \endcode
1818 *
1819 * \hideinitializer
1820 */
1821#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
1822#define UIP_APPDATA_PTR (void *)&uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN]
1823
1824#define UIP_PROTO_ICMP 1
1825#define UIP_PROTO_TCP 6
1826#define UIP_PROTO_UDP 17
1827#define UIP_PROTO_ICMP6 58
1828
1829
1830#if UIP_CONF_IPV6
1831/** @{ */
1832/** \brief extension headers types */
1833#define UIP_PROTO_HBHO 0
1834#define UIP_PROTO_DESTO 60
1835#define UIP_PROTO_ROUTING 43
1836#define UIP_PROTO_FRAG 44
1837#define UIP_PROTO_NONE 59
1838/** @} */
1839
1840/** @{ */
1841/** \brief Destination and Hop By Hop extension headers option types */
1842#define UIP_EXT_HDR_OPT_PAD1 0
1843#define UIP_EXT_HDR_OPT_PADN 1
1844/** @} */
1845
1846/** @{ */
1847/**
1848 * \brief Bitmaps for extension header processing
1849 *
1850 * When processing extension headers, we should record somehow which one we
1851 * see, because you cannot have twice the same header, except for destination
1852 * We store all this in one u8_t bitmap one bit for each header expected. The
1853 * order in the bitmap is the order recommended in RFC2460
1854 */
1855#define UIP_EXT_HDR_BITMAP_HBHO 0x01
1856#define UIP_EXT_HDR_BITMAP_DESTO1 0x02
1857#define UIP_EXT_HDR_BITMAP_ROUTING 0x04
1858#define UIP_EXT_HDR_BITMAP_FRAG 0x08
1859#define UIP_EXT_HDR_BITMAP_AH 0x10
1860#define UIP_EXT_HDR_BITMAP_ESP 0x20
1861#define UIP_EXT_HDR_BITMAP_DESTO2 0x40
1862/** @} */
1863
1864
1865#endif /* UIP_CONF_IPV6 */
1866
1867
1868/* Header sizes. */
1869#if UIP_CONF_IPV6
1870#define UIP_IPH_LEN 40
1871#define UIP_FRAGH_LEN 8
1872#else /* UIP_CONF_IPV6 */
1873#define UIP_IPH_LEN 20 /* Size of IP header */
1874#endif /* UIP_CONF_IPV6 */
1875
1876#define UIP_UDPH_LEN 8 /* Size of UDP header */
1877#define UIP_TCPH_LEN 20 /* Size of TCP header */
1878#ifdef UIP_IPH_LEN
1879#define UIP_ICMPH_LEN 4 /* Size of ICMP header */
1880#endif
1881#define UIP_IPUDPH_LEN (UIP_UDPH_LEN + UIP_IPH_LEN) /* Size of IP +
1882 * UDP
1883 * header */
1884#define UIP_IPTCPH_LEN (UIP_TCPH_LEN + UIP_IPH_LEN) /* Size of IP +
1885 * TCP
1886 * header */
1887#define UIP_TCPIP_HLEN UIP_IPTCPH_LEN
1888#define UIP_IPICMPH_LEN (UIP_IPH_LEN + UIP_ICMPH_LEN) /* size of ICMP
1889 + IP header */
1890#define UIP_LLIPH_LEN (UIP_LLH_LEN + UIP_IPH_LEN) /* size of L2
1891 + IP header */
1892#if UIP_CONF_IPV6
1893/**
1894 * The sums below are quite used in ND. When used for uip_buf, we
1895 * include link layer length when used for uip_len, we do not, hence
1896 * we need values with and without LLH_LEN we do not use capital
1897 * letters as these values are variable
1898 */
1899#define uip_l2_l3_hdr_len (UIP_LLH_LEN + UIP_IPH_LEN + uip_ext_len)
1900#define uip_l2_l3_icmp_hdr_len (UIP_LLH_LEN + UIP_IPH_LEN + uip_ext_len + UIP_ICMPH_LEN)
1901#define uip_l3_hdr_len (UIP_IPH_LEN + uip_ext_len)
1902#define uip_l3_icmp_hdr_len (UIP_IPH_LEN + uip_ext_len + UIP_ICMPH_LEN)
1903#endif /*UIP_CONF_IPV6*/
1904
1905
1906#if UIP_FIXEDADDR
1907extern const uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr;
1908#else /* UIP_FIXEDADDR */
1909extern uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr;
1910#endif /* UIP_FIXEDADDR */
1911extern const uip_ipaddr_t uip_broadcast_addr;
1912extern const uip_ipaddr_t uip_all_zeroes_addr;
1913
1914#if UIP_FIXEDETHADDR
1915extern const uip_lladdr_t uip_lladdr;
1916#else
1917extern uip_lladdr_t uip_lladdr;
1918#endif
1919
1920
1921
1922
1923#ifdef UIP_CONF_IPV6
1924/**
1925 * \brief Is IPv6 address a the unspecified address
1926 * a is of type uip_ipaddr_t
1927 */
1928#define uip_is_addr_unspecified(a) \
1929 ((((a)->u16[0]) == 0) && \
1930 (((a)->u16[1]) == 0) && \
1931 (((a)->u16[2]) == 0) && \
1932 (((a)->u16[3]) == 0) && \
1933 (((a)->u16[4]) == 0) && \
1934 (((a)->u16[5]) == 0) && \
1935 (((a)->u16[6]) == 0) && \
1936 (((a)->u16[7]) == 0))
1937
1938/** \brief Is IPv6 address a the link local all-nodes multicast address */
1939#define uip_is_addr_linklocal_allnodes_mcast(a) \
1940 ((((a)->u8[0]) == 0xff) && \
1941 (((a)->u8[1]) == 0x02) && \
1942 (((a)->u16[1]) == 0) && \
1943 (((a)->u16[2]) == 0) && \
1944 (((a)->u16[3]) == 0) && \
1945 (((a)->u16[4]) == 0) && \
1946 (((a)->u16[5]) == 0) && \
1947 (((a)->u16[6]) == 0) && \
1948 (((a)->u8[14]) == 0) && \
1949 (((a)->u8[15]) == 0x01))
1950
1951/** \brief set IP address a to unspecified */
1952#define uip_create_unspecified(a) uip_ip6addr(a, 0, 0, 0, 0, 0, 0, 0, 0)
1953
1954/** \brief set IP address a to the link local all-nodes multicast address */
1955#define uip_create_linklocal_allnodes_mcast(a) uip_ip6addr(a, 0xff02, 0, 0, 0, 0, 0, 0, 0x0001)
1956
1957/** \brief set IP address a to the link local all-routers multicast address */
1958#define uip_create_linklocal_allrouters_mcast(a) uip_ip6addr(a, 0xff02, 0, 0, 0, 0, 0, 0, 0x0002)
1959
1960/**
1961 * \brief is addr (a) a solicited node multicast address, see RFC3513
1962 * a is of type uip_ipaddr_t*
1963 */
1964#define uip_is_addr_solicited_node(a) \
1965 ((((a)->u8[0]) == 0xFF) && \
1966 (((a)->u8[1]) == 0x02) && \
1967 (((a)->u16[1]) == 0) && \
1968 (((a)->u16[2]) == 0) && \
1969 (((a)->u16[3]) == 0) && \
1970 (((a)->u16[4]) == 0) && \
1971 (((a)->u16[5]) == 1) && \
1972 (((a)->u8[12]) == 0xFF))
1973
1974/**
1975 * \briefput in b the solicited node address corresponding to address a
1976 * both a and b are of type uip_ipaddr_t*
1977 * */
1978#define uip_create_solicited_node(a, b) \
1979 (((b)->u8[0]) = 0xFF); \
1980 (((b)->u8[1]) = 0x02); \
1981 (((b)->u16[1]) = 0); \
1982 (((b)->u16[2]) = 0); \
1983 (((b)->u16[3]) = 0); \
1984 (((b)->u16[4]) = 0); \
1985 (((b)->u8[10]) = 0); \
1986 (((b)->u8[11]) = 0x01); \
1987 (((b)->u8[12]) = 0xFF); \
1988 (((b)->u8[13]) = ((a)->u8[13])); \
1989 (((b)->u16[7]) = ((a)->u16[7]))
1990
1991/**
1992 * \brief is addr (a) a link local unicast address, see RFC3513
1993 * i.e. is (a) on prefix FE80::/10
1994 * a is of type uip_ipaddr_t*
1995 */
1996#define uip_is_addr_link_local(a) \
1997 ((((a)->u8[0]) == 0xFE) && \
1998 (((a)->u8[1]) == 0x80))
1999
2000/**
2001 * \brief was addr (a) forged based on the mac address m
2002 * a type is uip_ipaddr_t
2003 * m type is uiplladdr_t
2004 */
2005#if UIP_CONF_LL_802154
2006#define uip_is_addr_mac_addr_based(a, m) \
2007 ((((a)->u8[8]) == (((m)->addr[0]) ^ 0x02)) && \
2008 (((a)->u8[9]) == (m)->addr[1]) && \
2009 (((a)->u8[10]) == (m)->addr[2]) && \
2010 (((a)->u8[11]) == (m)->addr[3]) && \
2011 (((a)->u8[12]) == (m)->addr[4]) && \
2012 (((a)->u8[13]) == (m)->addr[5]) && \
2013 (((a)->u8[14]) == (m)->addr[6]) && \
2014 (((a)->u8[15]) == (m)->addr[7]))
2015#else
2016
2017#define uip_is_addr_mac_addr_based(a, m) \
2018 ((((a)->u8[8]) == (((m)->addr[0]) | 0x02)) && \
2019 (((a)->u8[9]) == (m)->addr[1]) && \
2020 (((a)->u8[10]) == (m)->addr[2]) && \
2021 (((a)->u8[11]) == 0xff) && \
2022 (((a)->u8[12]) == 0xfe) && \
2023 (((a)->u8[13]) == (m)->addr[3]) && \
2024 (((a)->u8[14]) == (m)->addr[4]) && \
2025 (((a)->u8[15]) == (m)->addr[5]))
2026
2027#endif /*UIP_CONF_LL_802154*/
2028
2029/**
2030 * \brief is address a multicast address, see RFC 3513
2031 * a is of type uip_ipaddr_t*
2032 * */
2033#define uip_is_addr_mcast(a) \
2034 (((a)->u8[0]) == 0xFF)
2035
2036/**
2037 * \brief is group-id of multicast address a
2038 * the all nodes group-id
2039 */
2040#define uip_is_mcast_group_id_all_nodes(a) \
2041 ((((a)->u16[1]) == 0) && \
2042 (((a)->u16[2]) == 0) && \
2043 (((a)->u16[3]) == 0) && \
2044 (((a)->u16[4]) == 0) && \
2045 (((a)->u16[5]) == 0) && \
2046 (((a)->u16[6]) == 0) && \
2047 (((a)->u8[14]) == 0) && \
2048 (((a)->u8[15]) == 1))
2049
2050/**
2051 * \brief is group-id of multicast address a
2052 * the all routers group-id
2053 */
2054#define uip_is_mcast_group_id_all_routers(a) \
2055 ((((a)->u16[1]) == 0) && \
2056 (((a)->u16[2]) == 0) && \
2057 (((a)->u16[3]) == 0) && \
2058 (((a)->u16[4]) == 0) && \
2059 (((a)->u16[5]) == 0) && \
2060 (((a)->u16[6]) == 0) && \
2061 (((a)->u8[14]) == 0) && \
2062 (((a)->u8[15]) == 2))
2063
2064
2065#endif /*UIP_CONF_IPV6*/
2066
2067/**
2068 * Calculate the Internet checksum over a buffer.
2069 *
2070 * The Internet checksum is the one's complement of the one's
2071 * complement sum of all 16-bit words in the buffer.
2072 *
2073 * See RFC1071.
2074 *
2075 * \param buf A pointer to the buffer over which the checksum is to be
2076 * computed.
2077 *
2078 * \param len The length of the buffer over which the checksum is to
2079 * be computed.
2080 *
2081 * \return The Internet checksum of the buffer.
2082 */
2083u16_t uip_chksum(u16_t *buf, u16_t len);
2084
2085/**
2086 * Calculate the IP header checksum of the packet header in uip_buf.
2087 *
2088 * The IP header checksum is the Internet checksum of the 20 bytes of
2089 * the IP header.
2090 *
2091 * \return The IP header checksum of the IP header in the uip_buf
2092 * buffer.
2093 */
2094u16_t uip_ipchksum(void);
2095
2096/**
2097 * Calculate the TCP checksum of the packet in uip_buf and uip_appdata.
2098 *
2099 * The TCP checksum is the Internet checksum of data contents of the
2100 * TCP segment, and a pseudo-header as defined in RFC793.
2101 *
2102 * \return The TCP checksum of the TCP segment in uip_buf and pointed
2103 * to by uip_appdata.
2104 */
2105u16_t uip_tcpchksum(void);
2106
2107/**
2108 * Calculate the UDP checksum of the packet in uip_buf and uip_appdata.
2109 *
2110 * The UDP checksum is the Internet checksum of data contents of the
2111 * UDP segment, and a pseudo-header as defined in RFC768.
2112 *
2113 * \return The UDP checksum of the UDP segment in uip_buf and pointed
2114 * to by uip_appdata.
2115 */
2116u16_t uip_udpchksum(void);
2117
2118/**
2119 * Calculate the ICMP checksum of the packet in uip_buf.
2120 *
2121 * \return The ICMP checksum of the ICMP packet in uip_buf
2122 */
2123u16_t uip_icmp6chksum(void);
2124
2125
2126#endif /* __UIP_H__ */
2127
2128
2129/** @} */
2130
diff --git a/lib/lufa/Projects/Webserver/Lib/uip/uip_arp.c b/lib/lufa/Projects/Webserver/Lib/uip/uip_arp.c
deleted file mode 100644
index fcb783b14..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uip/uip_arp.c
+++ /dev/null
@@ -1,432 +0,0 @@
1/**
2 * \addtogroup uip
3 * @{
4 */
5
6/**
7 * \defgroup uiparp uIP Address Resolution Protocol
8 * @{
9 *
10 * The Address Resolution Protocol ARP is used for mapping between IP
11 * addresses and link level addresses such as the Ethernet MAC
12 * addresses. ARP uses broadcast queries to ask for the link level
13 * address of a known IP address and the host which is configured with
14 * the IP address for which the query was meant, will respond with its
15 * link level address.
16 *
17 * \note This ARP implementation only supports Ethernet.
18 */
19
20/**
21 * \file
22 * Implementation of the ARP Address Resolution Protocol.
23 * \author Adam Dunkels <adam@dunkels.com>
24 *
25 */
26
27/*
28 * Copyright (c) 2001-2003, Adam Dunkels.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. The name of the author may not be used to endorse or promote
40 * products derived from this software without specific prior
41 * written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
44 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
47 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
49 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
51 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
52 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
53 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 *
55 * This file is part of the uIP TCP/IP stack.
56 *
57 * $Id: uip_arp.c,v 1.5 2008/02/07 01:35:00 adamdunkels Exp $
58 *
59 */
60
61
62#include "uip_arp.h"
63
64#include <string.h>
65
66struct arp_hdr {
67 struct uip_eth_hdr ethhdr;
68 u16_t hwtype;
69 u16_t protocol;
70 u8_t hwlen;
71 u8_t protolen;
72 u16_t opcode;
73 struct uip_eth_addr shwaddr;
74 uip_ipaddr_t sipaddr;
75 struct uip_eth_addr dhwaddr;
76 uip_ipaddr_t dipaddr;
77};
78
79struct ethip_hdr {
80 struct uip_eth_hdr ethhdr;
81 /* IP header. */
82 u8_t vhl,
83 tos,
84 len[2],
85 ipid[2],
86 ipoffset[2],
87 ttl,
88 proto;
89 u16_t ipchksum;
90 uip_ipaddr_t srcipaddr, destipaddr;
91};
92
93#define ARP_REQUEST 1
94#define ARP_REPLY 2
95
96#define ARP_HWTYPE_ETH 1
97
98struct arp_entry {
99 uip_ipaddr_t ipaddr;
100 struct uip_eth_addr ethaddr;
101 u8_t time;
102};
103
104static const struct uip_eth_addr broadcast_ethaddr =
105 {{0xff,0xff,0xff,0xff,0xff,0xff}};
106static const u16_t broadcast_ipaddr[2] = {0xffff,0xffff};
107
108static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
109static uip_ipaddr_t ipaddr;
110static u8_t i, c;
111
112static u8_t arptime;
113static u8_t tmpage;
114
115#define BUF ((struct arp_hdr *)&uip_buf[0])
116#define IPBUF ((struct ethip_hdr *)&uip_buf[0])
117
118#define DEBUG 0
119#if DEBUG
120#include <stdio.h>
121#define PRINTF(...) printf(__VA_ARGS__)
122#else
123#define PRINTF(...)
124#endif
125
126/*-----------------------------------------------------------------------------------*/
127/**
128 * Initialize the ARP module.
129 *
130 */
131/*-----------------------------------------------------------------------------------*/
132void
133uip_arp_init(void)
134{
135 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
136 memset(&arp_table[i].ipaddr, 0, 4);
137 }
138}
139/*-----------------------------------------------------------------------------------*/
140/**
141 * Periodic ARP processing function.
142 *
143 * This function performs periodic timer processing in the ARP module
144 * and should be called at regular intervals. The recommended interval
145 * is 10 seconds between the calls.
146 *
147 */
148/*-----------------------------------------------------------------------------------*/
149void
150uip_arp_timer(void)
151{
152 struct arp_entry *tabptr = NULL;
153
154 ++arptime;
155 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
156 tabptr = &arp_table[i];
157 if(uip_ipaddr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr) &&
158 arptime - tabptr->time >= UIP_ARP_MAXAGE) {
159 memset(&tabptr->ipaddr, 0, 4);
160 }
161 }
162
163}
164/*-----------------------------------------------------------------------------------*/
165static void
166uip_arp_update(uip_ipaddr_t *ipaddr, struct uip_eth_addr *ethaddr)
167{
168 register struct arp_entry *tabptr = NULL;
169 /* Walk through the ARP mapping table and try to find an entry to
170 update. If none is found, the IP -> MAC address mapping is
171 inserted in the ARP table. */
172 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
173
174 tabptr = &arp_table[i];
175 /* Only check those entries that are actually in use. */
176 if(!uip_ipaddr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) {
177
178 /* Check if the source IP address of the incoming packet matches
179 the IP address in this ARP table entry. */
180 if(uip_ipaddr_cmp(ipaddr, &tabptr->ipaddr)) {
181
182 /* An old entry found, update this and return. */
183 memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
184 tabptr->time = arptime;
185
186 return;
187 }
188 }
189 }
190
191 /* If we get here, no existing ARP table entry was found, so we
192 create one. */
193
194 /* First, we try to find an unused entry in the ARP table. */
195 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
196 tabptr = &arp_table[i];
197 if(uip_ipaddr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) {
198 break;
199 }
200 }
201
202 /* If no unused entry is found, we try to find the oldest entry and
203 throw it away. */
204 if(i == UIP_ARPTAB_SIZE) {
205 tmpage = 0;
206 c = 0;
207 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
208 tabptr = &arp_table[i];
209 if(arptime - tabptr->time > tmpage) {
210 tmpage = arptime - tabptr->time;
211 c = i;
212 }
213 }
214 i = c;
215 tabptr = &arp_table[i];
216 }
217
218 /* Now, i is the ARP table entry which we will fill with the new
219 information. */
220 uip_ipaddr_copy(&tabptr->ipaddr, ipaddr);
221 memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
222 tabptr->time = arptime;
223}
224/*-----------------------------------------------------------------------------------*/
225/**
226 * ARP processing for incoming IP packets
227 *
228 * This function should be called by the device driver when an IP
229 * packet has been received. The function will check if the address is
230 * in the ARP cache, and if so the ARP cache entry will be
231 * refreshed. If no ARP cache entry was found, a new one is created.
232 *
233 * This function expects an IP packet with a prepended Ethernet header
234 * in the uip_buf[] buffer, and the length of the packet in the global
235 * variable uip_len.
236 */
237/*-----------------------------------------------------------------------------------*/
238#if 0
239void
240uip_arp_ipin(void)
241{
242 uip_len -= sizeof(struct uip_eth_hdr);
243
244 /* Only insert/update an entry if the source IP address of the
245 incoming IP packet comes from a host on the local network. */
246 if((IPBUF->srcipaddr[0] & uip_netmask[0]) !=
247 (uip_hostaddr[0] & uip_netmask[0])) {
248 return;
249 }
250 if((IPBUF->srcipaddr[1] & uip_netmask[1]) !=
251 (uip_hostaddr[1] & uip_netmask[1])) {
252 return;
253 }
254 uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));
255
256 return;
257}
258#endif /* 0 */
259/*-----------------------------------------------------------------------------------*/
260/**
261 * ARP processing for incoming ARP packets.
262 *
263 * This function should be called by the device driver when an ARP
264 * packet has been received. The function will act differently
265 * depending on the ARP packet type: if it is a reply for a request
266 * that we previously sent out, the ARP cache will be filled in with
267 * the values from the ARP reply. If the incoming ARP packet is an ARP
268 * request for our IP address, an ARP reply packet is created and put
269 * into the uip_buf[] buffer.
270 *
271 * When the function returns, the value of the global variable uip_len
272 * indicates whether the device driver should send out a packet or
273 * not. If uip_len is zero, no packet should be sent. If uip_len is
274 * non-zero, it contains the length of the outbound packet that is
275 * present in the uip_buf[] buffer.
276 *
277 * This function expects an ARP packet with a prepended Ethernet
278 * header in the uip_buf[] buffer, and the length of the packet in the
279 * global variable uip_len.
280 */
281/*-----------------------------------------------------------------------------------*/
282void
283uip_arp_arpin(void)
284{
285 if(uip_len < sizeof(struct arp_hdr)) {
286 uip_len = 0;
287 return;
288 }
289 uip_len = 0;
290
291 switch(BUF->opcode) {
292 case HTONS(ARP_REQUEST):
293 /* ARP request. If it asked for our address, we send out a
294 reply. */
295 /* if(BUF->dipaddr[0] == uip_hostaddr[0] &&
296 BUF->dipaddr[1] == uip_hostaddr[1]) {*/
297 PRINTF("uip_arp_arpin: request for %d.%d.%d.%d (we are %d.%d.%d.%d)\n",
298 BUF->dipaddr.u8[0], BUF->dipaddr.u8[1],
299 BUF->dipaddr.u8[2], BUF->dipaddr.u8[3],
300 uip_hostaddr.u8[0], uip_hostaddr.u8[1],
301 uip_hostaddr.u8[2], uip_hostaddr.u8[3]);
302 if(uip_ipaddr_cmp(&BUF->dipaddr, &uip_hostaddr)) {
303 /* First, we register the one who made the request in our ARP
304 table, since it is likely that we will do more communication
305 with this host in the future. */
306 uip_arp_update(&BUF->sipaddr, &BUF->shwaddr);
307
308 BUF->opcode = HTONS(ARP_REPLY);
309
310 memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6);
311 memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
312 memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
313 memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6);
314
315 uip_ipaddr_copy(&BUF->dipaddr, &BUF->sipaddr);
316 uip_ipaddr_copy(&BUF->sipaddr, &uip_hostaddr);
317
318 BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
319 uip_len = sizeof(struct arp_hdr);
320 }
321 break;
322 case HTONS(ARP_REPLY):
323 /* ARP reply. We insert or update the ARP table if it was meant
324 for us. */
325 if(uip_ipaddr_cmp(&BUF->dipaddr, &uip_hostaddr)) {
326 uip_arp_update(&BUF->sipaddr, &BUF->shwaddr);
327 }
328 break;
329 }
330
331 return;
332}
333/*-----------------------------------------------------------------------------------*/
334/**
335 * Prepend Ethernet header to an outbound IP packet and see if we need
336 * to send out an ARP request.
337 *
338 * This function should be called before sending out an IP packet. The
339 * function checks the destination IP address of the IP packet to see
340 * what Ethernet MAC address that should be used as a destination MAC
341 * address on the Ethernet.
342 *
343 * If the destination IP address is in the local network (determined
344 * by logical ANDing of netmask and our IP address), the function
345 * checks the ARP cache to see if an entry for the destination IP
346 * address is found. If so, an Ethernet header is prepended and the
347 * function returns. If no ARP cache entry is found for the
348 * destination IP address, the packet in the uip_buf[] is replaced by
349 * an ARP request packet for the IP address. The IP packet is dropped
350 * and it is assumed that they higher level protocols (e.g., TCP)
351 * eventually will retransmit the dropped packet.
352 *
353 * If the destination IP address is not on the local network, the IP
354 * address of the default router is used instead.
355 *
356 * When the function returns, a packet is present in the uip_buf[]
357 * buffer, and the length of the packet is in the global variable
358 * uip_len.
359 */
360/*-----------------------------------------------------------------------------------*/
361void
362uip_arp_out(void)
363{
364 struct arp_entry *tabptr = NULL;
365
366 /* Find the destination IP address in the ARP table and construct
367 the Ethernet header. If the destination IP address isn't on the
368 local network, we use the default router's IP address instead.
369
370 If not ARP table entry is found, we overwrite the original IP
371 packet with an ARP request for the IP address. */
372
373 /* First check if destination is a local broadcast. */
374 if(uip_ipaddr_cmp(&IPBUF->destipaddr, &uip_broadcast_addr)) {
375 memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);
376 } else {
377 /* Check if the destination address is on the local network. */
378 if(!uip_ipaddr_maskcmp(&IPBUF->destipaddr, &uip_hostaddr, &uip_netmask)) {
379 /* Destination address was not on the local network, so we need to
380 use the default router's IP address instead of the destination
381 address when determining the MAC address. */
382 uip_ipaddr_copy(&ipaddr, &uip_draddr);
383 } else {
384 /* Else, we use the destination IP address. */
385 uip_ipaddr_copy(&ipaddr, &IPBUF->destipaddr);
386 }
387
388 for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
389 tabptr = &arp_table[i];
390 if(uip_ipaddr_cmp(&ipaddr, &tabptr->ipaddr)) {
391 break;
392 }
393 }
394
395 if(i == UIP_ARPTAB_SIZE) {
396 /* The destination address was not in our ARP table, so we
397 overwrite the IP packet with an ARP request. */
398
399 memset(BUF->ethhdr.dest.addr, 0xff, 6);
400 memset(BUF->dhwaddr.addr, 0x00, 6);
401 memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
402 memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
403
404 uip_ipaddr_copy(&BUF->dipaddr, &ipaddr);
405 uip_ipaddr_copy(&BUF->sipaddr, &uip_hostaddr);
406 BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */
407 BUF->hwtype = HTONS(ARP_HWTYPE_ETH);
408 BUF->protocol = HTONS(UIP_ETHTYPE_IP);
409 BUF->hwlen = 6;
410 BUF->protolen = 4;
411 BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
412
413 uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];
414
415 uip_len = sizeof(struct arp_hdr);
416 return;
417 }
418
419 /* Build an ethernet header. */
420 memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);
421 }
422 memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
423
424 IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP);
425
426 uip_len += sizeof(struct uip_eth_hdr);
427}
428/*-----------------------------------------------------------------------------------*/
429
430/** @} */
431/** @} */
432
diff --git a/lib/lufa/Projects/Webserver/Lib/uip/uip_arp.h b/lib/lufa/Projects/Webserver/Lib/uip/uip_arp.h
deleted file mode 100644
index 4e78ce7b7..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uip/uip_arp.h
+++ /dev/null
@@ -1,146 +0,0 @@
1/**
2 * \addtogroup uip
3 * @{
4 */
5
6/**
7 * \addtogroup uiparp
8 * @{
9 */
10
11/**
12 * \file
13 * Macros and definitions for the ARP module.
14 * \author Adam Dunkels <adam@dunkels.com>
15 */
16
17
18/*
19 * Copyright (c) 2001-2003, Adam Dunkels.
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. The name of the author may not be used to endorse or promote
31 * products derived from this software without specific prior
32 * written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
35 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
36 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
38 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
43 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 *
46 * This file is part of the uIP TCP/IP stack.
47 *
48 * $Id: uip_arp.h,v 1.2 2006/08/26 23:58:45 oliverschmidt Exp $
49 *
50 */
51
52#ifndef __UIP_ARP_H__
53#define __UIP_ARP_H__
54
55#include "uip.h"
56
57
58extern struct uip_eth_addr uip_ethaddr;
59
60/**
61 * The Ethernet header.
62 */
63struct uip_eth_hdr {
64 struct uip_eth_addr dest;
65 struct uip_eth_addr src;
66 u16_t type;
67};
68
69#define UIP_ETHTYPE_ARP 0x0806
70#define UIP_ETHTYPE_IP 0x0800
71#define UIP_ETHTYPE_IPV6 0x86dd
72
73
74/* The uip_arp_init() function must be called before any of the other
75 ARP functions. */
76void uip_arp_init(void);
77
78/* The uip_arp_ipin() function should be called whenever an IP packet
79 arrives from the Ethernet. This function refreshes the ARP table or
80 inserts a new mapping if none exists. The function assumes that an
81 IP packet with an Ethernet header is present in the uip_buf buffer
82 and that the length of the packet is in the uip_len variable. */
83/*void uip_arp_ipin(void);*/
84#define uip_arp_ipin()
85
86/* The uip_arp_arpin() should be called when an ARP packet is received
87 by the Ethernet driver. This function also assumes that the
88 Ethernet frame is present in the uip_buf buffer. When the
89 uip_arp_arpin() function returns, the contents of the uip_buf
90 buffer should be sent out on the Ethernet if the uip_len variable
91 is > 0. */
92void uip_arp_arpin(void);
93
94/* The uip_arp_out() function should be called when an IP packet
95 should be sent out on the Ethernet. This function creates an
96 Ethernet header before the IP header in the uip_buf buffer. The
97 Ethernet header will have the correct Ethernet MAC destination
98 address filled in if an ARP table entry for the destination IP
99 address (or the IP address of the default router) is present. If no
100 such table entry is found, the IP packet is overwritten with an ARP
101 request and we rely on TCP to retransmit the packet that was
102 overwritten. In any case, the uip_len variable holds the length of
103 the Ethernet frame that should be transmitted. */
104void uip_arp_out(void);
105
106/* The uip_arp_timer() function should be called every ten seconds. It
107 is responsible for flushing old entries in the ARP table. */
108void uip_arp_timer(void);
109
110/** @} */
111
112/**
113 * \addtogroup uipconffunc
114 * @{
115 */
116
117
118/**
119 * Specifiy the Ethernet MAC address.
120 *
121 * The ARP code needs to know the MAC address of the Ethernet card in
122 * order to be able to respond to ARP queries and to generate working
123 * Ethernet headers.
124 *
125 * \note This macro only specifies the Ethernet MAC address to the ARP
126 * code. It cannot be used to change the MAC address of the Ethernet
127 * card.
128 *
129 * \param eaddr A pointer to a struct uip_eth_addr containing the
130 * Ethernet MAC address of the Ethernet card.
131 *
132 * \hideinitializer
133 */
134#define uip_setethaddr(eaddr) do {uip_ethaddr.addr[0] = eaddr.addr[0]; \
135 uip_ethaddr.addr[1] = eaddr.addr[1];\
136 uip_ethaddr.addr[2] = eaddr.addr[2];\
137 uip_ethaddr.addr[3] = eaddr.addr[3];\
138 uip_ethaddr.addr[4] = eaddr.addr[4];\
139 uip_ethaddr.addr[5] = eaddr.addr[5];} while(0)
140
141/** @} */
142
143
144#endif /* __UIP_ARP_H__ */
145/** @} */
146
diff --git a/lib/lufa/Projects/Webserver/Lib/uip/uipopt.h b/lib/lufa/Projects/Webserver/Lib/uip/uipopt.h
deleted file mode 100644
index 520c03f25..000000000
--- a/lib/lufa/Projects/Webserver/Lib/uip/uipopt.h
+++ /dev/null
@@ -1,740 +0,0 @@
1/**
2 * \addtogroup uip
3 * @{
4 */
5
6/**
7 * \defgroup uipopt Configuration options for uIP
8 * @{
9 *
10 * uIP is configured using the per-project configuration file
11 * "uipopt.h". This file contains all compile-time options for uIP and
12 * should be tweaked to match each specific project. The uIP
13 * distribution contains a documented example "uipopt.h" that can be
14 * copied and modified for each project.
15 */
16
17/**
18 * \file
19 * Configuration options for uIP.
20 * \author Adam Dunkels <adam@dunkels.com>
21 *
22 * This file is used for tweaking various configuration options for
23 * uIP. You should make a copy of this file into one of your project's
24 * directories instead of editing this example "uipopt.h" file that
25 * comes with the uIP distribution.
26 */
27
28/*
29 * Copyright (c) 2001-2003, Adam Dunkels.
30 * All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. The name of the author may not be used to endorse or promote
41 * products derived from this software without specific prior
42 * written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
45 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
46 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
48 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
50 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
52 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
53 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
54 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 *
56 * This file is part of the uIP TCP/IP stack.
57 *
58 * $Id: uipopt.h,v 1.11 2009/04/10 00:37:48 adamdunkels Exp $
59 *
60 */
61
62#ifndef __UIPOPT_H__
63#define __UIPOPT_H__
64
65#include "Config/AppConfig.h"
66
67#ifndef UIP_LITTLE_ENDIAN
68#define UIP_LITTLE_ENDIAN 3412
69#endif /* UIP_LITTLE_ENDIAN */
70#ifndef UIP_BIG_ENDIAN
71#define UIP_BIG_ENDIAN 1234
72#endif /* UIP_BIG_ENDIAN */
73
74/*------------------------------------------------------------------------------*/
75
76/**
77 * \defgroup uipoptstaticconf Static configuration options
78 * @{
79 *
80 * These configuration options can be used for setting the IP address
81 * settings statically, but only if UIP_FIXEDADDR is set to 1. The
82 * configuration options for a specific node includes IP address,
83 * netmask and default router as well as the Ethernet address. The
84 * netmask, default router and Ethernet address are applicable only
85 * if uIP should be run over Ethernet.
86 *
87 * This options are meaningful only for the IPv4 code.
88 *
89 * All of these should be changed to suit your project.
90 */
91
92/**
93 * Determines if uIP should use a fixed IP address or not.
94 *
95 * If uIP should use a fixed IP address, the settings are set in the
96 * uipopt.h file. If not, the macros uip_sethostaddr(),
97 * uip_setdraddr() and uip_setnetmask() should be used instead.
98 *
99 * \hideinitializer
100 */
101#define UIP_FIXEDADDR 0
102
103/**
104 * Ping IP address assignment.
105 *
106 * uIP uses a "ping" packets for setting its own IP address if this
107 * option is set. If so, uIP will start with an empty IP address and
108 * the destination IP address of the first incoming "ping" (ICMP echo)
109 * packet will be used for setting the hosts IP address.
110 *
111 * \note This works only if UIP_FIXEDADDR is 0.
112 *
113 * \hideinitializer
114 */
115#ifdef UIP_CONF_PINGADDRCONF
116#define UIP_PINGADDRCONF UIP_CONF_PINGADDRCONF
117#else /* UIP_CONF_PINGADDRCONF */
118#define UIP_PINGADDRCONF 0
119#endif /* UIP_CONF_PINGADDRCONF */
120
121
122/**
123 * Specifies if the uIP ARP module should be compiled with a fixed
124 * Ethernet MAC address or not.
125 *
126 * If this configuration option is 0, the macro uip_setethaddr() can
127 * be used to specify the Ethernet address at run-time.
128 *
129 * \hideinitializer
130 */
131#define UIP_FIXEDETHADDR 0
132
133/** @} */
134/*------------------------------------------------------------------------------*/
135/**
136 * \defgroup uipoptip IP configuration options
137 * @{
138 *
139 */
140/**
141 * The IP TTL (time to live) of IP packets sent by uIP.
142 *
143 * This should normally not be changed.
144 */
145#define UIP_TTL 64
146
147/**
148 * The maximum time an IP fragment should wait in the reassembly
149 * buffer before it is dropped.
150 *
151 */
152#define UIP_REASS_MAXAGE 60 /*60s*/
153
154/**
155 * Turn on support for IP packet reassembly.
156 *
157 * uIP supports reassembly of fragmented IP packets. This features
158 * requires an additional amount of RAM to hold the reassembly buffer
159 * and the reassembly code size is approximately 700 bytes. The
160 * reassembly buffer is of the same size as the uip_buf buffer
161 * (configured by UIP_BUFSIZE).
162 *
163 * \note IP packet reassembly is not heavily tested.
164 *
165 * \hideinitializer
166 */
167#ifdef UIP_CONF_REASSEMBLY
168#define UIP_REASSEMBLY UIP_CONF_REASSEMBLY
169#else /* UIP_CONF_REASSEMBLY */
170#define UIP_REASSEMBLY 0
171#endif /* UIP_CONF_REASSEMBLY */
172/** @} */
173
174/*------------------------------------------------------------------------------*/
175/**
176 * \defgroup uipoptipv6 IPv6 configuration options
177 * @{
178 *
179 */
180
181/** The maximum transmission unit at the IP Layer*/
182#define UIP_LINK_MTU 1280
183
184#ifndef UIP_CONF_IPV6
185/** Do we use IPv6 or not (default: no) */
186#define UIP_CONF_IPV6 0
187#endif
188
189#ifndef UIP_CONF_IPV6_QUEUE_PKT
190/** Do we do per %neighbor queuing during address resolution (default: no) */
191#define UIP_CONF_IPV6_QUEUE_PKT 0
192#endif
193
194#ifndef UIP_CONF_IPV6_CHECKS
195/** Do we do IPv6 consistency checks (highly recommended, default: yes) */
196#define UIP_CONF_IPV6_CHECKS 1
197#endif
198
199#ifndef UIP_CONF_IPV6_REASSEMBLY
200/** Do we do IPv6 fragmentation (default: no) */
201#define UIP_CONF_IPV6_REASSEMBLY 0
202#endif
203
204#ifndef UIP_CONF_NETIF_MAX_ADDRESSES
205/** Default number of IPv6 addresses associated to the node's interface */
206#define UIP_CONF_NETIF_MAX_ADDRESSES 3
207#endif
208
209#ifndef UIP_CONF_ND6_MAX_PREFIXES
210/** Default number of IPv6 prefixes associated to the node's interface */
211#define UIP_CONF_ND6_MAX_PREFIXES 3
212#endif
213
214#ifndef UIP_CONF_ND6_MAX_NEIGHBORS
215/** Default number of neighbors that can be stored in the %neighbor cache */
216#define UIP_CONF_ND6_MAX_NEIGHBORS 4
217#endif
218
219#ifndef UIP_CONF_ND6_MAX_DEFROUTERS
220/** Minimum number of default routers */
221#define UIP_CONF_ND6_MAX_DEFROUTERS 2
222#endif
223/** @} */
224
225/*------------------------------------------------------------------------------*/
226/**
227 * \defgroup uipoptudp UDP configuration options
228 * @{
229 *
230 * \note The UDP support in uIP is still not entirely complete; there
231 * is no support for sending or receiving broadcast or multicast
232 * packets, but it works well enough to support a number of vital
233 * applications such as DNS queries, though
234 */
235
236/**
237 * Toggles whether UDP support should be compiled in or not.
238 *
239 * \hideinitializer
240 */
241#ifdef UIP_CONF_UDP
242#define UIP_UDP UIP_CONF_UDP
243#else /* UIP_CONF_UDP */
244#define UIP_UDP 1
245#endif /* UIP_CONF_UDP */
246
247/**
248 * Toggles if UDP checksums should be used or not.
249 *
250 * \note Support for UDP checksums is currently not included in uIP,
251 * so this option has no function.
252 *
253 * \hideinitializer
254 */
255#ifdef UIP_CONF_UDP_CHECKSUMS
256#define UIP_UDP_CHECKSUMS UIP_CONF_UDP_CHECKSUMS
257#else
258#define UIP_UDP_CHECKSUMS 0
259#endif
260
261/**
262 * The maximum amount of concurrent UDP connections.
263 *
264 * \hideinitializer
265 */
266#ifdef UIP_CONF_UDP_CONNS
267#define UIP_UDP_CONNS UIP_CONF_UDP_CONNS
268#else /* UIP_CONF_UDP_CONNS */
269#define UIP_UDP_CONNS 10
270#endif /* UIP_CONF_UDP_CONNS */
271
272/**
273 * The name of the function that should be called when UDP datagrams arrive.
274 *
275 * \hideinitializer
276 */
277
278
279/** @} */
280/*------------------------------------------------------------------------------*/
281/**
282 * \defgroup uipopttcp TCP configuration options
283 * @{
284 */
285
286/**
287 * Toggles whether TCP support should be compiled in or not.
288 *
289 * \hideinitializer
290 */
291#ifdef UIP_CONF_TCP
292#define UIP_TCP UIP_CONF_TCP
293#else /* UIP_CONF_TCP */
294#define UIP_TCP 1
295#endif /* UIP_CONF_TCP */
296
297/**
298 * Determines if support for opening connections from uIP should be
299 * compiled in.
300 *
301 * If the applications that are running on top of uIP for this project
302 * do not need to open outgoing TCP connections, this configuration
303 * option can be turned off to reduce the code size of uIP.
304 *
305 * \hideinitializer
306 */
307#ifndef UIP_CONF_ACTIVE_OPEN
308#define UIP_ACTIVE_OPEN 1
309#else /* UIP_CONF_ACTIVE_OPEN */
310#define UIP_ACTIVE_OPEN UIP_CONF_ACTIVE_OPEN
311#endif /* UIP_CONF_ACTIVE_OPEN */
312
313/**
314 * The maximum number of simultaneously open TCP connections.
315 *
316 * Since the TCP connections are statically allocated, turning this
317 * configuration knob down results in less RAM used. Each TCP
318 * connection requires approximately 30 bytes of memory.
319 *
320 * \hideinitializer
321 */
322#ifndef UIP_CONF_MAX_CONNECTIONS
323#define UIP_CONNS 10
324#else /* UIP_CONF_MAX_CONNECTIONS */
325#define UIP_CONNS UIP_CONF_MAX_CONNECTIONS
326#endif /* UIP_CONF_MAX_CONNECTIONS */
327
328
329/**
330 * The maximum number of simultaneously listening TCP ports.
331 *
332 * Each listening TCP port requires 2 bytes of memory.
333 *
334 * \hideinitializer
335 */
336#ifndef UIP_CONF_MAX_LISTENPORTS
337#define UIP_LISTENPORTS 20
338#else /* UIP_CONF_MAX_LISTENPORTS */
339#define UIP_LISTENPORTS UIP_CONF_MAX_LISTENPORTS
340#endif /* UIP_CONF_MAX_LISTENPORTS */
341
342/**
343 * Determines if support for TCP urgent data notification should be
344 * compiled in.
345 *
346 * Urgent data (out-of-band data) is a rarely used TCP feature that
347 * very seldom would be required.
348 *
349 * \hideinitializer
350 */
351#if !defined(UIP_URGDATA)
352#define UIP_URGDATA 0
353#endif
354
355/**
356 * The initial retransmission timeout counted in timer pulses.
357 *
358 * This should not be changed.
359 */
360#if !defined(UIP_RTO)
361#define UIP_RTO 3
362#endif
363
364/**
365 * The maximum number of times a segment should be retransmitted
366 * before the connection should be aborted.
367 *
368 * This should not be changed.
369 */
370#if !defined(UIP_MAXRTX)
371#define UIP_MAXRTX 8
372#endif
373
374/**
375 * The maximum number of times a SYN segment should be retransmitted
376 * before a connection request should be deemed to have been
377 * unsuccessful.
378 *
379 * This should not need to be changed.
380 */
381#if !defined(UIP_MAXSYNRTX)
382#define UIP_MAXSYNRTX 5
383#endif
384
385/**
386 * The TCP maximum segment size.
387 *
388 * This is should not be to set to more than
389 * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN.
390 */
391#ifdef UIP_CONF_TCP_MSS
392#define UIP_TCP_MSS UIP_CONF_TCP_MSS
393#else
394#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
395#endif
396
397/**
398 * The size of the advertised receiver's window.
399 *
400 * Should be set low (i.e., to the size of the uip_buf buffer) if the
401 * application is slow to process incoming data, or high (32768 bytes)
402 * if the application processes data quickly.
403 *
404 * \hideinitializer
405 */
406#ifndef UIP_CONF_RECEIVE_WINDOW
407#define UIP_RECEIVE_WINDOW UIP_TCP_MSS
408#else
409#define UIP_RECEIVE_WINDOW UIP_CONF_RECEIVE_WINDOW
410#endif
411
412/**
413 * How long a connection should stay in the TIME_WAIT state.
414 *
415 * This configuration option has no real implication, and it should be
416 * left untouched.
417 */
418#define UIP_TIME_WAIT_TIMEOUT 120
419
420
421/** @} */
422/*------------------------------------------------------------------------------*/
423/**
424 * \defgroup uipoptarp ARP configuration options
425 * @{
426 */
427
428/**
429 * The size of the ARP table.
430 *
431 * This option should be set to a larger value if this uIP node will
432 * have many connections from the local network.
433 *
434 * \hideinitializer
435 */
436#ifdef UIP_CONF_ARPTAB_SIZE
437#define UIP_ARPTAB_SIZE UIP_CONF_ARPTAB_SIZE
438#else
439#define UIP_ARPTAB_SIZE 8
440#endif
441
442/**
443 * The maximum age of ARP table entries measured in 10ths of seconds.
444 *
445 * An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD
446 * default).
447 */
448#define UIP_ARP_MAXAGE 120
449
450
451/** @} */
452
453/*------------------------------------------------------------------------------*/
454
455/**
456 * \defgroup uipoptmac layer 2 options (for ipv6)
457 * @{
458 */
459
460#define UIP_DEFAULT_PREFIX_LEN 64
461
462/** @} */
463
464/*------------------------------------------------------------------------------*/
465
466/**
467 * \defgroup uipoptsics 6lowpan options (for ipv6)
468 * @{
469 */
470/**
471 * Timeout for packet reassembly at the 6lowpan layer
472 * (should be < 60s)
473 */
474#ifdef SICSLOWPAN_CONF_MAXAGE
475#define SICSLOWPAN_REASS_MAXAGE SICSLOWPAN_CONF_MAXAGE
476#else
477#define SICSLOWPAN_REASS_MAXAGE 20
478#endif
479
480/**
481 * Do we compress the IP header or not (default: no)
482 */
483#ifndef SICSLOWPAN_CONF_COMPRESSION
484#define SICSLOWPAN_CONF_COMPRESSION 0
485#endif
486
487/**
488 * If we use IPHC compression, how many address contexts do we support
489 */
490#ifndef SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS
491#define SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS 1
492#endif
493
494/**
495 * Do we support 6lowpan fragmentation
496 */
497#ifndef SICSLOWPAN_CONF_FRAG
498#define SICSLOWPAN_CONF_FRAG 0
499#endif
500
501/** @} */
502
503/*------------------------------------------------------------------------------*/
504
505/**
506 * \defgroup uipoptgeneral General configuration options
507 * @{
508 */
509
510/**
511 * The size of the uIP packet buffer.
512 *
513 * The uIP packet buffer should not be smaller than 60 bytes, and does
514 * not need to be larger than 1514 bytes. Lower size results in lower
515 * TCP throughput, larger size results in higher TCP throughput.
516 *
517 * \hideinitializer
518 */
519#ifndef UIP_CONF_BUFFER_SIZE
520#define UIP_BUFSIZE UIP_LINK_MTU + UIP_LLH_LEN
521#else /* UIP_CONF_BUFFER_SIZE */
522#define UIP_BUFSIZE UIP_CONF_BUFFER_SIZE
523#endif /* UIP_CONF_BUFFER_SIZE */
524
525
526/**
527 * Determines if statistics support should be compiled in.
528 *
529 * The statistics is useful for debugging and to show the user.
530 *
531 * \hideinitializer
532 */
533#ifndef UIP_CONF_STATISTICS
534#define UIP_STATISTICS 0
535#else /* UIP_CONF_STATISTICS */
536#define UIP_STATISTICS UIP_CONF_STATISTICS
537#endif /* UIP_CONF_STATISTICS */
538
539/**
540 * Determines if logging of certain events should be compiled in.
541 *
542 * This is useful mostly for debugging. The function uip_log()
543 * must be implemented to suit the architecture of the project, if
544 * logging is turned on.
545 *
546 * \hideinitializer
547 */
548#ifndef UIP_CONF_LOGGING
549#define UIP_LOGGING 0
550#else /* UIP_CONF_LOGGING */
551#define UIP_LOGGING UIP_CONF_LOGGING
552#endif /* UIP_CONF_LOGGING */
553
554/**
555 * Broadcast support.
556 *
557 * This flag configures IP broadcast support. This is useful only
558 * together with UDP.
559 *
560 * \hideinitializer
561 *
562 */
563#ifndef UIP_CONF_BROADCAST
564#define UIP_BROADCAST 0
565#else /* UIP_CONF_BROADCAST */
566#define UIP_BROADCAST UIP_CONF_BROADCAST
567#endif /* UIP_CONF_BROADCAST */
568
569/**
570 * Print out a uIP log message.
571 *
572 * This function must be implemented by the module that uses uIP, and
573 * is called by uIP whenever a log message is generated.
574 */
575void uip_log(char *msg);
576
577/**
578 * The link level header length.
579 *
580 * This is the offset into the uip_buf where the IP header can be
581 * found. For Ethernet, this should be set to 14. For SLIP, this
582 * should be set to 0.
583 *
584 * \note we probably won't use this constant for other link layers than
585 * ethernet as they have variable header length (this is due to variable
586 * number and type of address fields and to optional security features)
587 * E.g.: 802.15.4 -> 2 + (1/2*4/8) + 0/5/6/10/14
588 * 802.11 -> 4 + (6*3/4) + 2
589 * \hideinitializer
590 */
591#ifdef UIP_CONF_LLH_LEN
592#define UIP_LLH_LEN UIP_CONF_LLH_LEN
593#else /* UIP_LLH_LEN */
594#define UIP_LLH_LEN 14
595#endif /* UIP_CONF_LLH_LEN */
596
597/** @} */
598/*------------------------------------------------------------------------------*/
599/**
600 * \defgroup uipoptcpu CPU architecture configuration
601 * @{
602 *
603 * The CPU architecture configuration is where the endianess of the
604 * CPU on which uIP is to be run is specified. Most CPUs today are
605 * little endian, and the most notable exception are the Motorolas
606 * which are big endian. The BYTE_ORDER macro should be changed to
607 * reflect the CPU architecture on which uIP is to be run.
608 */
609
610/**
611 * The byte order of the CPU architecture on which uIP is to be run.
612 *
613 * This option can be either UIP_BIG_ENDIAN (Motorola byte order) or
614 * UIP_LITTLE_ENDIAN (Intel byte order).
615 *
616 * \hideinitializer
617 */
618#ifdef UIP_CONF_BYTE_ORDER
619#define UIP_BYTE_ORDER UIP_CONF_BYTE_ORDER
620#else /* UIP_CONF_BYTE_ORDER */
621#define UIP_BYTE_ORDER UIP_LITTLE_ENDIAN
622#endif /* UIP_CONF_BYTE_ORDER */
623
624/** @} */
625/*------------------------------------------------------------------------------*/
626
627#include <ff.h>
628#include <stdbool.h>
629#include <stdint.h>
630
631#include "timer.h"
632
633typedef uint8_t u8_t;
634typedef uint16_t u16_t;
635typedef uint32_t u32_t;
636typedef uint32_t uip_stats_t;
637
638/**
639 * \defgroup uipoptapp Application specific configurations
640 * @{
641 *
642 * An uIP application is implemented using a single application
643 * function that is called by uIP whenever a TCP/IP event occurs. The
644 * name of this function must be registered with uIP at compile time
645 * using the UIP_APPCALL definition.
646 *
647 * uIP applications can store the application state within the
648 * uip_conn structure by specifying the type of the application
649 * structure by typedef:ing the type uip_tcp_appstate_t and uip_udp_appstate_t.
650 *
651 * The file containing the definitions must be included in the
652 * uipopt.h file.
653 *
654 * The following example illustrates how this can look.
655 \code
656
657 void httpd_appcall(void);
658 #define UIP_APPCALL httpd_appcall
659
660 struct httpd_state {
661 u8_t state;
662 u16_t count;
663 char *dataptr;
664 char *script;
665 };
666 typedef struct httpd_state uip_tcp_appstate_t
667 \endcode
668*/
669#define UIP_UDP_APPCALL uIPManagement_UDPCallback
670void UIP_UDP_APPCALL(void);
671
672/**
673 * \var #define UIP_APPCALL
674 *
675 * The name of the application function that uIP should call in
676 * response to TCP/IP events.
677 *
678 */
679#define UIP_APPCALL uIPManagement_TCPCallback
680void UIP_APPCALL(void);
681
682/**
683 * \var typedef uip_tcp_appstate_t
684 *
685 * The type of the application state that is to be stored in the
686 * uip_conn structure. This usually is typedef:ed to a struct holding
687 * application state information.
688 */
689typedef union
690{
691 struct
692 {
693 uint8_t CurrentState;
694 uint8_t NextState;
695
696 char FileName[MAX_URI_LENGTH];
697 FIL FileHandle;
698 bool FileOpen;
699 uint32_t ACKedFilePos;
700 uint16_t SentChunkSize;
701 } HTTPServer;
702
703 struct
704 {
705 uint8_t CurrentState;
706 uint8_t NextState;
707
708 uint8_t IssuedCommand;
709 } TELNETServer;
710} uip_tcp_appstate_t;
711
712/**
713 * \var typedef uip_udp_appstate_t
714 *
715 * The type of the application state that is to be stored in the
716 * uip_conn structure. This usually is typedef:ed to a struct holding
717 * application state information.
718 */
719typedef union
720{
721 struct
722 {
723 uint8_t CurrentState;
724 struct timer Timeout;
725
726 struct
727 {
728 uint8_t AllocatedIP[4];
729 uint8_t Netmask[4];
730 uint8_t GatewayIP[4];
731 uint8_t ServerIP[4];
732 } DHCPOffer_Data;
733 } DHCPClient;
734} uip_udp_appstate_t;
735/** @} */
736
737#endif /* __UIPOPT_H__ */
738/** @} */
739/** @} */
740