BA
/
BaBoRo1
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_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 Tue Jul 12 2022 12:22:17 by
