/*-----------------------------------------------------------------------------------*/ err_t netconn_listen(struct netconn *conn) { struct api_msg *msg; if (conn == NULL) { return ERR_VAL; } if (conn->acceptmbox == SYS_MBOX_NULL) { conn->acceptmbox = sys_mbox_new(); if (conn->acceptmbox == SYS_MBOX_NULL) { return ERR_MEM; } } if ((msg = memp_mallocp(MEMP_API_MSG)) == NULL) { return (conn->err = ERR_MEM); } msg->type = API_MSG_LISTEN; msg->msg.conn = conn; api_msg_post(msg); sys_mbox_fetch(conn->mbox, NULL); memp_freep(MEMP_API_MSG, msg); return conn->err; }
/*-----------------------------------------------------------------------------------*/ struct netconn *netconn_new(enum netconn_type t) { struct netconn *conn; conn = memp_mallocp(MEMP_NETCONN); if (conn == NULL) { return NULL; } conn->type = t; conn->pcb.tcp = NULL; if ((conn->mbox = sys_mbox_new()) == SYS_MBOX_NULL) { memp_freep(MEMP_NETCONN, conn); return NULL; } conn->recvmbox = SYS_MBOX_NULL; conn->acceptmbox = SYS_MBOX_NULL; conn->sem = SYS_SEM_NULL; conn->state = NETCONN_NONE; conn->socket = 0; conn->callback = 0; conn->recv_avail = 0; return conn; }
/*-----------------------------------------------------------------------------------*/ err_t netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port) { struct api_msg *msg; if (conn == NULL) { return ERR_VAL; } if (conn->recvmbox == SYS_MBOX_NULL) { if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) { return ERR_MEM; } } if ((msg = memp_mallocp(MEMP_API_MSG)) == NULL) { return ERR_MEM; } msg->type = API_MSG_CONNECT; msg->msg.conn = conn; msg->msg.msg.bc.ipaddr = addr; msg->msg.msg.bc.port = port; api_msg_post(msg); sys_mbox_fetch(conn->mbox, NULL); memp_freep(MEMP_API_MSG, msg); return conn->err; }
/*-----------------------------------------------------------------------------------*/ err_t netconn_send(struct netconn *conn, struct netbuf *buf) { struct api_msg *msg; if (conn == NULL) { return ERR_VAL; } if (conn->err != ERR_OK) { return conn->err; } if ((msg = memp_mallocp(MEMP_API_MSG)) == NULL) { return (conn->err = ERR_MEM); } DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %ld bytes\n", buf->p->tot_len)); msg->type = API_MSG_SEND; msg->msg.conn = conn; msg->msg.msg.p = buf->p; api_msg_post(msg); sys_mbox_fetch(conn->mbox, NULL); memp_freep(MEMP_API_MSG, msg); return conn->err; }
/*-----------------------------------------------------------------------------------*/ err_t netconn_close(struct netconn *conn) { struct api_msg *msg; if (conn == NULL) { return ERR_VAL; } if ((msg = memp_mallocp(MEMP_API_MSG)) == NULL) { return (conn->err = ERR_MEM); } conn->state = NETCONN_CLOSE; again: msg->type = API_MSG_CLOSE; msg->msg.conn = conn; api_msg_post(msg); sys_mbox_fetch(conn->mbox, NULL); if (conn->err == ERR_MEM && conn->sem != SYS_SEM_NULL) { sys_sem_wait(conn->sem); goto again; } conn->state = NETCONN_NONE; memp_freep(MEMP_API_MSG, msg); return conn->err; }
static void recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) { struct netbuf *buf; struct netconn *conn; conn = arg; if (conn == NULL) { pbuf_free(p); return; } if (conn->recvmbox != SYS_MBOX_NULL) { buf = memp_mallocp(MEMP_NETBUF); if (buf == NULL) { pbuf_free(p); return; } else { buf->p = p; buf->ptr = p; buf->fromaddr = addr; buf->fromport = port; } conn->recv_avail += p->tot_len; /* Register event with callback */ if (conn->callback) (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len); sys_mbox_post(conn->recvmbox, buf); } }
/*-----------------------------------------------------------------------------------*/ static err_t accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) { sys_mbox_t mbox; struct netconn *newconn; struct netconn *conn; #if API_MSG_DEBUG #if TCP_DEBUG tcp_debug_print_state(newpcb->state); #endif /* TCP_DEBUG */ #endif /* API_MSG_DEBUG */ conn = (struct netconn *)arg; mbox = conn->acceptmbox; newconn = memp_mallocp(MEMP_NETCONN); if (newconn == NULL) { return ERR_MEM; } newconn->type = NETCONN_TCP; newconn->pcb.tcp = newpcb; setup_tcp(newconn); newconn->recvmbox = sys_mbox_new(); if (newconn->recvmbox == SYS_MBOX_NULL) { memp_free(MEMP_NETCONN, newconn); return ERR_MEM; } newconn->mbox = sys_mbox_new(); if (newconn->mbox == SYS_MBOX_NULL) { sys_mbox_free(newconn->recvmbox); memp_free(MEMP_NETCONN, newconn); return ERR_MEM; } newconn->sem = sys_sem_new(0); if (newconn->sem == SYS_SEM_NULL) { sys_mbox_free(newconn->recvmbox); sys_mbox_free(newconn->mbox); memp_free(MEMP_NETCONN, newconn); return ERR_MEM; } newconn->acceptmbox = SYS_MBOX_NULL; newconn->err = err; /* Register event with callback */ if (conn->callback) { (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0); /* We have to set the callback here even though * the new socket is unknown. Mark the socket as -1. */ newconn->callback = conn->callback; newconn->socket = -1; } sys_mbox_post(mbox, newconn); return ERR_OK; }
/*-----------------------------------------------------------------------------------*/ err_t netconn_delete(struct netconn *conn) { struct api_msg *msg; void *mem; if (conn == NULL) { return ERR_OK; } if ((msg = memp_mallocp(MEMP_API_MSG)) == NULL) { return ERR_MEM; } msg->type = API_MSG_DELCONN; msg->msg.conn = conn; api_msg_post(msg); sys_mbox_fetch(conn->mbox, NULL); memp_freep(MEMP_API_MSG, msg); /* Drain the recvmbox. */ if (conn->recvmbox != SYS_MBOX_NULL) { while (sys_arch_mbox_fetch(conn->recvmbox, &mem, 1) != SYS_ARCH_TIMEOUT) { if (conn->type == NETCONN_TCP) { pbuf_free((struct pbuf *)mem); } else { netbuf_delete((struct netbuf *)mem); } } sys_mbox_free(conn->recvmbox); conn->recvmbox = SYS_MBOX_NULL; } /* Drain the acceptmbox. */ if (conn->acceptmbox != SYS_MBOX_NULL) { while (sys_arch_mbox_fetch(conn->acceptmbox, &mem, 1) != SYS_ARCH_TIMEOUT) { netconn_delete((struct netconn *)mem); } sys_mbox_free(conn->acceptmbox); conn->acceptmbox = SYS_MBOX_NULL; } sys_mbox_free(conn->mbox); conn->mbox = SYS_MBOX_NULL; if (conn->sem != SYS_SEM_NULL) { sys_sem_free(conn->sem); } /* conn->sem = SYS_SEM_NULL;*/ memp_free(MEMP_NETCONN, conn); return ERR_OK; }
/*-----------------------------------------------------------------------------------*/ void tcpip_apimsg(struct api_msg *apimsg) { struct tcpip_msg *msg; msg = memp_mallocp(MEMP_TCPIP_MSG); if (msg == NULL) { memp_free(MEMP_API_MSG, apimsg); return; } msg->type = TCPIP_MSG_API; msg->msg.apimsg = apimsg; sys_mbox_post(mbox, msg); }
/*-----------------------------------------------------------------------------------*/ struct netbuf *netbuf_new(void) { struct netbuf *buf; buf = memp_mallocp(MEMP_NETBUF); if (buf != NULL) { buf->p = NULL; buf->ptr = NULL; return buf; } else { return NULL; } }
/*-----------------------------------------------------------------------------------*/ err_t tcpip_callback(void (*f)(void *ctx), void *ctx) { struct tcpip_msg *msg; msg = memp_mallocp(MEMP_TCPIP_MSG); if (msg == NULL) { return ERR_MEM; } msg->type = TCPIP_MSG_CALLBACK; msg->msg.cb.f = f; msg->msg.cb.ctx = ctx; sys_mbox_post(mbox, msg); return ERR_OK; }
/*-----------------------------------------------------------------------------------*/ err_t tcpip_input(struct pbuf *p, struct netif *inp) { struct tcpip_msg *msg; msg = memp_mallocp(MEMP_TCPIP_MSG); if (msg == NULL) { pbuf_free(p); return ERR_MEM; } msg->type = TCPIP_MSG_INPUT; msg->msg.inp.p = p; msg->msg.inp.netif = inp; sys_mbox_post(mbox, msg); return ERR_OK; }
err_t netconn_disconnect(struct netconn *conn) { struct api_msg *msg; if (conn == NULL) { return ERR_VAL; } if ((msg = memp_mallocp(MEMP_API_MSG)) == NULL) { return ERR_MEM; } msg->type = API_MSG_DISCONNECT; msg->msg.conn = conn; api_msg_post(msg); sys_mbox_fetch(conn->mbox, NULL); memp_freep(MEMP_API_MSG, msg); return conn->err; }
/** * Allocates a pbuf. * * The actual memory allocated for the pbuf is determined by the * layer at which the pbuf is allocated and the requested size * (from the size parameter). * * @param flag this parameter decides how and where the pbuf * should be allocated as follows: * * - PBUF_RAM: buffer memory for pbuf is allocated as one large * chunk. This includes protocol headers as well. * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for * protocol headers. Additional headers must be prepended * by allocating another pbuf and chain in to the front of * the ROM pbuf. It is assumed that the memory used is really * similar to ROM in that it is immutable and will not be * changed. Memory which is dynamic should generally not * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. * - PBUF_REF: no buffer memory is allocated for the pbuf, even for * protocol headers. It is assumed that the pbuf is only * being used in a single thread. If the pbuf gets queued, * then pbuf_take should be called to copy the buffer. * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from * the pbuf pool that is allocated during pbuf_init(). * * @return the allocated pbuf. If multiple pbufs where allocated, this * is the first pbuf of a pbuf chain. */ struct pbuf * pbuf_alloc(pbuf_layer l, u16_t length, pbuf_flag flag) { struct pbuf *p, *q, *r; u16_t offset; s32_t rem_len; /* remaining length */ #ifdef PBUF_DEBUG char text[200]; #endif LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%u)\n", length)); /* determine header offset */ offset = 0; switch (l) { case PBUF_TRANSPORT: /* add room for transport (often TCP) layer header */ offset += PBUF_TRANSPORT_HLEN; /* FALLTHROUGH */ case PBUF_IP: /* add room for IP layer header */ offset += PBUF_IP_HLEN; /* FALLTHROUGH */ case PBUF_LINK: /* add room for link layer header */ offset += PBUF_LINK_HLEN; break; case PBUF_RAW: break; default: LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); return NULL; } /* add room for IPsec layer header */ offset += IPSEC_HLEN; /** *** CS *** add room for ESP and AH header */ switch (flag) { case PBUF_POOL: /* allocate head of pbuf chain into p */ p = pbuf_pool_alloc(); LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); if (p == NULL) { #ifdef PBUF_STATS ++lwip_stats.pbuf.err; #endif /* PBUF_STATS */ return NULL; } p->next = NULL; /* make the payload pointer point 'offset' bytes into pbuf data memory */ p->payload = MEM_ALIGN((void *)((u8_t *)p + (sizeof(struct pbuf) + offset))); LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", ((u32_t)p->payload % MEM_ALIGNMENT) == 0); /* the total length of the pbuf chain is the requested size */ p->tot_len = length; /* set the length of the first pbuf in the chain */ p->len = length > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: length; /* set pbuf type */ p->flags = PBUF_FLAG_POOL; /* set reference count (needed here in case we fail) */ p->ref = 1; /* now allocate the tail of the pbuf chain */ /* remember first pbuf for linkage in next iteration */ r = p; /* remaining length to be allocated */ rem_len = length - p->len; /* any remaining pbufs to be allocated? */ while (rem_len > 0) { q = pbuf_pool_alloc(); if (q == NULL) { LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_alloc: Out of pbufs in pool.\n")); #ifdef PBUF_STATS ++lwip_stats.pbuf.err; #endif /* PBUF_STATS */ /* free chain so far allocated */ pbuf_free(p); /* bail out unsuccesfully */ return NULL; } q->next = NULL; /* make previous pbuf point to this pbuf */ r->next = q; /* set total length of this pbuf and next in chain */ q->tot_len = rem_len; /* this pbuf length is pool size, unless smaller sized tail */ q->len = rem_len > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rem_len; q->flags = PBUF_FLAG_POOL; q->payload = (void *)((u8_t *)q + sizeof(struct pbuf)); LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", ((u32_t)q->payload % MEM_ALIGNMENT) == 0); q->ref = 1; /* calculate remaining length to be allocated */ rem_len -= q->len; /* remember this pbuf for linkage in next iteration */ r = q; } /* end of chain */ //r->next = NULL; break; case PBUF_RAM: /* If pbuf is to be allocated in RAM, allocate memory for it. */ p = mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + length + offset)); if (p == NULL) { return NULL; } /* Set up internal structure of the pbuf. */ p->payload = MEM_ALIGN((void *)((u8_t *)p + sizeof(struct pbuf) + offset)); p->len = p->tot_len = length; p->next = NULL; p->flags = PBUF_FLAG_RAM; LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", ((u32_t)p->payload % MEM_ALIGNMENT) == 0); break; /* pbuf references existing (static constant) ROM payload? */ case PBUF_ROM: /* pbuf references existing (externally allocated) RAM payload? */ case PBUF_REF: /* only allocate memory for the pbuf structure */ p = memp_mallocp(MEMP_PBUF); if (p == NULL) { LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", flag == PBUF_ROM?"ROM":"REF")); return NULL; } /* caller must set this field properly, afterwards */ p->payload = NULL; p->len = p->tot_len = length; p->next = NULL; p->flags = (flag == PBUF_ROM? PBUF_FLAG_ROM: PBUF_FLAG_REF); break; default: LWIP_ASSERT("pbuf_alloc: erroneous flag", 0); return NULL; } /* set reference count */ p->ref = 1; LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_alloc(length=%u) == %p\n", length, (void *)p)); #ifdef PBUF_DEBUG pbufstats_pbuf_counter++; sprintf(text, "pbuf_alloc: p=%p, flag=%s, layer=%s length=%d", p, pbufstats_text_pbuf_flags[flag], pbufstats_text_pbuf_layers[l], length); pbufstats_print_pbuf_counter(text); pbufstats_addptr(p); #endif return p; }
/*-----------------------------------------------------------------------------------*/ err_t netconn_write(struct netconn *conn, void *dataptr, u32_t size, u8_t copy) { struct api_msg *msg; u32_t len; if (conn == NULL) { return ERR_VAL; } if (conn->err != ERR_OK) { return conn->err; } if (conn->sem == SYS_SEM_NULL) { conn->sem = sys_sem_new(0); if (conn->sem == SYS_SEM_NULL) { return ERR_MEM; } } if ((msg = memp_mallocp(MEMP_API_MSG)) == NULL) { return (conn->err = ERR_MEM); } msg->type = API_MSG_WRITE; msg->msg.conn = conn; conn->state = NETCONN_WRITE; while (conn->err == ERR_OK && size > 0) { msg->msg.msg.w.dataptr = dataptr; msg->msg.msg.w.copy = copy; if (conn->type == NETCONN_TCP) { if (tcp_sndbuf(conn->pcb.tcp) == 0) { sys_sem_wait(conn->sem); if (conn->err != ERR_OK) { goto ret; } } if (size > tcp_sndbuf(conn->pcb.tcp)) { /* We cannot send more than one send buffer's worth of data at a time. */ len = tcp_sndbuf(conn->pcb.tcp); } else { len = size; } } else { len = size; } DEBUGF(API_LIB_DEBUG, ("netconn_write: writing %ld bytes (%d)\n", len, copy)); msg->msg.msg.w.len = len; api_msg_post(msg); sys_mbox_fetch(conn->mbox, NULL); if (conn->err == ERR_OK) { dataptr = (void *)((char *)dataptr + len); size -= len; } else if (conn->err == ERR_MEM) { conn->err = ERR_OK; sys_sem_wait(conn->sem); } else { goto ret; } } ret: memp_freep(MEMP_API_MSG, msg); conn->state = NETCONN_NONE; if (conn->sem != SYS_SEM_NULL) { sys_sem_free(conn->sem); conn->sem = SYS_SEM_NULL; } return conn->err; }
/*-----------------------------------------------------------------------------------*/ struct pbuf * pbuf_alloc(pbuf_layer l, uint16_t size, pbuf_flag flag) { struct pbuf *p, *q, *r; uint16_t offset; int32_t rsize; offset = 0; switch(l) { case PBUF_TRANSPORT: offset += PBUF_TRANSPORT_HLEN; /* FALLTHROUGH */ case PBUF_IP: offset += PBUF_IP_HLEN; offset += PBUF_LINK_HLEN; /* FALLTHROUGH */ case PBUF_LINK: break; case PBUF_RAW: break; default: ASSERT("pbuf_alloc: bad pbuf layer", 0); return NULL; } switch(flag) { case PBUF_POOL: /* Allocate head of pbuf chain into p. */ p = pbuf_pool_alloc(); if(p == NULL) { #ifdef PBUF_STATS ++stats.pbuf.err; #endif /* PBUF_STATS */ return NULL; } p->next = NULL; /* Set the payload pointer so that it points offset bytes into pbuf data memory. */ p->payload = MEM_ALIGN((void *)((uint8_t *)p + (sizeof(struct pbuf) + offset))); /* The total length of the pbuf is the requested size. */ p->tot_len = size; /* Set the length of the first pbuf is the chain. */ p->len = size > PBUF_POOL_BUFSIZE - offset? PBUF_POOL_BUFSIZE - offset: size; p->flags = PBUF_FLAG_POOL; /* Allocate the tail of the pbuf chain. */ r = p; rsize = size - p->len; while(rsize > 0) { q = pbuf_pool_alloc(); if(q == NULL) { DEBUGF(PBUF_DEBUG, ("pbuf_alloc: Out of pbufs in pool,\n")); #ifdef PBUF_STATS ++stats.pbuf.err; #endif /* PBUF_STATS */ pbuf_pool_free(p); return NULL; } q->next = NULL; r->next = q; q->len = rsize > PBUF_POOL_BUFSIZE? PBUF_POOL_BUFSIZE: rsize; q->flags = PBUF_FLAG_POOL; q->payload = (void *)((uint8_t *)q + sizeof(struct pbuf)); r = q; q->ref = 1; q = q->next; rsize -= PBUF_POOL_BUFSIZE; } r->next = NULL; ASSERT("pbuf_alloc: pbuf->payload properly aligned", ((uint32_t)p->payload % MEM_ALIGNMENT) == 0); break; case PBUF_RAM: /* If pbuf is to be allocated in RAM, allocate memory for it. */ p = (struct pbuf*)mem_malloc(MEM_ALIGN_SIZE(sizeof(struct pbuf) + size + offset)); if(p == NULL) { return NULL; } /* Set up internal structure of the pbuf. */ p->payload = MEM_ALIGN((void *)((uint8_t *)p + sizeof(struct pbuf) + offset)); p->len = p->tot_len = size; p->next = NULL; p->flags = PBUF_FLAG_RAM; ASSERT("pbuf_alloc: pbuf->payload properly aligned", ((uint32_t)p->payload % MEM_ALIGNMENT) == 0); break; case PBUF_ROM: /* If the pbuf should point to ROM, we only need to allocate memory for the pbuf structure. */ p = (struct pbuf*)memp_mallocp(MEMP_PBUF); if(p == NULL) { return NULL; } p->payload = NULL; p->len = p->tot_len = size; p->next = NULL; p->flags = PBUF_FLAG_ROM; break; default: ASSERT("pbuf_alloc: erroneous flag", 0); return NULL; } p->ref = 1; return p; }
/*-----------------------------------------------------------------------------------*/ struct netbuf * netconn_recv(struct netconn *conn) { struct api_msg *msg; struct netbuf *buf; struct pbuf *p; u32_t len; if (conn == NULL) { return NULL; } if (conn->recvmbox == SYS_MBOX_NULL) { conn->err = ERR_CONN; return NULL; } if (conn->err != ERR_OK) { return NULL; } if (conn->type == NETCONN_TCP) { if (conn->pcb.tcp->state == LISTEN) { conn->err = ERR_CONN; return NULL; } buf = memp_mallocp(MEMP_NETBUF); if (buf == NULL) { conn->err = ERR_MEM; return NULL; } sys_mbox_fetch(conn->recvmbox, (void **)&p); if (p != NULL) { len = p->tot_len; conn->recv_avail -= len; } else len = 0; /* Register event with callback */ if (conn->callback) (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, len); /* If we are closed, we indicate that we no longer wish to receive data by setting conn->recvmbox to SYS_MBOX_NULL. */ if (p == NULL) { memp_freep(MEMP_NETBUF, buf); sys_mbox_free(conn->recvmbox); conn->recvmbox = SYS_MBOX_NULL; return NULL; } buf->p = p; buf->ptr = p; buf->fromport = 0; buf->fromaddr = NULL; /* Let the stack know that we have taken the data. */ if ((msg = memp_mallocp(MEMP_API_MSG)) == NULL) { conn->err = ERR_MEM; return buf; } msg->type = API_MSG_RECV; msg->msg.conn = conn; if (buf != NULL) { msg->msg.msg.len = buf->p->tot_len; } else { msg->msg.msg.len = 1; } api_msg_post(msg); sys_mbox_fetch(conn->mbox, NULL); memp_freep(MEMP_API_MSG, msg); } else { sys_mbox_fetch(conn->recvmbox, (void **)&buf); conn->recv_avail -= buf->p->tot_len; /* Register event with callback */ if (conn->callback) (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len); } DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err)); return buf; }