diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 80b2d088..3dfd7043 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -154,7 +154,7 @@ netbuf_copy_partial(struct netbuf *buf, void *dataptr, u16_t len, u16_t offset) left = 0; - if (buf == NULL) { + if(buf == NULL || dataptr == NULL) { return; } @@ -197,11 +197,14 @@ struct netconn *netconn_new(enum netconn_type t) { struct netconn *conn; + struct api_msg *msg; conn = memp_malloc(MEMP_NETCONN); if (conn == NULL) { return NULL; } + + conn->err = ERR_OK; conn->type = t; conn->pcb.tcp = NULL; @@ -216,6 +219,23 @@ netconn *netconn_new(enum netconn_type t) conn->socket = 0; conn->callback = 0; conn->recv_avail = 0; + + if((msg = memp_malloc(MEMP_API_MSG)) == NULL) { + memp_free(MEMP_NETCONN, conn); + return NULL; + } + + msg->type = API_MSG_NEWCONN; + msg->msg.conn = conn; + api_msg_post(msg); + sys_mbox_fetch(conn->mbox, NULL); + memp_free(MEMP_API_MSG, msg); + + if ( conn->err != ERR_OK ) { + memp_free(MEMP_NETCONN, conn); + return NULL; + } + return conn; } /*-----------------------------------------------------------------------------------*/ diff --git a/src/api/api_msg.c b/src/api/api_msg.c index de03dca9..f52d44f4 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -238,7 +238,62 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) static void do_newconn(struct api_msg_msg *msg) { + if(msg->conn->pcb.tcp != NULL) { + /* This "new" connection already has a PCB allocated. */ + /* Is this an error condition? Should it be deleted? + We currently just are happy and return. */ + sys_mbox_post(msg->conn->mbox, NULL); + return; + } + + msg->conn->err = ERR_OK; + + /* Allocate a PCB for this connection */ + switch(msg->conn->type) { +#if LWIP_UDP + case NETCONN_UDPLITE: + msg->conn->pcb.udp = udp_new(); + if(msg->conn->pcb.udp == NULL) { + msg->conn->err = ERR_MEM; + break; + } + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); + udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); + break; + case NETCONN_UDPNOCHKSUM: + msg->conn->pcb.udp = udp_new(); + if(msg->conn->pcb.udp == NULL) { + msg->conn->err = ERR_MEM; + break; + } + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); + udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); + break; + case NETCONN_UDP: + msg->conn->pcb.udp = udp_new(); + if(msg->conn->pcb.udp == NULL) { + msg->conn->err = ERR_MEM; + break; + } + udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + msg->conn->pcb.tcp = tcp_new(); + if(msg->conn->pcb.tcp == NULL) { + msg->conn->err = ERR_MEM; + break; + } + setup_tcp(msg->conn); + break; +#endif + } + + + sys_mbox_post(msg->conn->mbox, NULL); } + /*-----------------------------------------------------------------------------------*/ static void do_delconn(struct api_msg_msg *msg) @@ -571,7 +626,7 @@ do_write(struct api_msg_msg *msg) segments when new outgoing data arrives from the user if any previously transmitted data on the connection remains unacknowledged. */ - if (err == ERR_OK && msg->conn->pcb.tcp->unacked == NULL) { + if(err == ERR_OK && (msg->conn->pcb.tcp->unacked == NULL || (msg->conn->pcb.tcp->flags & TF_NODELAY)) ) { tcp_output(msg->conn->pcb.tcp); } msg->conn->err = err; diff --git a/src/api/sockets.c b/src/api/sockets.c index 0fbed317..f7bfbdb1 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -164,6 +164,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); sock = get_socket(s); if (!sock) { + set_errno(EBADF); return -1; } @@ -217,6 +218,7 @@ lwip_bind(int s, struct sockaddr *name, socklen_t namelen) sock = get_socket(s); if (!sock) { + set_errno(EBADF); return -1; } @@ -257,6 +259,7 @@ lwip_close(int s) sock = get_socket(s); if (!sock) { sys_sem_signal(socksem); + set_errno(EBADF); return -1; } @@ -280,6 +283,7 @@ lwip_connect(int s, struct sockaddr *name, socklen_t namelen) sock = get_socket(s); if (!sock) { + set_errno(EBADF); return -1; } @@ -322,6 +326,7 @@ lwip_listen(int s, int backlog) LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); sock = get_socket(s); if (!sock) { + set_errno(EBADF); return -1; } @@ -351,6 +356,7 @@ lwip_recvfrom(int s, void *mem, int len, unsigned int flags, LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags)); sock = get_socket(s); if (!sock) { + set_errno(EBADF); return -1; } @@ -468,11 +474,14 @@ lwip_send(int s, void *data, int size, unsigned int flags) sock = get_socket(s); if (!sock) { + set_errno(EBADF); return -1; } switch (netconn_type(sock->conn)) { case NETCONN_UDP: + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: /* create a buffer */ buf = netbuf_new(); @@ -521,6 +530,7 @@ lwip_sendto(int s, void *data, int size, unsigned int flags, sock = get_socket(s); if (!sock) { + set_errno(EBADF); return -1; } @@ -895,6 +905,7 @@ int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen) sock = get_socket(s); if (!sock) { + set_errno(EBADF); return -1; } @@ -930,6 +941,7 @@ int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen) sock = get_socket(s); if (!sock) { + set_errno(EBADF); return -1; } @@ -959,32 +971,183 @@ int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen) int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen) { - int err = ENOSYS; + int err = 0; struct lwip_socket *sock = get_socket(s); - if (!sock) { + if(!sock) { + set_errno(EBADF); return -1; } - if (level == SOL_SOCKET) { - switch (optname) { + if( NULL == optval || NULL == optlen ) { + sock_set_errno( sock, EFAULT ); + return -1; + } + + /* Do length and type checks for the various options first, to keep it readable. */ + switch( level ) { + +/* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch(optname) { + + case SO_ACCEPTCONN: + case SO_BROADCAST: + /* UNIMPL case SO_DEBUG: */ + /* UNIMPL case SO_DONTROUTE: */ case SO_ERROR: - if (!optval || !optlen || (*optlen != sizeof(int))) { + case SO_KEEPALIVE: + /* UNIMPL case SO_OOBINLINE: */ + /* UNIMPL case SO_RCVBUF: */ + /* UNIMPL case SO_SNDBUF: */ + /* UNIMPL case SO_RCVLOWAT: */ + /* UNIMPL case SO_SNDLOWAT: */ + /* UNIMPL case SO_REUSEADDR: */ + /* UNIMPL case SO_REUSEPORT: */ + case SO_TYPE: + /* UNIMPL case SO_USELOOPBACK: */ + if( *optlen < sizeof(int) ) { err = EINVAL; - break; } - *(int *)optval = sock->err; - sock->err = 0; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", s, *(int *)optval)); - err = 0; - break; + break; + default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname)); + err = ENOPROTOOPT; + } /* switch */ + break; + +/* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch(optname) { + /* UNIMPL case IP_HDRINCL: */ + /* UNIMPL case IP_RCVDSTADDR: */ + /* UNIMPL case IP_RCVIF: */ + case IP_TTL: + case IP_TOS: + if( *optlen < sizeof(int) ) { + err = EINVAL; + } + break; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname)); + err = ENOPROTOOPT; + } /* switch */ + break; + +/* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + if( *optlen < sizeof(int) ) { + err = EINVAL; break; } - } else { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname)); + + /* If this is no TCP socket, ignore any options. */ + if ( sock->conn->type != NETCONN_TCP ) return 0; + + switch( optname ) { + case TCP_NODELAY: + case TCP_KEEPALIVE: + break; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname)); + err = ENOPROTOOPT; + } /* switch */ + break; + +/* UNDEFINED LEVEL */ + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname)); + err = ENOPROTOOPT; + } /* switch */ + + + if( 0 != err ) { + sock_set_errno(sock, err); + return -1; } + + + + /* Now do the actual option processing */ + + switch(level) { + +/* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch( optname ) { + + /* The option flags */ + case SO_ACCEPTCONN: + case SO_BROADCAST: + /* UNIMPL case SO_DEBUG: */ + /* UNIMPL case SO_DONTROUTE: */ + case SO_KEEPALIVE: + /* UNIMPL case SO_OOBINCLUDE: */ + /* UNIMPL case SO_REUSEADDR: */ + /* UNIMPL case SO_REUSEPORT: */ + /*case SO_USELOOPBACK: UNIMPL */ + *(int*)optval = sock->conn->pcb.tcp->so_options & optname; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", s, optname, (*(int*)optval?"on":"off"))); + break; + + case SO_TYPE: + switch (sock->conn->type) { + case NETCONN_TCP: + *(int*)optval = SOCK_STREAM; + break; + case NETCONN_UDP: + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + *(int*)optval = SOCK_DGRAM; + break; + default: /* unrecognized socket type */ + *(int*)optval = sock->conn->type; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", s, *(int *)optval)); + } /* switch */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", s, *(int *)optval)); + break; + + case SO_ERROR: + *(int *)optval = sock->err; + sock->err = 0; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", s, *(int *)optval)); + break; + } /* switch */ + break; + +/* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch( optname ) { + case IP_TTL: + *(int*)optval = sock->conn->pcb.tcp->ttl; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", s, *(int *)optval)); + break; + case IP_TOS: + *(int*)optval = sock->conn->pcb.tcp->tos; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", s, *(int *)optval)); + break; + } /* switch */ + break; + +/* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + switch( optname ) { + case TCP_NODELAY: + *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", s, (*(int*)optval)?"on":"off") ); + break; + case TCP_KEEPALIVE: + *(int*)optval = sock->conn->pcb.tcp->keepalive; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", s, *(int *)optval)); + break; + } /* switch */ + break; + } + + sock_set_errno(sock, err); return err ? -1 : 0; } @@ -992,27 +1155,161 @@ int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *opt int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen) { struct lwip_socket *sock = get_socket(s); - int err = ENOSYS; + int err = 0; - if (!sock) { + if(!sock) { + set_errno(EBADF); return -1; } - if (level == SOL_SOCKET) { - switch (optname) { - case SO_REUSEADDR: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, SO_REUSEADDR, ..)\n", s)); - /* XXX just pretend we support this for now */ - err = 0; + if( NULL == optval ) { + sock_set_errno( sock, EFAULT ); + return -1; + } + + + /* Do length and type checks for the various options first, to keep it readable. */ + switch( level ) { + +/* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch(optname) { + + case SO_BROADCAST: + /* UNIMPL case SO_DEBUG: */ + /* UNIMPL case SO_DONTROUTE: */ + case SO_KEEPALIVE: + /* UNIMPL case SO_OOBINLINE: */ + /* UNIMPL case SO_RCVBUF: */ + /* UNIMPL case SO_SNDBUF: */ + /* UNIMPL case SO_RCVLOWAT: */ + /* UNIMPL case SO_SNDLOWAT: */ + /* UNIMPL case SO_REUSEADDR: */ + /* UNIMPL case SO_REUSEPORT: */ + /* UNIMPL case SO_USELOOPBACK: */ + if( optlen < sizeof(int) ) { + err = EINVAL; + } + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname)); + err = ENOPROTOOPT; + } /* switch */ + break; + +/* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch(optname) { + /* UNIMPL case IP_HDRINCL: */ + /* UNIMPL case IP_RCVDSTADDR: */ + /* UNIMPL case IP_RCVIF: */ + case IP_TTL: + case IP_TOS: + if( optlen < sizeof(int) ) { + err = EINVAL; + } break; default: - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname)); + err = ENOPROTOOPT; + } /* switch */ + break; + +/* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + if( optlen < sizeof(int) ) { + err = EINVAL; break; } - } else { + + /* If this is no TCP socket, ignore any options. */ + if ( sock->conn->type != NETCONN_TCP ) return 0; + + switch( optname ) { + case TCP_NODELAY: + case TCP_KEEPALIVE: + break; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname)); + err = ENOPROTOOPT; + } /* switch */ + break; + +/* UNDEFINED LEVEL */ + default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname)); + err = ENOPROTOOPT; + } /* switch */ + + + if( 0 != err ) { + sock_set_errno(sock, err); + return -1; } + + + /* Now do the actual option processing */ + + switch(level) { + +/* Level: SOL_SOCKET */ + case SOL_SOCKET: + switch(optname) { + + /* The option flags */ + case SO_BROADCAST: + /* UNIMPL case SO_DEBUG: */ + /* UNIMPL case SO_DONTROUTE: */ + case SO_KEEPALIVE: + /* UNIMPL case SO_OOBINCLUDE: */ + /* UNIMPL case SO_REUSEADDR: */ + /* UNIMPL case SO_REUSEPORT: */ + /* UNIMPL case SO_USELOOPBACK: */ + if ( *(int*)optval ) { + sock->conn->pcb.tcp->so_options |= optname; + } else { + sock->conn->pcb.tcp->so_options &= ~optname; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", s, optname, (*(int*)optval?"on":"off"))); + break; + } /* switch */ + break; + +/* Level: IPPROTO_IP */ + case IPPROTO_IP: + switch( optname ) { + case IP_TTL: + sock->conn->pcb.tcp->ttl = (u8_t)(*(int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n", s, sock->conn->pcb.tcp->ttl)); + break; + case IP_TOS: + sock->conn->pcb.tcp->tos = (u8_t)(*(int*)optval); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", s, sock->conn->pcb.tcp->tos)); + break; + } /* switch */ + break; + +/* Level: IPPROTO_TCP */ + case IPPROTO_TCP: + switch( optname ) { + case TCP_NODELAY: + if ( *(int*)optval ) { + sock->conn->pcb.tcp->flags |= TF_NODELAY; + } else { + sock->conn->pcb.tcp->flags &= ~TF_NODELAY; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", s, (*(int *)optval)?"on":"off") ); + break; + case TCP_KEEPALIVE: + sock->conn->pcb.tcp->keepalive = (u32_t)(*(int*)optval);; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %u\n", s, sock->conn->pcb.tcp->keepalive)); + break; + } /* switch */ + break; + } /* switch */ + sock_set_errno(sock, err); return err ? -1 : 0; } @@ -1021,7 +1318,8 @@ int lwip_ioctl(int s, long cmd, void *argp) { struct lwip_socket *sock = get_socket(s); - if (!sock) { + if(!sock) { + set_errno(EBADF); return -1; } @@ -1035,7 +1333,7 @@ int lwip_ioctl(int s, long cmd, void *argp) *((u16_t*)argp) = sock->conn->recv_avail; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp))); - sock_set_errno(sock, 0); + sock_set_errno(sock, 0); return 0; case FIONBIO: @@ -1044,7 +1342,7 @@ int lwip_ioctl(int s, long cmd, void *argp) else sock->flags &= ~O_NONBLOCK; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK))); - sock_set_errno(sock, 0); + sock_set_errno(sock, 0); return 0; default: diff --git a/src/core/ipv4/icmp.c b/src/core/ipv4/icmp.c index d62013ff..bd6876d0 100644 --- a/src/core/ipv4/icmp.c +++ b/src/core/ipv4/icmp.c @@ -126,8 +126,8 @@ icmp_input(struct pbuf *p, struct netif *inp) snmp_inc_icmpoutechoreps(); pbuf_header(p, hlen); - ip_output_if (p, &(iphdr->src), IP_HDRINCL, - IPH_TTL(iphdr), IP_PROTO_ICMP, inp); + ip_output_if(p, &(iphdr->src), IP_HDRINCL, + IPH_TTL(iphdr), 0, IP_PROTO_ICMP, inp); break; default: LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %d code %d not supported.\n", (int)type, (int)code)); @@ -169,7 +169,7 @@ icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) snmp_inc_icmpoutdestunreachs(); ip_output(q, NULL, &(iphdr->src), - ICMP_TTL, IP_PROTO_ICMP); + ICMP_TTL, 0, IP_PROTO_ICMP); pbuf_free(q); } /*-----------------------------------------------------------------------------------*/ @@ -210,7 +210,7 @@ icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) /* increase number of destination unreachable messages attempted to send */ snmp_inc_icmpouttimeexcds(); ip_output(q, NULL, &(iphdr->src), - ICMP_TTL, IP_PROTO_ICMP); + ICMP_TTL, 0, IP_PROTO_ICMP); pbuf_free(q); } diff --git a/src/core/ipv4/ip.c b/src/core/ipv4/ip.c index 551eefb1..02c5d297 100644 --- a/src/core/ipv4/ip.c +++ b/src/core/ipv4/ip.c @@ -448,8 +448,8 @@ ip_input(struct pbuf *p, struct netif *inp) { */ /*-----------------------------------------------------------------------------------*/ err_t -ip_output_if (struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, +ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif) { static struct ip_hdr *iphdr; @@ -475,7 +475,7 @@ ip_output_if (struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, ip_addr_set(&(iphdr->dest), dest); - IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, 0); + IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos); IPH_LEN_SET(iphdr, htons(p->tot_len)); IPH_OFFSET_SET(iphdr, htons(IP_DF)); IPH_ID_SET(iphdr, htons(ip_id)); @@ -521,7 +521,7 @@ ip_output_if (struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, /*-----------------------------------------------------------------------------------*/ err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, u8_t proto) + u8_t ttl, u8_t tos, u8_t proto) { struct netif *netif; @@ -535,7 +535,7 @@ ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, return ERR_RTE; } - return ip_output_if (p, src, dest, ttl, proto, netif); + return ip_output_if(p, src, dest, ttl, tos, proto, netif); } /*-----------------------------------------------------------------------------------*/ #if IP_DEBUG diff --git a/src/core/raw.c b/src/core/raw.c index 4d914ce8..73aa37ef 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -175,7 +175,7 @@ raw_send_payload(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) src_ip = &(pcb->local_ip); } - err = ip_output_if (p, src_ip, ipaddr, 64, pcb->protocol, netif); + err = ip_output_if (p, src_ip, ipaddr, 64, pcb->tos, pcb->protocol, netif); return ERR_OK; } diff --git a/src/core/tcp.c b/src/core/tcp.c index bfeab24c..4aa51bdf 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -318,6 +318,10 @@ tcp_listen(struct tcp_pcb *pcb) lpcb->callback_arg = pcb->callback_arg; lpcb->local_port = pcb->local_port; lpcb->state = LISTEN; + lpcb->so_options = pcb->so_options; + lpcb->so_options |= SOF_ACCEPTCONN; + lpcb->ttl = pcb->ttl; + lpcb->tos = pcb->tos; ip_addr_set(&lpcb->local_ip, &pcb->local_ip); memp_free(MEMP_TCP_PCB, pcb); #if LWIP_CALLBACK_API @@ -520,6 +524,21 @@ tcp_slowtmr(void) } } + /* Check if KEEPALIVE should be sent */ + if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { + if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %u.%u.%u.%u.\n", + ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), + ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); + + tcp_abort(pcb); + } + else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + pcb->keep_cnt * TCP_KEEPINTVL) / TCP_SLOW_INTERVAL) { + tcp_keepalive(pcb); + pcb->keep_cnt++; + } + } + /* If this PCB has queued out of sequence data, but has been inactive for too long, will drop the data (it will eventually be retransmitted). */ @@ -810,6 +829,8 @@ tcp_alloc(u8_t prio) pcb->snd_buf = TCP_SND_BUF; pcb->snd_queuelen = 0; pcb->rcv_wnd = TCP_WND; + pcb->tos = 0; + pcb->ttl = TCP_TTL; pcb->mss = TCP_MSS; pcb->rto = 3000 / TCP_SLOW_INTERVAL; pcb->sa = 0; @@ -829,6 +850,10 @@ tcp_alloc(u8_t prio) #if LWIP_CALLBACK_API pcb->recv = tcp_recv_null; #endif /* LWIP_CALLBACK_API */ + + /* Init KEEPALIVE timer */ + pcb->keepalive = TCP_KEEPDEFAULT; + pcb->keep_cnt = 0; } return pcb; } diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 908c336b..190f42b8 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -396,7 +396,8 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) #if LWIP_CALLBACK_API npcb->accept = pcb->accept; #endif /* LWIP_CALLBACK_API */ - + /* inherit socket options */ + npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER); /* Register the new PCB so that we can begin receiving segments for it. */ TCP_REG(&tcp_active_pcbs, npcb); @@ -483,6 +484,7 @@ tcp_process(struct tcp_pcb *pcb) /* Update the PCB (in)activity timer. */ pcb->tmr = tcp_ticks; + pcb->keep_cnt = 0; /* Do different things depending on the TCP state. */ switch (pcb->state) { diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 3315fdb2..646c709f 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -405,7 +405,8 @@ tcp_output(struct tcp_pcb *pcb) tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), IP_PROTO_TCP, p->tot_len); - ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), TCP_TTL, + + ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, IP_PROTO_TCP); pbuf_free(p); @@ -527,7 +528,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) ++lwip_stats.tcp.xmit; #endif /* TCP_STATS */ - ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), TCP_TTL, + ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, IP_PROTO_TCP); } /*-----------------------------------------------------------------------------------*/ @@ -561,7 +562,8 @@ tcp_rst(u32_t seqno, u32_t ackno, #ifdef TCP_STATS ++lwip_stats.tcp.xmit; #endif /* TCP_STATS */ - ip_output(p, local_ip, remote_ip, TCP_TTL, IP_PROTO_TCP); + /* Send output with hardcoded TTL since we have no access to the pcb */ + ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); pbuf_free(p); LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno)); } @@ -595,6 +597,50 @@ tcp_rexmit(struct tcp_pcb *pcb) tcp_output(pcb); } +/*-----------------------------------------------------------------------------------*/ +void +tcp_keepalive(struct tcp_pcb *pcb) +{ + struct pbuf *p; + struct tcp_hdr *tcphdr; + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %u.%u.%u.%u\n", + ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), + ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); + + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %ld pcb->tmr %ld pcb->keep_cnt %ld\n", tcp_ticks, pcb->tmr, pcb->keep_cnt)); + + p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); + + if(p == NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n")); + return; + } + + tcphdr = p->payload; + tcphdr->src = htons(pcb->local_port); + tcphdr->dest = htons(pcb->remote_port); + tcphdr->seqno = htonl(pcb->snd_nxt - 1); + tcphdr->ackno = htonl(pcb->rcv_nxt); + tcphdr->wnd = htons(pcb->rcv_wnd); + tcphdr->urgp = 0; + TCPH_HDRLEN_SET(tcphdr, 5); + + tcphdr->chksum = 0; + tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len); + +#ifdef TCP_STATS + ++lwip_stats.tcp.xmit; +#endif /* TCP_STATS */ + + /* Send output to IP */ + ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); + + pbuf_free(p); + + LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_keepalive: seqno %lu ackno %lu.\n", pcb->snd_nxt - 1, pcb->rcv_nxt)); +} + #endif /* LWIP_TCP */ diff --git a/src/core/udp.c b/src/core/udp.c index b0873066..a29234d4 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -407,7 +407,7 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; /* output to IP */ - err = ip_output_if (q, src_ip, &pcb->remote_ip, UDP_TTL, IP_PROTO_UDPLITE, netif); + err = ip_output_if (p, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); snmp_inc_udpoutdatagrams(); } else { LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %u\n", q->tot_len)); @@ -422,7 +422,7 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) snmp_inc_udpoutdatagrams(); LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n")); /* output to IP */ - err = ip_output_if (q, src_ip, &pcb->remote_ip, UDP_TTL, IP_PROTO_UDP, netif); + err = ip_output_if(p, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); } /* did we chain a header earlier? */ @@ -650,6 +650,9 @@ udp_new(void) { /* initialize PCB to all zeroes */ memset(pcb, 0, sizeof(struct udp_pcb)); } + + pcb->ttl = UDP_TTL; + return pcb; } /*-----------------------------------------------------------------------------------*/ diff --git a/src/include/ipv4/lwip/ip.h b/src/include/ipv4/lwip/ip.h index 070c8d6c..1aa8a30b 100644 --- a/src/include/ipv4/lwip/ip.h +++ b/src/include/ipv4/lwip/ip.h @@ -47,9 +47,9 @@ u8_t ip_lookup(void *header, struct netif *inp); struct netif *ip_route(struct ip_addr *dest); err_t ip_input(struct pbuf *p, struct netif *inp); err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, u8_t proto); + u8_t ttl, u8_t tos, u8_t proto); err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, u8_t proto, + u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); #define IP_HLEN 20 @@ -67,6 +67,36 @@ err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, #endif /* IP_HDRINCL */ #define IP_HDRINCL NULL + +/* This is the common part of all PCB types. It needs to be at the + beginning of a PCB type definition. It is located here so that + changes to this common part are made in one location instead of + having to change all PCB structs. */ +#define IP_PCB struct ip_addr local_ip; \ + struct ip_addr remote_ip; \ + /* Socket options */ \ + u16_t so_options; \ + /* Type Of Service */ \ + u8_t tos; \ + /* Time To Live */ \ + u8_t ttl + +/* + * Option flags per-socket. These are the same like SO_XXX. + */ +#define SOF_DEBUG (u16_t)0x0001U /* turn on debugging info recording */ +#define SOF_ACCEPTCONN (u16_t)0x0002U /* socket has had listen() */ +#define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */ +#define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */ +#define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */ +#define SOF_BROADCAST (u16_t)0x0020U /* permit sending of broadcast msgs */ +#define SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */ +#define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */ +#define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */ +#define SOF_REUSEPORT (u16_t)0x0200U /* allow local address & port reuse */ + + + #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif diff --git a/src/include/lwip/raw.h b/src/include/lwip/raw.h index 633e814d..55a1c2b3 100644 --- a/src/include/lwip/raw.h +++ b/src/include/lwip/raw.h @@ -39,9 +39,11 @@ #include "lwip/ip.h" struct raw_pcb { +/* Common members of all PCB types */ + IP_PCB; + struct raw_pcb *next; - struct ip_addr local_ip;/*, remote_ip;*/ u16_t protocol; void (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p, diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index d460d84f..2bf7740e 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -70,6 +70,7 @@ struct sockaddr { #define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ #define SO_LINGER 0x0080 /* linger on close if data present */ #define SO_OOBINLINE 0x0100 /* leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */ #define SO_DONTLINGER (int)(~SO_LINGER) @@ -117,6 +118,36 @@ struct linger { #define MSG_DONTWAIT 0x40 /* Nonblocking i/o for this operation only */ +/* + * Options for level IPPROTO_IP + */ +#define IP_TOS 1 +#define IP_TTL 2 + + +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 +#define IPTOS_MINCOST IPTOS_LOWCOST + +/* + * Definitions for IP precedence (also in ip_tos) (hopefully unused) + */ +#define IPTOS_PREC_MASK 0xe0 +#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + + /* * Commands for ioctlsocket(), taken from the BSD file fcntl.h. * diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 3a988e89..1231f6e7 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -151,6 +151,19 @@ void tcp_rexmit (struct tcp_pcb *pcb); #define TCP_MSL 60000 /* The maximum segment lifetime in microseconds */ +/* + * User-settable options (used with setsockopt). + */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keepalive miliseconds */ + +/* Keepalive values */ +#define TCP_KEEPDEFAULT 7200000 /* KEEPALIVE timer in miliseconds */ +#define TCP_KEEPINTVL 75000 /* Time between KEEPALIVE probes in miliseconds */ +#define TCP_KEEPCNT 9 /* Counter for KEEPALIVE probes */ +#define TCP_MAXIDLE TCP_KEEPCNT * TCP_KEEPINTVL /* Maximum KEEPALIVE probe time */ + + #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif @@ -200,17 +213,30 @@ enum tcp_state { /* the TCP protocol control block */ struct tcp_pcb { +/* Common members of all PCB types */ + IP_PCB; + +/* Protocol specific PCB members */ + struct tcp_pcb *next; /* for the linked list */ + + enum tcp_state state; /* TCP state */ + u8_t prio; void *callback_arg; - struct ip_addr local_ip; u16_t local_port; - enum tcp_state state; /* TCP state */ - - struct ip_addr remote_ip; u16_t remote_port; + u8_t flags; +#define TF_ACK_DELAY (u8_t)0x01U /* Delayed ACK. */ +#define TF_ACK_NOW (u8_t)0x02U /* Immediate ACK. */ +#define TF_INFR (u8_t)0x04U /* In fast recovery. */ +#define TF_RESET (u8_t)0x08U /* Connection was reset. */ +#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ +#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ +#define TF_NODELAY (u8_t)0x40U /* Disable Nagle algorithm */ + /* receiver varables */ u32_t rcv_nxt; /* next seqno expected */ u16_t rcv_wnd; /* receiver window */ @@ -223,14 +249,6 @@ struct tcp_pcb { u16_t rtime; u16_t mss; /* maximum segment size */ - - u8_t flags; -#define TF_ACK_DELAY (u8_t)0x01U /* Delayed ACK. */ -#define TF_ACK_NOW (u8_t)0x02U /* Immediate ACK. */ -#define TF_INFR (u8_t)0x04U /* In fast recovery. */ -#define TF_RESET (u8_t)0x08U /* Connection was reset. */ -#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ -#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ /* RTT estimation variables. */ u16_t rttest; /* RTT estimate in 500ms ticks */ @@ -288,21 +306,32 @@ struct tcp_pcb { /* Function to be called whenever a fatal error occurs. */ void (* errf)(void *arg, err_t err); #endif /* LWIP_CALLBACK_API */ + + /* idle time before KEEPALIVE is sent */ + u32_t keepalive; + + /* KEEPALIVE counter */ + u8_t keep_cnt; }; struct tcp_pcb_listen { +/* Common members of all PCB types */ + IP_PCB; + +/* Protocol specific PCB members */ struct tcp_pcb_listen *next; /* for the linked list */ - u8_t prio; - void *callback_arg; - struct ip_addr local_ip; - u16_t local_port; /* Even if state is obviously LISTEN this is here for * field compatibility with tpc_pcb to which it is cast sometimes * Until a cleaner solution emerges this is here.FIXME */ enum tcp_state state; /* TCP state */ + u8_t prio; + void *callback_arg; + + u16_t local_port; + #if LWIP_CALLBACK_API /* Function to call when a listener has been connected. */ err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err); @@ -402,6 +431,8 @@ void tcp_rst(u32_t seqno, u32_t ackno, u32_t tcp_next_iss(void); +void tcp_keepalive(struct tcp_pcb *pcb); + extern struct tcp_pcb *tcp_input_pcb; extern u32_t tcp_ticks; diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index 84d2bfde..f716f89e 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -52,12 +52,16 @@ struct udp_hdr { #define UDP_FLAGS_CONNECTED 0x04U struct udp_pcb { +/* Common members of all PCB types */ + IP_PCB; + +/* Protocol specific PCB members */ + struct udp_pcb *next; - struct ip_addr local_ip, remote_ip; + u8_t flags; u16_t local_port, remote_port; - u8_t flags; u16_t chksum_len; void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p,