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