This application requires the PNUT file system, which is not available on Ethernut 1.x or Charon II.
00001 /* 00002 * Copyright (C) 2005 by egnite Software GmbH. All rights reserved. 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions 00006 * are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the copyright holders nor the names of 00014 * contributors may be used to endorse or promote products derived 00015 * from this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS 00018 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00019 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00020 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE 00021 * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00022 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00023 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 00024 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 00025 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00026 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 00027 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00028 * SUCH DAMAGE. 00029 * 00030 * For additional information see http://www.ethernut.de/ 00031 * 00032 */ 00033 00065 #include <stdio.h> 00066 #include <fcntl.h> 00067 #include <io.h> 00068 00069 #include <dev/board.h> 00070 #include <dev/lanc111.h> 00071 #include <dev/debug.h> 00072 #include <dev/pnut.h> 00073 #include <dev/nplmmc.h> 00074 #include <dev/sbimmc.h> 00075 #include <dev/spimmc_at91.h> 00076 #include <dev/at91_mci.h> 00077 #include <dev/x12rtc.h> 00078 #include <fs/phatfs.h> 00079 00080 #include <sys/confnet.h> 00081 #include <sys/version.h> 00082 #include <sys/heap.h> 00083 #include <sys/thread.h> 00084 #include <sys/socket.h> 00085 00086 #include <arpa/inet.h> 00087 #include <netinet/tcp.h> 00088 #include <net/route.h> 00089 #include <pro/dhcp.h> 00090 #include <pro/ftpd.h> 00091 #include <pro/wins.h> 00092 #include <pro/sntp.h> 00093 #include <pro/discover.h> 00094 00095 /* Determine the compiler. */ 00096 #if defined(__IMAGECRAFT__) 00097 #if defined(__AVR__) 00098 #define CC_STRING "ICCAVR" 00099 #else 00100 #define CC_STRING "ICC" 00101 #endif 00102 #elif defined(__GNUC__) 00103 #if defined(__AVR__) 00104 #define CC_STRING "AVRGCC" 00105 #elif defined(__arm__) 00106 #define CC_STRING "ARMGCC" 00107 #else 00108 #define CC_STRING "GCC" 00109 #endif 00110 #else 00111 #define CC_STRING "Compiler unknown" 00112 #endif 00113 00123 /* 00124 * Baudrate for debug output. 00125 */ 00126 #ifndef DBG_BAUDRATE 00127 #define DBG_BAUDRATE 115200 00128 #endif 00129 00130 /* 00131 * Wether we should use DHCP. 00132 */ 00133 #define USE_DHCP 00134 00135 /* 00136 * Wether we should run a discovery responder. 00137 */ 00138 #if defined(__arm__) 00139 #define USE_DISCOVERY 00140 #endif 00141 00142 /* 00143 * Unique MAC address of the Ethernut Board. 00144 * 00145 * Ignored if EEPROM contains a valid configuration. 00146 */ 00147 #define MY_MAC { 0x00, 0x06, 0x98, 0x30, 0x00, 0x35 } 00148 00149 /* 00150 * Unique IP address of the Ethernut Board. 00151 * 00152 * Ignored if DHCP is used. 00153 */ 00154 #define MY_IPADDR "192.168.192.35" 00155 00156 /* 00157 * IP network mask of the Ethernut Board. 00158 * 00159 * Ignored if DHCP is used. 00160 */ 00161 #define MY_IPMASK "255.255.255.0" 00162 00163 /* 00164 * Gateway IP address for the Ethernut Board. 00165 * 00166 * Ignored if DHCP is used. 00167 */ 00168 #define MY_IPGATE "192.168.192.1" 00169 00170 /* 00171 * NetBIOS name. 00172 * 00173 * Use a symbolic name with Win32 Explorer. 00174 */ 00175 //#define MY_WINSNAME "ETHERNUT" 00176 00177 /* 00178 * FTP port number. 00179 */ 00180 #define FTP_PORTNUM 21 00181 00182 /* 00183 * FTP timeout. 00184 * 00185 * The server will terminate the session, if no new command is received 00186 * within the specified number of milliseconds. 00187 */ 00188 #define FTPD_TIMEOUT 600000 00189 00190 /* 00191 * TCP buffer size. 00192 */ 00193 #define TCPIP_BUFSIZ 5840 00194 00195 /* 00196 * Maximum segment size. 00197 * 00198 * Choose 536 up to 1460. Note, that segment sizes above 536 may result 00199 * in fragmented packets. Remember, that Ethernut doesn't support TCP 00200 * fragmentation. 00201 */ 00202 #define TCPIP_MSS 1460 00203 00204 #if defined(ETHERNUT3) 00205 00206 /* Ethernut 3 file system. */ 00207 #define FSDEV devPhat0 00208 #define FSDEV_NAME "PHAT0" 00209 00210 /* Ethernut 3 block device interface. */ 00211 #define BLKDEV devNplMmc0 00212 #define BLKDEV_NAME "MMC0" 00213 00214 #elif defined(AT91SAM7X_EK) 00215 00216 /* SAM7X-EK file system. */ 00217 #define FSDEV devPhat0 00218 #define FSDEV_NAME "PHAT0" 00219 00220 /* SAM7X-EK block device interface. */ 00221 #define BLKDEV devAt91SpiMmc0 00222 #define BLKDEV_NAME "MMC0" 00223 00224 #elif defined(AT91SAM9260_EK) 00225 00226 /* SAM9260-EK file system. */ 00227 #define FSDEV devPhat0 00228 #define FSDEV_NAME "PHAT0" 00229 00230 /* SAM9260-EK block device interface. */ 00231 #define BLKDEV devAt91Mci0 00232 #define BLKDEV_NAME "MCI0" 00233 00234 #elif defined(ETHERNUT2) 00235 00236 /* 00237 * Ethernut 2 File system 00238 */ 00239 #define FSDEV devPnut 00240 #define FSDEV_NAME "PNUT" 00241 00242 #else 00243 00244 #define FSDEV_NAME "NONE" 00245 00246 #endif 00247 00249 #define MYTZ -1 00250 00252 #define MYTIMED "130.149.17.21" 00253 00254 #ifdef ETHERNUT3 00255 00256 #define X12RTC_DEV 00257 #endif 00258 00259 /* 00260 * FTP service. 00261 * 00262 * This function waits for client connect, processes the FTP request 00263 * and disconnects. Nut/Net doesn't support a server backlog. If one 00264 * client has established a connection, further connect attempts will 00265 * be rejected. 00266 * 00267 * Some FTP clients, like the Win32 Explorer, open more than one 00268 * connection for background processing. So we run this routine by 00269 * several threads. 00270 */ 00271 void FtpService(void) 00272 { 00273 TCPSOCKET *sock; 00274 00275 /* 00276 * Create a socket. 00277 */ 00278 if ((sock = NutTcpCreateSocket()) != 0) { 00279 00280 /* 00281 * Set specified socket options. 00282 */ 00283 #ifdef TCPIP_MSS 00284 { 00285 u_short mss = TCPIP_MSS; 00286 NutTcpSetSockOpt(sock, TCP_MAXSEG, &mss, sizeof(mss)); 00287 } 00288 #endif 00289 #ifdef FTPD_TIMEOUT 00290 { 00291 u_long tmo = FTPD_TIMEOUT; 00292 NutTcpSetSockOpt(sock, SO_RCVTIMEO, &tmo, sizeof(tmo)); 00293 } 00294 #endif 00295 #ifdef TCPIP_BUFSIZ 00296 { 00297 u_short siz = TCPIP_BUFSIZ; 00298 NutTcpSetSockOpt(sock, SO_RCVBUF, &siz, sizeof(siz)); 00299 } 00300 #endif 00301 00302 /* 00303 * Listen on our port. If we return, we got a client. 00304 */ 00305 printf("\nWaiting for an FTP client..."); 00306 if (NutTcpAccept(sock, FTP_PORTNUM) == 0) { 00307 printf("%s connected, %u bytes free\n", inet_ntoa(sock->so_remote_addr), (u_int)NutHeapAvailable()); 00308 NutFtpServerSession(sock); 00309 printf("%s disconnected, %u bytes free\n", inet_ntoa(sock->so_remote_addr), (u_int)NutHeapAvailable()); 00310 } else { 00311 puts("Accept failed"); 00312 } 00313 00314 /* 00315 * Close our socket. 00316 */ 00317 NutTcpCloseSocket(sock); 00318 } 00319 } 00320 00321 /* 00322 * FTP service thread. 00323 */ 00324 THREAD(FtpThread, arg) 00325 { 00326 /* Loop endless for connections. */ 00327 for (;;) { 00328 FtpService(); 00329 } 00330 } 00331 00332 /* 00333 * Assign stdout to the UART device. 00334 */ 00335 void InitDebugDevice(void) 00336 { 00337 u_long baud = DBG_BAUDRATE; 00338 00339 NutRegisterDevice(&DEV_DEBUG, 0, 0); 00340 freopen(DEV_DEBUG_NAME, "w", stdout); 00341 _ioctl(_fileno(stdout), UART_SETSPEED, &baud); 00342 } 00343 00344 /* 00345 * Setup the ethernet device. Try DHCP first. If this is 00346 * the first time boot with empty EEPROM and no DHCP server 00347 * was found, use hardcoded values. 00348 */ 00349 int InitEthernetDevice(void) 00350 { 00351 u_long ip_addr = inet_addr(MY_IPADDR); 00352 u_long ip_mask = inet_addr(MY_IPMASK); 00353 u_long ip_gate = inet_addr(MY_IPGATE); 00354 u_char mac[6] = MY_MAC; 00355 00356 if (NutRegisterDevice(&DEV_ETHER, 0x8300, 5)) { 00357 puts("No Ethernet Device"); 00358 return -1; 00359 } 00360 00361 printf("Configure %s...", DEV_ETHER_NAME); 00362 #ifdef USE_DHCP 00363 if (NutDhcpIfConfig(DEV_ETHER_NAME, 0, 60000) == 0) { 00364 puts("OK"); 00365 return 0; 00366 } 00367 printf("initial boot..."); 00368 if (NutDhcpIfConfig(DEV_ETHER_NAME, mac, 60000) == 0) { 00369 puts("OK"); 00370 return 0; 00371 } 00372 #endif 00373 printf("No DHCP..."); 00374 NutNetIfConfig(DEV_ETHER_NAME, mac, ip_addr, ip_mask); 00375 /* Without DHCP we had to set the default gateway manually.*/ 00376 if(ip_gate) { 00377 printf("hard coded gate..."); 00378 NutIpRouteAdd(0, 0, ip_gate, &DEV_ETHER); 00379 } 00380 puts("OK"); 00381 00382 return 0; 00383 } 00384 00385 /* 00386 * Query a time server and optionally update the hardware clock. 00387 */ 00388 static int QueryTimeServer(void) 00389 { 00390 int rc = -1; 00391 00392 #ifdef MYTIMED 00393 { 00394 time_t now; 00395 u_long timeserver = inet_addr(MYTIMED); 00396 00397 /* Query network time service and set the system time. */ 00398 printf("Query time from %s...", MYTIMED); 00399 if(NutSNTPGetTime(×erver, &now) == 0) { 00400 puts("OK"); 00401 rc = 0; 00402 stime(&now); 00403 #ifdef X12RTC_DEV 00404 /* If RTC hardware is available, update it. */ 00405 { 00406 struct _tm *gmt = gmtime(&now); 00407 00408 if (X12RtcSetClock(gmt)) { 00409 puts("RTC update failed"); 00410 } 00411 } 00412 #endif 00413 } 00414 else { 00415 puts("failed"); 00416 } 00417 } 00418 #endif 00419 00420 return rc; 00421 } 00422 00423 /* 00424 * Try to get initial date and time from the hardware clock or a time server. 00425 */ 00426 static int InitTimeAndDate(void) 00427 { 00428 int rc = -1; 00429 00430 /* Set the local time zone. */ 00431 _timezone = MYTZ * 60L * 60L; 00432 00433 #ifdef X12RTC_DEV 00434 /* Query RTC hardware if available. */ 00435 { 00436 u_long rs; 00437 00438 /* Query the status. If it fails, we do not have an RTC. */ 00439 if (X12RtcGetStatus(&rs)) { 00440 puts("No hardware RTC"); 00441 rc = QueryTimeServer(); 00442 } 00443 else { 00444 /* RTC hardware seems to be available. Check for power failure. */ 00445 //rs = RTC_STATUS_PF; 00446 if ((rs & RTC_STATUS_PF) == RTC_STATUS_PF) { 00447 puts("RTC power fail detected"); 00448 rc = QueryTimeServer(); 00449 } 00450 00451 /* RTC hardware status is fine, update our system clock. */ 00452 else { 00453 struct _tm gmt; 00454 00455 /* Assume that RTC is running at GMT. */ 00456 if (X12RtcGetClock(&gmt) == 0) { 00457 time_t now = _mkgmtime(&gmt); 00458 00459 if (now != -1) { 00460 stime(&now); 00461 rc = 0; 00462 } 00463 } 00464 } 00465 } 00466 } 00467 #else 00468 /* No hardware RTC, query the time server if available. */ 00469 rc = QueryTimeServer(); 00470 #endif 00471 return rc; 00472 } 00473 00474 /* 00475 * Main application routine. 00476 * 00477 * Nut/OS automatically calls this entry after initialization. 00478 */ 00479 int main(void) 00480 { 00481 int volid; 00482 u_long ipgate; 00483 00484 /* Initialize a debug output device and print a banner. */ 00485 InitDebugDevice(); 00486 printf("\n\nFTP Server Sample - Nut/OS %s - " CC_STRING "\n", NutVersionString()); 00487 00488 /* Initialize the Ethernet device and print our IP address. */ 00489 if (InitEthernetDevice()) { 00490 for(;;); 00491 } 00492 printf("IP Addr: %s\n", inet_ntoa(confnet.cdn_ip_addr)); 00493 printf("IP Mask: %s\n", inet_ntoa(confnet.cdn_ip_mask)); 00494 NutIpRouteQuery(0, &ipgate); 00495 printf("IP Gate: %s\n", inet_ntoa(ipgate)); 00496 00497 #ifdef USE_DISCOVERY 00498 /* Register a discovery responder. */ 00499 printf("Start Responder..."); 00500 if (NutRegisterDiscovery((u_long)-1, 0, DISF_INITAL_ANN)) { 00501 puts("failed"); 00502 } 00503 else { 00504 puts("OK"); 00505 } 00506 #endif 00507 00508 /* Initialize system clock and calendar. */ 00509 if (InitTimeAndDate() == 0) { 00510 time_t now = time(0); 00511 struct _tm *lot = localtime(&now); 00512 printf("Date: %02u.%02u.%u\n", lot->tm_mday, lot->tm_mon + 1, 1900 + lot->tm_year); 00513 printf("Time: %02u:%02u:%02u\n", lot->tm_hour, lot->tm_min, lot->tm_sec); 00514 } 00515 00516 #ifdef FSDEV 00517 /* Initialize the file system. */ 00518 printf("Register file system..."); 00519 if (NutRegisterDevice(&FSDEV, 0, 0)) { 00520 puts("failed"); 00521 for (;;); 00522 } 00523 puts("OK"); 00524 #endif 00525 00526 #ifdef BLKDEV 00527 /* Register block device. */ 00528 printf("Register block device..."); 00529 if (NutRegisterDevice(&BLKDEV, 0, 0)) { 00530 puts("failed"); 00531 for (;;); 00532 } 00533 puts("OK"); 00534 00535 /* Mount partition. */ 00536 printf("Mounting partition..."); 00537 if ((volid = _open(BLKDEV_NAME ":1/" FSDEV_NAME, _O_RDWR | _O_BINARY)) == -1) { 00538 puts("failed"); 00539 for (;;); 00540 } 00541 puts("OK"); 00542 #else 00543 volid = 0; 00544 #endif 00545 00546 /* Register root path. */ 00547 printf("Register FTP root..."); 00548 if (NutRegisterFtpRoot(FSDEV_NAME ":")) { 00549 puts("failed"); 00550 for (;;); 00551 } 00552 puts("OK"); 00553 00554 /* Start two additional server threads. */ 00555 NutThreadCreate("ftpd0", FtpThread, 0, 1640); 00556 NutThreadCreate("ftpd1", FtpThread, 0, 1640); 00557 00558 /* Main server thread. */ 00559 for (;;) { 00560 #ifdef MY_WINSNAME 00561 NutWinsNameQuery(MY_WINSNAME, confnet.cdn_ip_addr); 00562 #endif 00563 FtpService(); 00564 } 00565 }