Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of OmniWheels by
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_event_t, intptr_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 /* status changes have to be reported */ 00211 if (connection_status_cb) { 00212 connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE , NSAPI_STATUS_GLOBAL_UP ); 00213 } 00214 return; 00215 } 00216 00217 /* If some error happened, we need to properly shutdown the PPP interface */ 00218 if (ppp_active) { 00219 ppp_active = false; 00220 connect_error_code = mapped_err_code; 00221 sys_sem_signal(&ppp_close_sem); 00222 } 00223 00224 /* Alright, PPP interface is down, we need to notify upper layer */ 00225 if (connection_status_cb) { 00226 connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE , NSAPI_STATUS_DISCONNECTED ); 00227 } 00228 } 00229 00230 static void handle_modem_hangup() 00231 { 00232 if (my_ppp_pcb->phase != PPP_PHASE_DEAD) { 00233 ppp_close(my_ppp_pcb, 1); 00234 } 00235 } 00236 00237 #if !PPP_INPROC_IRQ_SAFE 00238 #error "PPP_INPROC_IRQ_SAFE must be enabled" 00239 #endif 00240 static void ppp_input() 00241 { 00242 // Allow new events from now, avoiding potential races around the read 00243 event_queued = false; 00244 00245 if (!my_stream) { 00246 return; 00247 } 00248 00249 // Non-blocking error check handler 00250 pollfh fhs; 00251 fhs.fh = my_stream; 00252 fhs.events = POLLIN; 00253 poll(&fhs, 1, 0); 00254 if (fhs.revents & (POLLHUP|POLLERR|POLLNVAL)) { 00255 handle_modem_hangup(); 00256 return; 00257 } 00258 00259 // Infinite loop, but we assume that we can read faster than the 00260 // serial, so we will fairly rapidly hit -EAGAIN. 00261 for (;;) { 00262 u8_t buffer[16]; 00263 ssize_t len = my_stream->read(buffer, sizeof buffer); 00264 if (len == -EAGAIN) { 00265 break; 00266 } else if (len <= 0) { 00267 handle_modem_hangup(); 00268 return; 00269 } 00270 pppos_input(my_ppp_pcb, buffer, len); 00271 } 00272 return; 00273 } 00274 00275 static void stream_cb() { 00276 if (my_stream && !event_queued) { 00277 event_queued = true; 00278 if (event_queue->call(callback(ppp_input)) == 0) { 00279 event_queued = false; 00280 } 00281 } 00282 } 00283 00284 extern "C" err_t ppp_lwip_connect() 00285 { 00286 #if PPP_AUTH_SUPPORT 00287 ppp_set_auth(my_ppp_pcb, PPPAUTHTYPE_ANY, login, pwd); 00288 #endif //PPP_AUTH_SUPPORT 00289 ppp_active = true; 00290 err_t ret = ppp_connect(my_ppp_pcb, 0); 00291 // lwIP's ppp.txt says input must not be called until after connect 00292 if (ret == ERR_OK) { 00293 my_stream->sigio(callback(stream_cb)); 00294 } else { 00295 ppp_active = false; 00296 } 00297 return ret; 00298 } 00299 00300 extern "C" err_t ppp_lwip_disconnect() 00301 { 00302 err_t ret = ppp_close(my_ppp_pcb, 0); 00303 if (ret != ERR_OK) { 00304 return ret; 00305 } 00306 00307 /* close call made, now let's catch the response in the status callback */ 00308 sys_arch_sem_wait(&ppp_close_sem, 0); 00309 00310 /* Detach callbacks, and put handle back to default blocking mode */ 00311 my_stream->sigio(Callback<void()>()); 00312 my_stream->set_blocking(true); 00313 my_stream = NULL; 00314 00315 return ret; 00316 } 00317 00318 extern "C" nsapi_error_t ppp_lwip_if_init(struct netif *netif, const nsapi_ip_stack_t stack) 00319 { 00320 if (!prepare_event_queue()) { 00321 return NSAPI_ERROR_NO_MEMORY ; 00322 } 00323 00324 if (!my_ppp_pcb) { 00325 my_ppp_pcb = pppos_create(netif, 00326 ppp_output, ppp_link_status, NULL); 00327 if (!my_ppp_pcb) { 00328 return NSAPI_ERROR_DEVICE_ERROR ; 00329 } 00330 00331 sys_sem_new(&ppp_close_sem, 0); 00332 } 00333 00334 #if LWIP_IPV4 00335 if (stack != IPV6_STACK) { 00336 ppp_set_usepeerdns(my_ppp_pcb, true); 00337 } 00338 #endif 00339 00340 #if LWIP_IPV4 && LWIP_IPV6 00341 if (stack == IPV4_STACK) { 00342 my_ppp_pcb->ipv6cp_disabled = true; 00343 } else if (stack == IPV6_STACK) { 00344 my_ppp_pcb->ipcp_disabled = true; 00345 } 00346 #endif 00347 00348 return NSAPI_ERROR_OK ; 00349 } 00350 00351 nsapi_error_t nsapi_ppp_error_code() 00352 { 00353 return connect_error_code; 00354 } 00355 00356 nsapi_error_t nsapi_ppp_set_blocking(bool blocking) 00357 { 00358 mbed_lwip_set_blocking(blocking); 00359 return NSAPI_ERROR_OK ; 00360 } 00361 00362 nsapi_error_t nsapi_ppp_connect(FileHandle *stream, Callback<void(nsapi_event_t, intptr_t)> cb, const char *uname, const char *password, const nsapi_ip_stack_t stack) 00363 { 00364 if (my_stream) { 00365 return NSAPI_ERROR_PARAMETER ; 00366 } 00367 my_stream = stream; 00368 stream->set_blocking(false); 00369 connection_status_cb = cb; 00370 login = uname; 00371 pwd = password; 00372 00373 // mustn't start calling input until after connect - 00374 // attach deferred until ppp_lwip_connect, called from mbed_lwip_bringup 00375 nsapi_error_t retcode = mbed_lwip_bringup_2(false, true, NULL, NULL, NULL, stack); 00376 00377 if (retcode != NSAPI_ERROR_OK && connect_error_code != NSAPI_ERROR_OK ) { 00378 return connect_error_code; 00379 } else { 00380 return retcode; 00381 } 00382 } 00383 00384 nsapi_error_t nsapi_ppp_disconnect(FileHandle *stream) 00385 { 00386 return mbed_lwip_bringdown_2(true); 00387 } 00388 00389 NetworkStack *nsapi_ppp_get_stack() 00390 { 00391 return nsapi_create_stack(&lwip_stack); 00392 } 00393 00394 const char *nsapi_ppp_get_ip_addr(FileHandle *stream) 00395 { 00396 static char ip_addr[IPADDR_STRLEN_MAX]; 00397 00398 if (stream == my_stream) { 00399 00400 if (mbed_lwip_get_ip_address(ip_addr, IPADDR_STRLEN_MAX)) { 00401 return ip_addr; 00402 } 00403 } 00404 00405 return NULL; 00406 } 00407 const char *nsapi_ppp_get_netmask(FileHandle *stream) 00408 { 00409 #if !LWIP_IPV4 00410 return NULL; 00411 #endif 00412 00413 static char netmask[IPADDR_STRLEN_MAX]; 00414 if (stream == my_stream) { 00415 if (mbed_lwip_get_netmask(netmask, IPADDR_STRLEN_MAX)) { 00416 return netmask; 00417 } 00418 } 00419 00420 return NULL; 00421 } 00422 const char *nsapi_ppp_get_gw_addr(FileHandle *stream) 00423 { 00424 #if !LWIP_IPV4 00425 return NULL; 00426 #endif 00427 00428 static char gwaddr[IPADDR_STRLEN_MAX]; 00429 if (stream == my_stream) { 00430 if (mbed_lwip_get_gateway(gwaddr, IPADDR_STRLEN_MAX)) { 00431 return gwaddr; 00432 } 00433 } 00434 00435 return NULL; 00436 } 00437 00438 #endif /* LWIP_PPP_API */ 00439 00440 } // namespace mbed
Generated on Fri Jul 22 2022 04:53:58 by
1.7.2
