Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
ppp_lwip.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2016 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include <errno.h> 00018 #include "platform/FileHandle.h" 00019 #include "platform/mbed_poll.h" 00020 #include "events/EventQueue.h" 00021 #if defined(FEATURE_COMMON_PAL) 00022 #include "mbed_trace.h" 00023 #define TRACE_GROUP "LPPP" 00024 #else 00025 #define tr_debug(...) (void(0)) //dummies if feature common pal is not added 00026 #define tr_info(...) (void(0)) //dummies if feature common pal is not added 00027 #define tr_error(...) (void(0)) //dummies if feature common pal is not added 00028 #endif //defined(FEATURE_COMMON_PAL) 00029 #include "rtos/Thread.h" 00030 #include "lwip/tcpip.h" 00031 #include "lwip/tcp.h" 00032 #include "lwip/ip.h" 00033 #include "lwip/dns.h" 00034 #include "lwip/pbuf.h" 00035 extern "C" { // "pppos.h" is missing extern C 00036 #include "netif/ppp/pppapi.h" 00037 } 00038 00039 #include "nsapi_ppp.h" 00040 #include "ppp_lwip.h" 00041 #include "lwip_stack.h" 00042 00043 namespace mbed { 00044 00045 using rtos::Thread; 00046 using events::EventQueue; 00047 00048 #if LWIP_PPP_API 00049 00050 static EventQueue *event_queue; 00051 static Thread *event_thread; 00052 static volatile bool event_queued; 00053 static nsapi_error_t connect_error_code; 00054 00055 // Just one interface for now 00056 static FileHandle *my_stream; 00057 static ppp_pcb *my_ppp_pcb; 00058 static bool ppp_active = false; 00059 static const char *login; 00060 static const char *pwd; 00061 static sys_sem_t ppp_close_sem; 00062 static Callback<void(nsapi_error_t)> connection_status_cb; 00063 00064 static EventQueue *prepare_event_queue() 00065 { 00066 if (event_queue) { 00067 return event_queue; 00068 } 00069 00070 // Should be trying to get a global shared event queue here! 00071 // Shouldn't have to be making a private thread! 00072 00073 // Only need to queue 2 events. new blows on failure. 00074 event_queue = new EventQueue(2 * EVENTS_EVENT_SIZE, NULL); 00075 event_thread = new Thread(osPriorityNormal, PPP_THREAD_STACK_SIZE); 00076 00077 if (event_thread->start(callback(event_queue, &EventQueue::dispatch_forever)) != osOK) { 00078 delete event_thread; 00079 delete event_queue; 00080 return NULL; 00081 } 00082 00083 return event_queue; 00084 } 00085 00086 static u32_t ppp_output(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) 00087 { 00088 FileHandle *stream = my_stream; 00089 if (!stream) { 00090 return 0; 00091 } 00092 00093 pollfh fhs; 00094 fhs.fh = stream; 00095 fhs.events = POLLOUT; 00096 00097 // LWIP expects us to block on write 00098 // File handle will be in non-blocking mode, because of read events. 00099 // Therefore must use poll to achieve the necessary block for writing. 00100 00101 uint32_t written = 0; 00102 while (len != 0) { 00103 // Block forever until we're selected - don't care about reason we wake; 00104 // return from write should tell us what's up. 00105 poll(&fhs, 1, -1); 00106 // This write will be non-blocking, but blocking would be fine. 00107 ssize_t ret = stream->write(data, len); 00108 if (ret == -EAGAIN) { 00109 continue; 00110 } else if (ret < 0) { 00111 break; 00112 } 00113 written += ret; 00114 data += ret; 00115 len -= ret; 00116 } 00117 00118 // /tr_debug("> %ld bytes of data written\n", (long) written); 00119 00120 return written; 00121 } 00122 00123 static void ppp_link_status(ppp_pcb *pcb, int err_code, void *ctx) 00124 { 00125 nsapi_error_t mapped_err_code = NSAPI_ERROR_NO_CONNECTION ; 00126 00127 switch(err_code) { 00128 case PPPERR_NONE: 00129 mapped_err_code = NSAPI_ERROR_OK ; 00130 tr_info("status_cb: Connected"); 00131 #if PPP_IPV4_SUPPORT 00132 tr_debug(" our_ipaddr = %s", ipaddr_ntoa(&ppp_netif(pcb)->ip_addr)); 00133 tr_debug(" his_ipaddr = %s", ipaddr_ntoa(&ppp_netif(pcb)->gw)); 00134 tr_debug(" netmask = %s", ipaddr_ntoa(&ppp_netif(pcb)->netmask)); 00135 #if LWIP_DNS 00136 const ip_addr_t *ns; 00137 ns = dns_getserver(0); 00138 if (ns) { 00139 tr_debug(" dns1 = %s", ipaddr_ntoa(ns)); 00140 } 00141 ns = dns_getserver(1); 00142 if (ns) { 00143 tr_debug(" dns2 = %s", ipaddr_ntoa(ns)); 00144 } 00145 #endif /* LWIP_DNS */ 00146 #endif /* PPP_IPV4_SUPPORT */ 00147 #if PPP_IPV6_SUPPORT 00148 tr_debug(" our6_ipaddr = %s", ip6addr_ntoa(netif_ip6_addr(ppp_netif(pcb), 0))); 00149 #endif /* PPP_IPV6_SUPPORT */ 00150 break; 00151 00152 case PPPERR_PARAM: 00153 tr_info("status_cb: Invalid parameter"); 00154 break; 00155 00156 case PPPERR_OPEN: 00157 tr_info("status_cb: Unable to open PPP session"); 00158 break; 00159 00160 case PPPERR_DEVICE: 00161 tr_info("status_cb: Invalid I/O device for PPP"); 00162 break; 00163 00164 case PPPERR_ALLOC: 00165 tr_info("status_cb: Unable to allocate resources"); 00166 break; 00167 00168 case PPPERR_USER: 00169 tr_info("status_cb: User interrupt"); 00170 break; 00171 00172 case PPPERR_CONNECT: 00173 tr_info("status_cb: Connection lost"); 00174 mapped_err_code = NSAPI_ERROR_CONNECTION_LOST ; 00175 break; 00176 00177 case PPPERR_AUTHFAIL: 00178 tr_info("status_cb: Failed authentication challenge"); 00179 mapped_err_code = NSAPI_ERROR_AUTH_FAILURE ; 00180 break; 00181 00182 case PPPERR_PROTOCOL: 00183 tr_info("status_cb: Failed to meet protocol"); 00184 break; 00185 00186 case PPPERR_PEERDEAD: 00187 tr_info("status_cb: Connection timeout"); 00188 mapped_err_code = NSAPI_ERROR_CONNECTION_TIMEOUT ; 00189 break; 00190 00191 case PPPERR_IDLETIMEOUT: 00192 tr_info("status_cb: Idle Timeout"); 00193 break; 00194 00195 case PPPERR_CONNECTTIME: 00196 tr_info("status_cb: Max connect time reached"); 00197 break; 00198 00199 case PPPERR_LOOPBACK: 00200 tr_info("status_cb: Loopback detected"); 00201 break; 00202 00203 default: 00204 tr_info("status_cb: Unknown error code %d", err_code); 00205 break; 00206 00207 } 00208 00209 if (err_code == PPPERR_NONE) { 00210 /* suppress generating a callback event for connection up 00211 * Because connect() call is blocking, why wait for a callback */ 00212 return; 00213 } 00214 00215 /* If some error happened, we need to properly shutdown the PPP interface */ 00216 if (ppp_active) { 00217 ppp_active = false; 00218 connect_error_code = mapped_err_code; 00219 sys_sem_signal(&ppp_close_sem); 00220 } 00221 00222 /* Alright, PPP interface is down, we need to notify upper layer */ 00223 if (connection_status_cb) { 00224 connection_status_cb(mapped_err_code); 00225 } 00226 } 00227 00228 static void handle_modem_hangup() 00229 { 00230 if (my_ppp_pcb->phase != PPP_PHASE_DEAD) { 00231 ppp_close(my_ppp_pcb, 1); 00232 } 00233 } 00234 00235 #if !PPP_INPROC_IRQ_SAFE 00236 #error "PPP_INPROC_IRQ_SAFE must be enabled" 00237 #endif 00238 static void ppp_input() 00239 { 00240 // Allow new events from now, avoiding potential races around the read 00241 event_queued = false; 00242 00243 if (!my_stream) { 00244 return; 00245 } 00246 00247 // Non-blocking error check handler 00248 pollfh fhs; 00249 fhs.fh = my_stream; 00250 fhs.events = POLLIN; 00251 poll(&fhs, 1, 0); 00252 if (fhs.revents & (POLLHUP|POLLERR|POLLNVAL)) { 00253 handle_modem_hangup(); 00254 return; 00255 } 00256 00257 // Infinite loop, but we assume that we can read faster than the 00258 // serial, so we will fairly rapidly hit -EAGAIN. 00259 for (;;) { 00260 u8_t buffer[16]; 00261 ssize_t len = my_stream->read(buffer, sizeof buffer); 00262 if (len == -EAGAIN) { 00263 break; 00264 } else if (len <= 0) { 00265 handle_modem_hangup(); 00266 return; 00267 } 00268 pppos_input(my_ppp_pcb, buffer, len); 00269 } 00270 return; 00271 } 00272 00273 static void stream_cb() { 00274 if (my_stream && !event_queued) { 00275 event_queued = true; 00276 if (event_queue->call(callback(ppp_input)) == 0) { 00277 event_queued = false; 00278 } 00279 } 00280 } 00281 00282 extern "C" err_t ppp_lwip_connect() 00283 { 00284 #if PPP_AUTH_SUPPORT 00285 ppp_set_auth(my_ppp_pcb, PPPAUTHTYPE_ANY, login, pwd); 00286 #endif //PPP_AUTH_SUPPORT 00287 ppp_active = true; 00288 err_t ret = ppp_connect(my_ppp_pcb, 0); 00289 // lwIP's ppp.txt says input must not be called until after connect 00290 if (ret == ERR_OK) { 00291 my_stream->sigio(callback(stream_cb)); 00292 } else { 00293 ppp_active = false; 00294 } 00295 return ret; 00296 } 00297 00298 extern "C" err_t ppp_lwip_disconnect() 00299 { 00300 err_t ret = ppp_close(my_ppp_pcb, 0); 00301 if (ret != ERR_OK) { 00302 return ret; 00303 } 00304 00305 /* close call made, now let's catch the response in the status callback */ 00306 sys_arch_sem_wait(&ppp_close_sem, 0); 00307 00308 /* Detach callbacks, and put handle back to default blocking mode */ 00309 my_stream->sigio(Callback<void()>()); 00310 my_stream->set_blocking(true); 00311 my_stream = NULL; 00312 00313 return ret; 00314 } 00315 00316 extern "C" nsapi_error_t ppp_lwip_if_init(struct netif *netif, const nsapi_ip_stack_t stack) 00317 { 00318 if (!prepare_event_queue()) { 00319 return NSAPI_ERROR_NO_MEMORY ; 00320 } 00321 00322 if (!my_ppp_pcb) { 00323 my_ppp_pcb = pppos_create(netif, 00324 ppp_output, ppp_link_status, NULL); 00325 if (!my_ppp_pcb) { 00326 return NSAPI_ERROR_DEVICE_ERROR ; 00327 } 00328 00329 sys_sem_new(&ppp_close_sem, 0); 00330 } 00331 00332 #if LWIP_IPV4 00333 if (stack != IPV6_STACK) { 00334 ppp_set_usepeerdns(my_ppp_pcb, true); 00335 } 00336 #endif 00337 00338 #if LWIP_IPV4 && LWIP_IPV6 00339 if (stack == IPV4_STACK) { 00340 my_ppp_pcb->ipv6cp_disabled = true; 00341 } else if (stack == IPV6_STACK) { 00342 my_ppp_pcb->ipcp_disabled = true; 00343 } 00344 #endif 00345 00346 return NSAPI_ERROR_OK ; 00347 } 00348 00349 nsapi_error_t nsapi_ppp_error_code() 00350 { 00351 return connect_error_code; 00352 } 00353 00354 nsapi_error_t nsapi_ppp_connect(FileHandle *stream, Callback<void(nsapi_error_t)> cb, const char *uname, const char *password, const nsapi_ip_stack_t stack) 00355 { 00356 if (my_stream) { 00357 return NSAPI_ERROR_PARAMETER ; 00358 } 00359 my_stream = stream; 00360 stream->set_blocking(false); 00361 connection_status_cb = cb; 00362 login = uname; 00363 pwd = password; 00364 00365 // mustn't start calling input until after connect - 00366 // attach deferred until ppp_lwip_connect, called from mbed_lwip_bringup 00367 nsapi_error_t retcode = mbed_lwip_bringup_2(false, true, NULL, NULL, NULL, stack); 00368 00369 if (retcode != NSAPI_ERROR_OK && connect_error_code != NSAPI_ERROR_OK ) { 00370 return connect_error_code; 00371 } else { 00372 return retcode; 00373 } 00374 } 00375 00376 nsapi_error_t nsapi_ppp_disconnect(FileHandle *stream) 00377 { 00378 return mbed_lwip_bringdown_2(true); 00379 } 00380 00381 NetworkStack *nsapi_ppp_get_stack() 00382 { 00383 return nsapi_create_stack(&lwip_stack); 00384 } 00385 00386 const char *nsapi_ppp_get_ip_addr(FileHandle *stream) 00387 { 00388 static char ip_addr[IPADDR_STRLEN_MAX]; 00389 00390 if (stream == my_stream) { 00391 00392 if (mbed_lwip_get_ip_address(ip_addr, IPADDR_STRLEN_MAX)) { 00393 return ip_addr; 00394 } 00395 } 00396 00397 return NULL; 00398 } 00399 const char *nsapi_ppp_get_netmask(FileHandle *stream) 00400 { 00401 #if !LWIP_IPV4 00402 return NULL; 00403 #endif 00404 00405 static char netmask[IPADDR_STRLEN_MAX]; 00406 if (stream == my_stream) { 00407 if (mbed_lwip_get_netmask(netmask, IPADDR_STRLEN_MAX)) { 00408 return netmask; 00409 } 00410 } 00411 00412 return NULL; 00413 } 00414 const char *nsapi_ppp_get_gw_addr(FileHandle *stream) 00415 { 00416 #if !LWIP_IPV4 00417 return NULL; 00418 #endif 00419 00420 static char gwaddr[IPADDR_STRLEN_MAX]; 00421 if (stream == my_stream) { 00422 if (mbed_lwip_get_gateway(gwaddr, IPADDR_STRLEN_MAX)) { 00423 return gwaddr; 00424 } 00425 } 00426 00427 return NULL; 00428 } 00429 00430 #endif /* LWIP_PPP_API */ 00431 00432 } // namespace mbed
Generated on Sun Jul 17 2022 08:25:29 by 1.7.2