static inline struct pbuf *netfront_init_rxpbuf(struct net_rxbuffer *buf, struct netfront_dev *dev) { struct pbuf *p; p = pbuf_alloced_custom(PBUF_RAW, PAGE_SIZE, PBUF_REF, &buf->cpbuf, buf->page, PAGE_SIZE); if (p == NULL) return NULL; buf->dev = dev; buf->cpbuf.custom_free_function = netfront_free_rxpbuf; return p; }
static struct pbuf* pcapif_rx_ref(struct pbuf* p) { struct pcapif_pbuf_custom* ppc; struct pbuf* q; LWIP_ASSERT("NULL pointer", p != NULL); LWIP_ASSERT("chained pbuf not supported here", p->next == NULL); ppc = (struct pcapif_pbuf_custom*)mem_malloc(sizeof(struct pcapif_pbuf_custom)); LWIP_ASSERT("out of memory for RX", ppc != NULL); ppc->pc.custom_free_function = pcapif_rx_pbuf_free_custom; ppc->p = p; q = pbuf_alloced_custom(PBUF_RAW, p->tot_len, PBUF_REF, &ppc->pc, p->payload, p->tot_len); LWIP_ASSERT("pbuf_alloced_custom returned NULL", q != NULL); return q; }
void eth_rx_irq() { dma_descriptor* dma_desc = get_RX_DMA_descriptor_from_ethernet(); my_custom_pbuf_t* my_pbuf = (my_custom_pbuf_t*)LWIP_MEMPOOL_ALLOC(RX_POOL); my_pbuf->p.custom_free_function = my_pbuf_free_custom; my_pbuf->dma_descriptor = dma_desc; invalidate_cpu_cache(dma_desc->rx_data, dma_desc->rx_length); struct pbuf* p = pbuf_alloced_custom(PBUF_RAW, dma_desc->rx_length, PBUF_REF, &my_pbuf->p, dma_desc->rx_data, dma_desc->max_buffer_size); if(netif->input(p, netif) != ERR_OK) { pbuf_free(p); } }
/** * Fragment an IP datagram if too large for the netif. * * Chop the datagram in MTU sized chunks and send them in order * by using a fixed size static memory buffer (PBUF_REF) or * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF). * * @param p ip packet to send * @param netif the netif on which to send * @param dest destination ip address to which to send * * @return ERR_OK if sent successfully, err_t otherwise */ err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest) { struct pbuf *rambuf; #if IP_FRAG_USES_STATIC_BUF struct pbuf *header; #else #if !LWIP_NETIF_TX_SINGLE_PBUF struct pbuf *newpbuf; #endif struct ip_hdr *original_iphdr; #endif struct ip_hdr *iphdr; u16_t nfb; u16_t left, cop; u16_t mtu = netif->mtu; u16_t ofo, omf; u16_t last; u16_t poff = IP_HLEN; u16_t tmp; #if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF u16_t newpbuflen = 0; u16_t left_to_copy; #endif /* Get a RAM based MTU sized pbuf */ #if IP_FRAG_USES_STATIC_BUF /* When using a static buffer, we use a PBUF_REF, which we will * use to reference the packet (without link header). * Layer and length is irrelevant. */ rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF); if (rambuf == NULL) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n")); return ERR_MEM; } rambuf->tot_len = rambuf->len = mtu; rambuf->payload = LWIP_MEM_ALIGN((void *)buf); /* Copy the IP header in it */ iphdr = (struct ip_hdr *)rambuf->payload; SMEMCPY(iphdr, p->payload, IP_HLEN); #else /* IP_FRAG_USES_STATIC_BUF */ original_iphdr = (struct ip_hdr *)p->payload; iphdr = original_iphdr; #endif /* IP_FRAG_USES_STATIC_BUF */ /* Save original offset */ tmp = ntohs(IPH_OFFSET(iphdr)); ofo = tmp & IP_OFFMASK; omf = tmp & IP_MF; left = p->tot_len - IP_HLEN; nfb = (mtu - IP_HLEN) / 8; while (left) { last = (left <= mtu - IP_HLEN); /* Set new offset and MF flag */ tmp = omf | (IP_OFFMASK & (ofo)); if (!last) { tmp = tmp | IP_MF; } /* Fill this fragment */ cop = last ? left : nfb * 8; #if IP_FRAG_USES_STATIC_BUF poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff); #else /* IP_FRAG_USES_STATIC_BUF */ #if LWIP_NETIF_TX_SINGLE_PBUF rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM); if (rambuf == NULL) { return ERR_MEM; } LWIP_ASSERT("this needs a pbuf in one piece!", (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); poff += pbuf_copy_partial(p, rambuf->payload, cop, poff); /* make room for the IP header */ if(pbuf_header(rambuf, IP_HLEN)) { pbuf_free(rambuf); return ERR_MEM; } /* fill in the IP header */ SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); iphdr = rambuf->payload; #else /* LWIP_NETIF_TX_SINGLE_PBUF */ /* When not using a static buffer, create a chain of pbufs. * The first will be a PBUF_RAM holding the link and IP header. * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, * but limited to the size of an mtu. */ rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM); if (rambuf == NULL) { return ERR_MEM; } LWIP_ASSERT("this needs a pbuf in one piece!", (p->len >= (IP_HLEN))); SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); iphdr = (struct ip_hdr *)rambuf->payload; /* Can just adjust p directly for needed offset. */ p->payload = (u8_t *)p->payload + poff; p->len -= poff; left_to_copy = cop; while (left_to_copy) { struct pbuf_custom_ref *pcr; newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; /* Is this pbuf already empty? */ if (!newpbuflen) { p = p->next; continue; } pcr = ip_frag_alloc_pbuf_custom_ref(); if (pcr == NULL) { pbuf_free(rambuf); return ERR_MEM; } /* Mirror this pbuf, although we might not need all of it. */ newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); if (newpbuf == NULL) { ip_frag_free_pbuf_custom_ref(pcr); pbuf_free(rambuf); return ERR_MEM; } pbuf_ref(p); pcr->original = p; pcr->pc.custom_free_function = ipfrag_free_pbuf_custom; /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain * so that it is removed when pbuf_dechain is later called on rambuf. */ pbuf_cat(rambuf, newpbuf); left_to_copy -= newpbuflen; if (left_to_copy) { p = p->next; } } poff = newpbuflen; #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ #endif /* IP_FRAG_USES_STATIC_BUF */ /* Correct header */ IPH_OFFSET_SET(iphdr, htons(tmp)); IPH_LEN_SET(iphdr, htons(cop + IP_HLEN)); IPH_CHKSUM_SET(iphdr, 0); IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); #if IP_FRAG_USES_STATIC_BUF if (last) { pbuf_realloc(rambuf, left + IP_HLEN); } /* This part is ugly: we alloc a RAM based pbuf for * the link level header for each chunk and then * free it.A PBUF_ROM style pbuf for which pbuf_header * worked would make things simpler. */ header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM); if (header != NULL) { pbuf_chain(header, rambuf); netif->output(netif, header, dest); IPFRAG_STATS_INC(ip_frag.xmit); snmp_inc_ipfragcreates(); pbuf_free(header); } else { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n")); pbuf_free(rambuf); return ERR_MEM; } #else /* IP_FRAG_USES_STATIC_BUF */ /* No need for separate header pbuf - we allowed room for it in rambuf * when allocated. */ netif->output(netif, rambuf, dest); IPFRAG_STATS_INC(ip_frag.xmit); /* Unfortunately we can't reuse rambuf - the hardware may still be * using the buffer. Instead we free it (and the ensuing chain) and * recreate it next time round the loop. If we're lucky the hardware * will have already sent the packet, the free will really free, and * there will be zero memory penalty. */ pbuf_free(rambuf); #endif /* IP_FRAG_USES_STATIC_BUF */ left -= cop; ofo += nfb; } #if IP_FRAG_USES_STATIC_BUF pbuf_free(rambuf); #endif /* IP_FRAG_USES_STATIC_BUF */ snmp_inc_ipfragoks(); return ERR_OK; }
/** * Receive callback function for TCP connect. */ static err_t net_tcp_recv_cb(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { struct tls_netconn *conn; struct tls_netconn *server_conn = NULL; err_t err_ret = ERR_OK; u16 datalen = 0; #if (RAW_SOCKET_USE_CUSTOM_PBUF) struct raw_sk_pbuf_custom *pcr = NULL; struct pbuf *newpbuf = NULL; #endif struct pbuf *p_tmp,*p_next; // TLS_DBGPRT_INFO("net_tcp_recv_cb err=%d\n", err); LWIP_UNUSED_ARG(pcb); LWIP_ASSERT("must have a pcb argument", pcb != NULL); LWIP_ASSERT("must have an argument", arg != NULL); conn = (struct tls_netconn *)arg; LWIP_ASSERT("tcp recv for wrong pcb!", conn->pcb.tcp == pcb); if (err) { /* tcp is disconnect */ TLS_DBGPRT_INFO("err code = %d\n", err); err_ret = err; #if 0 if (conn->pcb.tcp != NULL) { tcp_arg(conn->pcb.tcp, NULL); tcp_accept(conn->pcb.tcp, NULL); tcp_recv(conn->pcb.tcp, NULL); tcp_sent(conn->pcb.tcp, NULL); tcp_poll(conn->pcb.tcp, NULL, 4); tcp_err(conn->pcb.tcp, NULL); tcp_close(conn->pcb.tcp); conn->state = NETCONN_STATE_NONE; net_send_event_to_hostif(conn, NET_EVENT_TCP_DISCONNECT); conn->pcb.tcp = NULL; net_free_socket(conn); } #endif if(conn->skd != NULL && conn->skd->recvf != NULL) { TLS_DBGPRT_INFO("conn->skd->recvf to call."); err_ret = conn->skd->recvf(conn->skt_num, p, err); if(err_ret == ERR_ABRT) tcp_abort(pcb); } if (p){ pbuf_free(p); p = NULL; } return err_ret; } if (pcb == NULL ||conn == NULL) {//p == NULL || TLS_DBGPRT_INFO("pcb = 0x%x, p = 0x%x\n", pcb ,p); return ERR_VAL; } if(p == NULL) { TLS_DBGPRT_ERR("received 0\n"); net_tcp_err_cb(conn, ERR_OK); return ERR_OK; } #if 0//(RAW_SOCKET_USE_CUSTOM_PBUF) pcr = raw_sk_alloc_pbuf_custom(); if(pcr == NULL) { return ERR_MEM; } //newpbuf = pbuf_alloced_custom(PBUF_RAW, p->tot_len, PBUF_REF, &pcr->pc, p->payload, p->tot_len); //使用上面的函数,当pbuf是链表结构时会被截断导致应用层拷贝数据出错 newpbuf = &(pcr->pc); newpbuf->len = 0; newpbuf->payload = NULL; newpbuf->tot_len = p->tot_len; newpbuf->next = p; newpbuf->flags = PBUF_FLAG_IS_CUSTOM; newpbuf->type = PBUF_REF; newpbuf->ref =1; if (newpbuf == NULL) { raw_sk_free_pbuf_custom(pcr); return ERR_MEM; } pcr->original = p; pcr->param = pcb; pcr->pc.custom_free_function = raw_sk_free_pbuf_custom_fn; #endif #if !RAW_SOCKET_USE_CUSTOM_PBUF tcp_recved(pcb, p->tot_len); #endif if(conn->client && conn->idle_time > 0) { TLS_DBGPRT_INFO("conn->skt_num=%d, conn->client=%d\n", conn->skt_num, conn->client); // server_conn = dl_list_first(&conn->list, struct tls_netconn, list); server_conn = get_server_conn(conn); TLS_DBGPRT_INFO("server_conn=%p\n", server_conn); if(server_conn) { conn->idle_time = server_conn->idle_time; TLS_DBGPRT_INFO("update conn->idle_time %d\n", conn->idle_time); } } if(conn->skd->recvf != NULL) { tls_net_set_sourceip(pcb->remote_ip.addr); datalen = p->tot_len; p_next = p; for(p_tmp = p; p_tmp != NULL; ) { p_next = p_tmp->next; p_tmp->next = NULL; //把后面的pbuf截断 if(p_next != NULL) printf("\npbufcat p next=%d\n",p_next); #if (RAW_SOCKET_USE_CUSTOM_PBUF) pcr = raw_sk_alloc_pbuf_custom(); if(pcr == NULL) { return ERR_MEM; } newpbuf = pbuf_alloced_custom(PBUF_RAW, p_tmp->len, PBUF_REF, &pcr->pc, p_tmp->payload, p_tmp->len); if (newpbuf == NULL) { raw_sk_free_pbuf_custom(pcr); return ERR_MEM; } pcr->original = p_tmp; pcr->param = pcb; pcr->pc.custom_free_function = raw_sk_free_pbuf_custom_fn; conn->skd->recvf(conn->skt_num, newpbuf, ERR_OK); #else conn->skd->recvf(conn->skt_num, p_tmp, ERR_OK); #endif p_tmp = p_next; } if (conn->skd->recvwithipf != NULL){ conn->skd->recvwithipf(conn->skt_num, datalen, (u8 *)(&(pcb->remote_ip.addr)), pcb->remote_port, ERR_OK); } } else { #if 0//(RAW_SOCKET_USE_CUSTOM_PBUF) raw_sk_free_pbuf_custom(pcr); #endif if (p) pbuf_free(p); } return err_ret; }
/** * Fragment an IPv6 datagram if too large for the netif or path MTU. * * Chop the datagram in MTU sized chunks and send them in order * by pointing PBUF_REFs into p * * @param p ipv6 packet to send * @param netif the netif on which to send * @param dest destination ipv6 address to which to send * * @return ERR_OK if sent successfully, err_t otherwise */ err_t ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest) { struct ip6_hdr *original_ip6hdr; struct ip6_hdr *ip6hdr; struct ip6_frag_hdr *frag_hdr; struct pbuf *rambuf; #if !LWIP_NETIF_TX_SINGLE_PBUF struct pbuf *newpbuf; u16_t newpbuflen = 0; u16_t left_to_copy; #endif static u32_t identification; u16_t nfb; u16_t left, cop; u16_t mtu; u16_t fragment_offset = 0; u16_t last; u16_t poff = IP6_HLEN; identification++; original_ip6hdr = (struct ip6_hdr *)p->payload; mtu = nd6_get_destination_mtu(dest, netif); /* @todo we assume there are no options in the unfragmentable part (IPv6 header). */ left = p->tot_len - IP6_HLEN; nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK; while (left) { last = (left <= nfb); /* Fill this fragment */ cop = last ? left : nfb; #if LWIP_NETIF_TX_SINGLE_PBUF rambuf = pbuf_alloc(PBUF_IP, cop + IP6_FRAG_HLEN, PBUF_RAM); if (rambuf == NULL) { IP6_FRAG_STATS_INC(ip6_frag.memerr); return ERR_MEM; } LWIP_ASSERT("this needs a pbuf in one piece!", (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); poff += pbuf_copy_partial(p, (u8_t*)rambuf->payload + IP6_FRAG_HLEN, cop, poff); /* make room for the IP header */ if (pbuf_header(rambuf, IP6_HLEN)) { pbuf_free(rambuf); IP6_FRAG_STATS_INC(ip6_frag.memerr); return ERR_MEM; } /* fill in the IP header */ SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); ip6hdr = (struct ip6_hdr *)rambuf->payload; frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); #else /* When not using a static buffer, create a chain of pbufs. * The first will be a PBUF_RAM holding the link, IPv6, and Fragment header. * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, * but limited to the size of an mtu. */ rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM); if (rambuf == NULL) { IP6_FRAG_STATS_INC(ip6_frag.memerr); return ERR_MEM; } LWIP_ASSERT("this needs a pbuf in one piece!", (p->len >= (IP6_HLEN))); SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); ip6hdr = (struct ip6_hdr *)rambuf->payload; frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); /* Can just adjust p directly for needed offset. */ p->payload = (u8_t *)p->payload + poff; p->len -= poff; p->tot_len -= poff; left_to_copy = cop; while (left_to_copy) { struct pbuf_custom_ref *pcr; newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; /* Is this pbuf already empty? */ if (!newpbuflen) { p = p->next; continue; } pcr = ip6_frag_alloc_pbuf_custom_ref(); if (pcr == NULL) { pbuf_free(rambuf); IP6_FRAG_STATS_INC(ip6_frag.memerr); return ERR_MEM; } /* Mirror this pbuf, although we might not need all of it. */ newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); if (newpbuf == NULL) { ip6_frag_free_pbuf_custom_ref(pcr); pbuf_free(rambuf); IP6_FRAG_STATS_INC(ip6_frag.memerr); return ERR_MEM; } pbuf_ref(p); pcr->original = p; pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom; /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain * so that it is removed when pbuf_dechain is later called on rambuf. */ pbuf_cat(rambuf, newpbuf); left_to_copy -= newpbuflen; if (left_to_copy) { p = p->next; } } poff = newpbuflen; #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ /* Set headers */ frag_hdr->_nexth = original_ip6hdr->_nexth; frag_hdr->reserved = 0; frag_hdr->_fragment_offset = lwip_htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG)); frag_hdr->_identification = lwip_htonl(identification); IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT); IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN); /* No need for separate header pbuf - we allowed room for it in rambuf * when allocated. */ IP6_FRAG_STATS_INC(ip6_frag.xmit); netif->output_ip6(netif, rambuf, dest); /* Unfortunately we can't reuse rambuf - the hardware may still be * using the buffer. Instead we free it (and the ensuing chain) and * recreate it next time round the loop. If we're lucky the hardware * will have already sent the packet, the free will really free, and * there will be zero memory penalty. */ pbuf_free(rambuf); left -= cop; fragment_offset += cop; } return ERR_OK; }