Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers NanostackPPPInterface.cpp Source File

NanostackPPPInterface.cpp

00001 /*
00002  * Copyright (c) 2019 ARM Limited
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "NanostackPPPInterface.h"
00019 #include "NanostackPPPPhy.h"
00020 #include "PPP.h"
00021 #include "nsdynmemLIB.h"
00022 #include "arm_hal_phy.h"
00023 #include "mbed_interface.h"
00024 #include "mesh_system.h"
00025 #include "callback_handler.h"
00026 #include "enet_tasklet.h"
00027 #include "ip6string.h"
00028 
00029 class PPPPhy : public NanostackPPPPhy {
00030 public:
00031     PPPPhy(NanostackMemoryManager &mem, PPP &m);
00032     virtual int8_t phy_register();
00033 
00034     virtual void phy_power_on();
00035     virtual void phy_power_off();
00036 
00037     virtual void get_iid64(uint8_t *iid64);
00038     virtual uint16_t get_mtu();
00039 
00040     virtual void set_link_state_change_cb(link_state_change_cb_t cb);
00041 
00042     int8_t tx(uint8_t *data_ptr, uint16_t data_len, uint8_t tx_handle, data_protocol_e data_flow);
00043 
00044     void ppp_phy_rx(net_stack_mem_buf_t *mem);
00045     void link_state_cb(bool up);
00046 
00047 private:
00048     NanostackMemoryManager &memory_manager;
00049     PPP &ppp;
00050     uint8_t iid64[8];
00051     link_state_change_cb_t link_state_change_cb;
00052     bool active;
00053     bool powered_up;
00054     int8_t device_id;
00055     phy_device_driver_s phy;
00056 };
00057 
00058 nsapi_error_t Nanostack::PPPInterface::initialize()
00059 {
00060     nanostack_lock();
00061 
00062     if (register_phy() < 0) {
00063         nanostack_unlock();
00064         return NSAPI_ERROR_DEVICE_ERROR ;
00065     }
00066 
00067     nanostack_unlock();
00068 
00069     return NSAPI_ERROR_OK ;
00070 }
00071 
00072 nsapi_error_t Nanostack::PPPInterface::bringup(bool dhcp, const char *ip,
00073                                                const char *netmask, const char *gw,
00074                                                nsapi_ip_stack_t stack, bool blocking)
00075 {
00076     if (stack == IPV4_STACK) {
00077         return NSAPI_ERROR_UNSUPPORTED ;
00078     }
00079 
00080     _blocking = blocking;
00081 
00082     if (link_state_up) {
00083         connect_enet_tasklet();
00084     }
00085 
00086     if (blocking) {
00087         uint8_t retries = 10;
00088         while (_connect_status != NSAPI_STATUS_GLOBAL_UP ) {
00089             int32_t count = connect_semaphore.try_acquire_for(3000);
00090             if (count <= 0 && retries-- == 0) {
00091                 return NSAPI_ERROR_DHCP_FAILURE ; // sort of...
00092             }
00093             // Not up until global up
00094             if (_connect_status == NSAPI_STATUS_LOCAL_UP ) {
00095                 _connect_status = NSAPI_STATUS_CONNECTING ;
00096             }
00097         }
00098     }
00099 
00100     return NSAPI_ERROR_OK ;
00101 }
00102 
00103 nsapi_error_t Nanostack::PPPInterface::connect_enet_tasklet()
00104 {
00105     if (enet_tasklet_connected) {
00106         return NSAPI_ERROR_OK ;
00107     }
00108 
00109     enet_tasklet_connected = true;
00110 
00111     nanostack_lock();
00112 
00113     if (interface_id < 0) {
00114         enet_tasklet_init();
00115         __mesh_handler_set_callback(this);
00116         interface_id = enet_tasklet_ppp_network_init(_device_id);
00117     }
00118     int8_t status = -1;
00119     if (interface_id >= 0) {
00120         status = enet_tasklet_connect(&__mesh_handler_c_callback, interface_id);
00121     }
00122 
00123     nanostack_unlock();
00124 
00125     if (status == -1) {
00126         return NSAPI_ERROR_DEVICE_ERROR ;
00127     } else if (status == -2) {
00128         return NSAPI_ERROR_NO_MEMORY ;
00129     } else if (status == -3) {
00130         return NSAPI_ERROR_ALREADY ;
00131     } else if (status != 0) {
00132         return NSAPI_ERROR_DEVICE_ERROR ;
00133     }
00134 
00135     return NSAPI_ERROR_OK ;
00136 }
00137 
00138 nsapi_error_t Nanostack::PPPInterface::bringdown()
00139 {
00140     nanostack_lock();
00141     int8_t status = enet_tasklet_disconnect(true);
00142     enet_tasklet_connected = false;
00143     nanostack_unlock();
00144 
00145     if (status == -1) {
00146         return NSAPI_ERROR_DEVICE_ERROR ;
00147     } else if (status == -2) {
00148         return NSAPI_ERROR_NO_MEMORY ;
00149     } else if (status == -3) {
00150         return NSAPI_ERROR_ALREADY ;
00151     } else if (status != 0) {
00152         return NSAPI_ERROR_DEVICE_ERROR ;
00153     }
00154 
00155     if (_blocking) {
00156         int32_t count = disconnect_semaphore.try_acquire_for(30000);
00157 
00158         if (count <= 0) {
00159             return NSAPI_ERROR_TIMEOUT ;
00160         }
00161     }
00162     return NSAPI_ERROR_OK ;
00163 }
00164 
00165 void Nanostack::PPPInterface::link_state_changed(bool up)
00166 {
00167     link_state_up = up;
00168 
00169     // If application callback is set
00170     if (link_state_cb) {
00171         link_state_cb(up, _device_id);
00172     } else {
00173         if (up) {
00174             connect_enet_tasklet();
00175         }
00176     }
00177 }
00178 
00179 void Nanostack::PPPInterface::set_link_state_changed_callback(link_state_cb_t new_link_state_cb)
00180 {
00181     link_state_cb = new_link_state_cb;
00182 }
00183 
00184 // GAH! no handles on the callback. Force a single interface
00185 static PPPPhy *single_phy;
00186 
00187 extern "C"
00188 {
00189     static int8_t ppp_phy_interface_state_control(phy_interface_state_e, uint8_t)
00190     {
00191         return -1;
00192     }
00193 
00194     static int8_t ppp_phy_tx(uint8_t *data_ptr, uint16_t data_len, uint8_t tx_handle, data_protocol_e data_flow)
00195     {
00196         return single_phy->tx(data_ptr, data_len, tx_handle, data_flow);
00197     }
00198 
00199     PPPPhy::PPPPhy(NanostackMemoryManager &mem, PPP &m) : memory_manager(mem), ppp(m), link_state_change_cb(NULL), active(false), powered_up(false), device_id(-1)
00200     {
00201     }
00202 
00203     void PPPPhy::ppp_phy_rx(net_stack_mem_buf_t *mem)
00204     {
00205         if (!active) {
00206             memory_manager.free(mem);
00207             return;
00208         }
00209 
00210         const uint8_t *ptr = NULL;
00211         uint8_t *tmpbuf = NULL;
00212         uint32_t total_len;
00213 
00214         if (memory_manager.get_next(mem) == NULL) {
00215             // Easy contiguous case
00216             ptr = static_cast<const uint8_t *>(memory_manager.get_ptr(mem));
00217             total_len = memory_manager.get_len(mem);
00218         } else {
00219             // Nanostack can't accept chunked data - make temporary contiguous copy
00220             total_len = memory_manager.get_total_len(mem);
00221             ptr = tmpbuf = static_cast<uint8_t *>(ns_dyn_mem_temporary_alloc(total_len));
00222             if (tmpbuf) {
00223                 memory_manager.copy_from_buf(tmpbuf, total_len, mem);
00224             }
00225         }
00226 
00227         if (ptr && phy.phy_rx_cb) {
00228             phy.phy_rx_cb(ptr, total_len, 0xff, 0, device_id);
00229         }
00230         ns_dyn_mem_free(tmpbuf);
00231         memory_manager.free(mem);
00232     }
00233 
00234 } // extern "C"
00235 
00236 int8_t PPPPhy::tx(uint8_t *data_ptr, uint16_t data_len, uint8_t tx_handle, data_protocol_e data_flow)
00237 {
00238     if (!active) {
00239         return -1;
00240     }
00241 
00242     net_stack_mem_buf_t *mem = memory_manager.alloc_pool(data_len, 0);
00243     if (!mem) {
00244         return -1;
00245     }
00246     memory_manager.copy_to_buf(mem, data_ptr, data_len);
00247 
00248     // They take ownership - their responsibility to free
00249     ppp.link_out(mem, IPV6_STACK);
00250 
00251     return 0;
00252 }
00253 
00254 int8_t PPPPhy::phy_register()
00255 {
00256     active = true;
00257 
00258     if (device_id < 0) {
00259         phy.PHY_MAC = iid64;
00260         phy.address_write = NULL;
00261         phy.driver_description = const_cast<char *>("PPP");
00262         phy.link_type = PHY_LINK_PPP;
00263         phy.phy_MTU = 0;
00264         phy.phy_header_length = 0;
00265         phy.phy_tail_length = 0;
00266         phy.state_control = ppp_phy_interface_state_control;
00267         phy.tx = ppp_phy_tx;
00268         phy.phy_rx_cb = NULL;
00269         phy.phy_tx_done_cb = NULL;
00270 
00271         ppp.set_memory_manager(memory_manager);
00272         ppp.set_link_input_cb(mbed::callback(this, &PPPPhy::ppp_phy_rx));
00273         if (link_state_change_cb) {
00274             ppp.set_link_state_cb(mbed::callback(this, &PPPPhy::link_state_cb));
00275         }
00276 
00277         device_id = arm_net_phy_register(&phy);
00278 
00279         if (device_id < 0) {
00280             return -1;
00281         }
00282     }
00283 
00284     return device_id;
00285 }
00286 
00287 void PPPPhy::phy_power_on()
00288 {
00289     if (!powered_up) {
00290         if (!ppp.power_up()) {
00291             return;
00292         }
00293         phy.phy_MTU = get_mtu();
00294         powered_up = true;
00295         active = true;
00296     }
00297 }
00298 
00299 void PPPPhy::phy_power_off()
00300 {
00301     if (powered_up) {
00302         ppp.power_down();
00303         powered_up = false;
00304     }
00305     active = false;
00306 }
00307 
00308 void PPPPhy::set_link_state_change_cb(link_state_change_cb_t cb)
00309 {
00310     link_state_change_cb = cb;
00311 }
00312 
00313 void PPPPhy::link_state_cb(bool up)
00314 {
00315     // Read negotiated parameters from PPP
00316     if (up) {
00317         get_iid64(iid64);
00318     }
00319 
00320     // Call upper level callback if set
00321     if (link_state_change_cb) {
00322         link_state_change_cb(up);
00323     }
00324 }
00325 
00326 void PPPPhy::get_iid64(uint8_t *iid64)
00327 {
00328     if (!iid64) {
00329         return;
00330     }
00331 
00332     // Read link local IPv6 address
00333     const nsapi_addr_t *ipv6_ll_addr = ppp.get_ip_address(NSAPI_IPv6 );
00334     if (ipv6_ll_addr) {
00335         memcpy(iid64, &ipv6_ll_addr->bytes[8], 8);
00336     }
00337 }
00338 
00339 uint16_t PPPPhy::get_mtu()
00340 {
00341     return ppp.get_mtu_size();
00342 }
00343 
00344 nsapi_error_t Nanostack::add_ppp_interface(PPP &ppp, bool default_if, Nanostack::PPPInterface **interface_out)
00345 {
00346     if (!single_phy) {
00347         single_phy = new (std::nothrow) PPPPhy(this->memory_manager, ppp);
00348         if (!single_phy) {
00349             return NSAPI_ERROR_NO_MEMORY ;
00350         }
00351     }
00352 
00353     static Nanostack::PPPInterface *interface = NULL;
00354 
00355     if (interface == NULL) {
00356         interface = new (std::nothrow) Nanostack::PPPInterface(*single_phy);
00357         if (!interface) {
00358             return NSAPI_ERROR_NO_MEMORY ;
00359         }
00360 
00361         single_phy->set_link_state_change_cb(mbed::callback(interface, &Nanostack::PPPInterface::link_state_changed));
00362     }
00363 
00364     interface->initialize();
00365 
00366     single_phy->phy_power_on();
00367 
00368     *interface_out = interface;
00369 
00370     return NSAPI_ERROR_OK ;
00371 }
00372 
00373 nsapi_error_t Nanostack::add_ppp_interface(PPP &ppp, bool default_if, OnboardNetworkStack::Interface **interface_out)
00374 {
00375     Nanostack::PPPInterface *interface;
00376     nsapi_error_t err = add_ppp_interface(ppp, default_if, &interface);
00377     *interface_out = interface;
00378     return err;
00379 }
00380 
00381 nsapi_error_t Nanostack::remove_ppp_interface(OnboardNetworkStack::Interface **interface_out)
00382 {
00383     single_phy->phy_power_off();
00384 
00385     return NSAPI_ERROR_OK ;
00386 }