#include "lwip/opt.h" #include "lwip/netif.h" #include "lwip/dns.h" #include "lwip/tcpip.h" #include "lwip/ip.h" #include "lwip/priv/tcpip_priv.h" #include "lwip/priv/api_msg.h" #include "wificliif.h" #include "psifapi.h" #ifdef FEATURE_WIFI_SWITCH_ENABLE extern UlPduBlock* NetifUlGetOnePkg(UlPduBlock *pUlHdr, UlPduBlock **ppOnePkgHead, UlPduBlock **ppOnePkgTail, UINT16 *pPkgLen); extern void* PsDlPkgAlloc(UINT32 wantedSize); extern void PsifInitPsDlPkgPbuf(DlPduBlock *pDlPduBlk); extern UINT16 NetifCopyDataFromUlPdu(UINT8 *payload, UlPduBlock *pUlPdu); extern void NetifDumpDlPduPacket(DlPduBlock *dlData, UINT8 type); WifiCliUlPkgPendingList gWifiCliUlpkgPendingList = {0}; wifiCliOutputFunc wifiOutPutCustFunc = NULL; void UlPduAddList(UlPduBlock **ppHdr, UlPduBlock **ppTailer, UlPduBlock *pNewHdr, UlPduBlock *pNewTailer) { if ((*ppHdr) == PNULL) { OsaCheck((*ppTailer) == PNULL && (pNewHdr) != PNULL && ((pNewTailer)->pNext) == PNULL, (*ppTailer), ((pNewTailer)->pNext), 0x12345678); (*ppHdr) = (pNewHdr); (*ppTailer) = (pNewTailer); } else { OsaCheck((*ppTailer) != PNULL && (pNewHdr) != PNULL && ((pNewTailer)->pNext) == PNULL, (*ppTailer), ((pNewTailer)->pNext), 0x87654321); (*ppTailer)->pNext = (pNewHdr); (*ppTailer) = (pNewTailer); } } /****************************************************************************** * wifi_cli_ulPkg_ListGet * Description: Get all UL PDU list from "gWifiCliUlpkgPendingList" * input: * ppHead //in & out * output: * Comment: this called in LWIP task ******************************************************************************/ static void wifi_cli_ulPkg_ListGet(UlPduBlock **ppHead) { WifiCliUlPkgPendingList *pPendingList = PNULL; UINT32 mask = 0; OsaCheck(ppHead != PNULL, ppHead, 0, 0); *ppHead = PNULL; mask = SaveAndSetIRQMask(); pPendingList = &gWifiCliUlpkgPendingList; if (pPendingList != PNULL) { if (pPendingList->pHead != PNULL) { OsaCheck(pPendingList->pTail != PNULL && pPendingList->pTail->pNext == PNULL, pPendingList->pTail, 0, 0); *ppHead = pPendingList->pHead; } pPendingList->pHead = pPendingList->pTail = PNULL; pPendingList->pkgNum = 0; } RestoreIRQMask(mask); return; } /****************************************************************************** * wifi_cli_ul_output * Description: Just pass UL raw IP pkg to wifi client * input: struct netif *netif, * struct pbuf *p, * output: * Comment: * Current only support pass ether PKG one by one ******************************************************************************/ err_t wifi_cli_ul_output(struct netif *netif, struct pbuf *p) { DlPduBlock *pDlPdu = PNULL; UINT16 totalLen = 0; UINT8 *pBuf = PNULL; //check PPP link state if(!netif_is_link_up(netif)) { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_cli_ul_output_if_down, P_WARNING, 0, "wifi cli if is not link up"); return ERR_IF; } if (p->tot_len > netif->mtu) { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_cli_ul_output_1, P_WARNING, 3, "UL pkg Len: %d > MTU: %d, ignore this pkg", p->tot_len, netif->mtu); return ERR_ARG; } totalLen = LLLNK_DLPDU_CONSUMED_SIZE(LWIP_PBUF_STRUCT_LEN + sizeof(DlPduBlock) + p->tot_len); pBuf = (UINT8 *)PsDlPkgAlloc(totalLen); if (pBuf == PNULL) { return ERR_MEM; } pDlPdu = (DlPduBlock *)(pBuf + LWIP_PBUF_STRUCT_LEN); memset(pDlPdu, 0x00, sizeof(DlPduBlock)); DL_PDU_BLOCK_SET_MAGIC_WORD(pDlPdu); pDlPdu->length = p->tot_len; pDlPdu->pPdu = pBuf + LWIP_PBUF_STRUCT_LEN + sizeof(DlPduBlock) + LLLNK_DLPDU_RSVD_HDR_SIZE; pDlPdu->dlMemType = DL_PS_PKG_MEM; pDlPdu->pbufBefore = TRUE; pDlPdu->bNetHdrRsvd = FALSE; /* init pbuf struct */ PsifInitPsDlPkgPbuf(pDlPdu); /* copy this ip pkg */ pbuf_copy_partial(p, (void *)pDlPdu->pPdu, p->tot_len, 0); //dump pkg for debug NetifDumpDlPduPacket(pDlPdu, LWIP_NETIF_TYPE_WAN_INTERNET); //need add send the dlpdu to wifi client // and wifi client process this dlpdu, must call PsifFreeDlIpPkgBlockList(pDlPdu); if(wifiOutPutCustFunc) { wifiOutPutCustFunc(0, pDlPdu); } else { OsaFreeDlPduBlockList(&pDlPdu); } return ERR_OK; } /****************************************************************************** * wifi_cli_ip4_output * Description: Just pass UL raw IPv4 pkg to wifi client * input: struct netif *netif, * struct pbuf *p, * output: * Comment: * Current only support pass ether PKG one by one ******************************************************************************/ static err_t wifi_cli_ip4_output(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) { // todo:you can add some check function return wifi_cli_ul_output(netif, p); } /****************************************************************************** * wifi_cli_ip6_output * Description: Just pass UL raw IPv6 pkg to wifi client * input: struct netif *netif, * struct pbuf *p, * output: * Comment: * Current only support pass ether PKG one by one ******************************************************************************/ static err_t wifi_cli_ip6_output(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) { // todo:you can add some check function return wifi_cli_ul_output(netif, p); } /****************************************************************************** * wifi_cli_netif_init * Description: wifi client netif init * input: struct netif *netif, * output: * Comment: * ******************************************************************************/ err_t wifi_cli_netif_init(struct netif *netif) { if(!netif) return ERR_ARG; //init netif name netif->name[0] = WIFI_CLI_NETIF_PREFIX_NAME; netif->name[1] = WIFI_CLI_NETIF_NAME; //init ipv4 & ipv6 output function netif->output = wifi_cli_ip4_output; netif->primary_ipv4_cid = LWIP_PS_INVALID_CID; #if LWIP_IPV6 netif->output_ip6 = wifi_cli_ip6_output; netif->primary_ipv6_cid = LWIP_PS_INVALID_CID; #endif /* LWIP_IPV6 */ netif->linkoutput = wifi_cli_ul_output; #if LWIP_IGMP netif->flags &= NETIF_FLAG_IGMP; #endif #if LWIP_IPV6_MLD netif->flags &= NETIF_FLAG_MLD6; #endif return ERR_OK; } /****************************************************************************** * wifi_client_wan_linkup_callback * Description: wifi client wan linkup call back * input: NmWifiCliConfiguration *conf * output: * Comment: * ******************************************************************************/ err_t wifi_client_wan_linkup_callback(NmWifiCliConfiguration *conf) { struct netif *wifi_cli_netif = NULL; ip4_addr_t wifi_netif_netmask; u8_t i; if(conf == NULL) { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_linkup_callback_1, P_WARNING, 0, "invalid argument"); } //check whether wifi wan has linkup wifi_cli_netif = netif_get_adpt_netif(LWIP_NETIF_TYPE_WAN_WIFI); if(wifi_cli_netif != NULL) { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_linkup_callback_2, P_INFO, 0, "wifi wan has linkup"); return ERR_OK; } // alloc netif structure wifi_cli_netif = mem_malloc(sizeof(struct netif)); if (wifi_cli_netif == NULL) { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_linkup_callback_mem_1, P_WARNING, 0, "LAN link type %u, can't alloc mem for netif"); return ERR_MEM; } memset(wifi_cli_netif, 0, sizeof(struct netif)); wifi_cli_netif->primary_ipv4_cid = LWIP_PS_INVALID_CID; wifi_cli_netif->primary_ipv6_cid = LWIP_PS_INVALID_CID; /* init netif mtu, MTU size suggest could config by AT - TBD */ wifi_cli_netif->mtu = (conf->mtu == 0)?LAN_NETIF_DEFAULT_MTU : conf->mtu; if(conf->ipv4NetMaskPresent) { ip4_addr_copy(wifi_netif_netmask, conf->ipv4NetMask); } else { IP4_ADDR(&wifi_netif_netmask, 255, 255, 255, 255); } //register LAN netif to tcpip stack netif_add(wifi_cli_netif, IP4_ADDR_ANY4, &wifi_netif_netmask, IP4_ADDR_ANY4, NULL, wifi_cli_netif_init, NULL); /* set the wan type */ netif_set_netif_type(wifi_cli_netif, LWIP_NETIF_TYPE_WAN_WIFI); netif_set_link_up(wifi_cli_netif); //ipv4 if(conf->ipType == NM_NET_TYPE_IPV4 || conf->ipType == NM_NET_TYPE_IPV4V6) { //set ipv4 address netif_set_ipaddr(wifi_cli_netif, &conf->ipv4Addr); //set ipv4 dns server if(conf->dnsNum > 0) { for (i = 0; i < conf->dnsNum; i++) { if(IP_IS_V4_VAL(conf->dns[i]) && (!ip_addr_isany(&conf->dns[i]))) { dns_setserver(wifi_cli_netif, &conf->dns[i]); } } } netif_set_type_up(wifi_cli_netif, NETIF_REPORT_TYPE_IPV4); } //ipv6 if(conf->ipType == NM_NET_TYPE_IPV6 || conf->ipType == NM_NET_TYPE_IPV4V6) { //set ipv6 linklocal address netif_ip6_addr_set(wifi_cli_netif, 0, &conf->ipv6LinkLocalAddr); netif_ip6_addr_set_state(wifi_cli_netif, 0, IP6_ADDR_VALID); //set ipv6 global address netif_ip6_addr_set(wifi_cli_netif, 1, &conf->ipv6GlobalAddr); /* Set address state. */ #if LWIP_IPV6_DUP_DETECT_ATTEMPTS /* Will perform duplicate address detection (DAD). */ netif_ip6_addr_set_state(wifi_cli_netif, 1, IP6_ADDR_TENTATIVE); #else /* Consider address valid. */ netif_ip6_addr_set_state(wifi_cli_netif, 1, IP6_ADDR_PREFERRED); #endif //set ipv6 dns server if(conf->dnsNum > 0) { for (i = 0; i < conf->dnsNum; i++) { if(IP_IS_V6_VAL(conf->dns[i]) && (!ip_addr_isany(&conf->dns[i]))) { dns_setserver(wifi_cli_netif, &conf->dns[i]); } } } netif_set_type_up(wifi_cli_netif, NETIF_REPORT_TYPE_IPV6); } //set default if(conf->bDefault) { netif_set_default(wifi_cli_netif); } ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_linkup_callback_3, P_INFO, 0, "wifi cli wan linkup"); return ERR_OK; } /****************************************************************************** * wifi_client_wan_linkdown_callback * Description: wifi client wan linkdown call back * input: * output: * Comment: * ******************************************************************************/ err_t wifi_client_wan_linkdown_callback(void) { struct netif *wifi_cli_netif = NULL; //check whether wifi wan has linkup wifi_cli_netif = netif_get_adpt_netif(LWIP_NETIF_TYPE_WAN_WIFI); if(wifi_cli_netif == NULL) { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_linkdown_callback_1, P_INFO, 0, "wifi cli wan has linkdown"); return ERR_OK; } dns_clearserver(wifi_cli_netif, IPADDR_TYPE_V4); dns_clearserver(wifi_cli_netif ,IPADDR_TYPE_V6); #if LINK_DOWN_NEED_CLEAR_DNS_CACHE dns_clear_cache(IPADDR_TYPE_V4); dns_clear_cache(IPADDR_TYPE_V6); #endif netif_remove(wifi_cli_netif); mem_free(wifi_cli_netif); ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_linkdown_callback_2, P_INFO, 0, "wifi cli wan linkdown"); return ERR_OK; } /****************************************************************************** * wifi_client_wan_default_route_change_callback * Description: wifi client wan default route change call back * input: * output: * Comment: * ******************************************************************************/ err_t wifi_client_wan_default_route_change_callback(NmWanNetDefaultChangeInfo *pInfo) { struct netif *netif = NULL; if(pInfo == NULL) { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_default_route_change_callback_1, P_ERROR, 0, "invalid argu"); return ERR_ARG; } else if(pInfo->type != NM_WAN_NET_PS_CAT1 && pInfo->type != NM_WAN_NET_WIFI_CLI) { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_default_route_change_callback_type_1, P_ERROR, 1, "invalid type %u", pInfo->type); return ERR_ARG; } if(pInfo->type == NM_WAN_NET_PS_CAT1) { if(LWIP_CHECK_CID_VALID(pInfo->cid)) { netif = netif_find_by_cid(pInfo->cid); if(netif == NULL) { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_default_route_change_callback_2, P_ERROR, 1, "can not find netif by cid %u", pInfo->cid); return ERR_ARG; } else { netif_set_default(netif); } } else { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_default_route_change_callback_3, P_ERROR, 1, "invalid cid %u", pInfo->cid); return ERR_ARG; } } else if(pInfo->type == NM_WAN_NET_WIFI_CLI) { netif = netif_get_adpt_netif(LWIP_NETIF_TYPE_WAN_WIFI); if(netif == NULL) { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_default_route_change_callback_4, P_ERROR, 0, "can not find wifi client netif"); return ERR_ARG; } else { netif_set_default(netif); } } ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_client_wan_default_route_change_callback_5, P_INFO, 2, "wifi wan default change to type %u ,cid &u", pInfo->type, pInfo->cid); return ERR_OK; } /****************************************************************************** * wifi_cli_wan_tcpip_input * Description: * input: u8_t wanType, UlPduBlock *pPduHdr * output:UINT8 * Comment: ******************************************************************************/ err_t wifi_cli_wan_tcpip_input(u8_t wanType) { struct netif *inp = PNULL; struct pbuf *p = PNULL; UlPduBlock *pUlPduTmp = PNULL, *pUlPduTmpNext = PNULL; UlPduBlock *pOnePkgHead = PNULL, *pOnePkgTail = PNULL; UINT16 pduTotalLen = 0; UlPduBlock *pPduHdr = PNULL; OsaDebugBegin(wanType == LWIP_NETIF_TYPE_WAN_WIFI, 0, wanType, 0); return ERR_ARG; OsaDebugEnd(); wifi_cli_ulPkg_ListGet(&pPduHdr); inp = netif_get_adpt_netif(LWIP_NETIF_TYPE_WAN_WIFI); if (inp == PNULL) { ECOMM_TRACE_I(UNILOG_TCPIP_NETADPT, wifi_cli_wan_tcpip_input_1, P_ERROR, 0, "wifi cli netif recv wan pkg, but can not find adpt netif, type %u", wanType); if(pPduHdr != PNULL) { OsaFreeUlPduBlockList(&pPduHdr); } return ERR_ARG; } for (pUlPduTmp = pPduHdr; pUlPduTmp != PNULL;) { pUlPduTmpNext = NetifUlGetOnePkg(pUlPduTmp, &pOnePkgHead, &pOnePkgTail, &pduTotalLen); //ToDo:could improve(zero copy) p = pbuf_alloc(PBUF_RAW, pduTotalLen, PBUF_RAM); if (p == PNULL) { ECOMM_TRACE_I(UNILOG_TCPIP_NETADPT, wifi_cli_wan_tcpip_input_2, P_ERROR, 1, "wifi cli recv wan pkg, but allocate pbuf free, dicard the pkglen: %d", pduTotalLen); OsaFreeUlPduBlockList(&pUlPduTmp); pUlPduTmp = pUlPduTmpNext; continue; } else { p->tot_len = NetifCopyDataFromUlPdu(p->payload, pUlPduTmp); OsaFreeUlPduBlockList(&pUlPduTmp); } //dump pkg for debug netif_dump_dl_packet(p->payload, p->tot_len, LWIP_NETIF_TYPE_WAN_INTERNET); ps_ip_input(p, inp); pUlPduTmp = pUlPduTmpNext; } return ERR_OK; } /****************************************************************************** * wifi_cli_wan_recv_ul_pkg * Description: wifi client wan netif low level input function * input: void * output: * Comment: ******************************************************************************/ err_t wifi_cli_wan_pkg_notify(void) { err_t ret; ret = TcpipWanInpkt(LWIP_NETIF_TYPE_WAN_WIFI, wifi_cli_wan_tcpip_input); if (ret != ERR_OK) { ECOMM_TRACE(UNILOG_TCPIP_NETADPT, wifi_cli_wan_pkg_notify_1, P_ERROR, 1, "wifi_cli_wan_pkg_notify fail"); return ret; //msg memory alloc fail or can not find netif by lcid } return ERR_OK; } /****************************************************************************** * wifi_cli_ul_listinput * Description: * input: * output: * Comment: * ******************************************************************************/ void wifi_cli_ul_listinput(UINT16 pkgNum, UlPduBlock *pHead, UlPduBlock *pTail) { UINT32 mask = 0, inIsr = osIsInISRContext(), needNotify = 0; WifiCliUlPkgPendingList *pPendingList = PNULL; OsaCheck(pHead != PNULL && pTail != PNULL && pTail->pNext == PNULL && pkgNum > 0, pHead, pTail, pkgNum); if (!inIsr) { mask = SaveAndSetIRQMask(); } pPendingList = &gWifiCliUlpkgPendingList; //OsaCheck(pPendingList != PNULL, cid, 0, 0); if(pPendingList->pHead == PNULL) { needNotify = 1; } /* Link */ UlPduAddList(&pPendingList->pHead, &pPendingList->pTail, pHead, pTail); pPendingList->pkgNum += pkgNum; if (!inIsr) { RestoreIRQMask(mask); } if (needNotify) { wifi_cli_wan_pkg_notify(); } return; } void wifi_cli_output_set_cust_func(BOOL isRegister, wifiCliOutputFunc custOutputFunc) { if(isRegister) wifiOutPutCustFunc = custOutputFunc; else wifiOutPutCustFunc = NULL; } #endif