support ipv4 ToS and ipv6 TrafficClass

Signed-off-by: 梁超众 <liangchaozhong@xiaomi.com>
This commit is contained in:
梁超众 2022-12-21 12:40:42 +08:00 committed by archer
parent 5e0af0ecfd
commit 5012195bde
26 changed files with 256 additions and 47 deletions

View file

@ -129,6 +129,8 @@
* the incoming packet */
#define IPV6_RECVPKTINFO (__SO_PROTOCOL + 9) /* It functions just same as
* IPV6_PKTINFO for now */
#define IPV6_TCLASS (__SO_PROTOCOL + 10) /* Access the Traffic Class
* field */
/* Values used with SIOCSIFMCFILTER and SIOCGIFMCFILTER ioctl's */

View file

@ -77,6 +77,26 @@
#define IP_PROTO_UDP 17
#define IP_PROTO_ICMP6 58
/* Values for the TOS field */
#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_MINCOST 0x02
#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
/* Flag bits in 16-bit flags + fragment offset IPv4 header field */
#define IP_FLAG_RESERVED 0x8000

View file

@ -222,6 +222,11 @@ struct socket_conn_s
uint8_t s_flags; /* See _SF_* definitions */
/* Definitions of IPv4 TOS and IPv6 Traffic Class */
uint8_t s_tos; /* IPv4 Type of Service */
#define s_tclass s_tos /* IPv6 traffic class defination */
/* Connection-specific content may follow */
};

View file

@ -183,7 +183,7 @@ void icmp_reply(FAR struct net_driver_s *dev, int type, int code)
ipv4_build_header(IPv4BUF, dev->d_len, IP_PROTO_ICMP,
&dev->d_ipaddr, (FAR in_addr_t *)ipv4->srcipaddr,
IP_TTL_DEFAULT, NULL);
IP_TTL_DEFAULT, 0, NULL);
/* Initialize the ICMP header */

View file

@ -119,7 +119,7 @@ static void sendto_request(FAR struct net_driver_s *dev,
ipv4_build_header(IPv4BUF, dev->d_len, IP_PROTO_ICMP,
&dev->d_ipaddr, &pstate->snd_toaddr,
IP_TTL_DEFAULT, NULL);
IP_TTL_DEFAULT, 0, NULL);
/* Copy the ICMP header and payload into place after the IPv4 header */

View file

@ -77,7 +77,7 @@ void icmpv6_advertise(FAR struct net_driver_s *dev,
l3size = SIZEOF_ICMPV6_NEIGHBOR_ADVERTISE_S(lladdrsize);
ipv6_build_header(IPv6BUF, l3size, IP_PROTO_ICMP6,
dev->d_ipv6addr, destipaddr, 255);
dev->d_ipv6addr, destipaddr, 255, 0);
/* Set up the ICMPv6 Neighbor Advertise response */

View file

@ -137,7 +137,7 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
icmpv6_linkipaddr(dev, srcv6addr);
ipv6_build_header(IPv6BUF, l3size, IP_PROTO_ICMP6,
srcv6addr, g_ipv6_allnodes, 255);
srcv6addr, g_ipv6_allnodes, 255, 0);
/* Set up the ICMPv6 Router Advertise response */

View file

@ -171,7 +171,7 @@ void icmpv6_reply(FAR struct net_driver_s *dev, int type, int code, int data)
dev->d_len = ipicmplen + datalen;
ipv6_build_header(IPv6BUF, dev->d_len - IPv6_HDRLEN, IP_PROTO_ICMP6,
dev->d_ipv6addr, ipv6->srcipaddr, 255);
dev->d_ipv6addr, ipv6->srcipaddr, 255, 0);
/* Initialize the ICMPv6 header */

View file

@ -76,7 +76,7 @@ void icmpv6_rsolicit(FAR struct net_driver_s *dev)
l3size = SIZEOF_ICMPV6_ROUTER_SOLICIT_S(lladdrsize);
ipv6_build_header(IPv6BUF, l3size, IP_PROTO_ICMP6,
dev->d_ipv6addr, g_ipv6_allrouters, 255);
dev->d_ipv6addr, g_ipv6_allrouters, 255, 0);
/* Set up the ICMPv6 Router Solicitation message */

View file

@ -115,7 +115,7 @@ static void sendto_request(FAR struct net_driver_s *dev,
dev->d_len = IPv6_HDRLEN + pstate->snd_buflen;
ipv6_build_header(IPv6BUF, pstate->snd_buflen, IP_PROTO_ICMP6,
dev->d_ipv6addr, pstate->snd_toaddr.s6_addr16, 255);
dev->d_ipv6addr, pstate->snd_toaddr.s6_addr16, 255, 0);
/* Copy the ICMPv6 request and payload into place after the IPv6 header */

View file

@ -95,7 +95,7 @@ void icmpv6_solicit(FAR struct net_driver_s *dev,
dstaddr[7] = ipaddr[7];
ipv6_build_header(IPv6BUF, l3size, IP_PROTO_ICMP6,
dev->d_ipv6addr, dstaddr, 255);
dev->d_ipv6addr, dstaddr, 255, 0);
/* Set up the ICMPv6 Neighbor Solicitation message */

View file

@ -142,7 +142,7 @@ void igmp_send(FAR struct net_driver_s *dev, FAR struct igmp_group_s *group,
opt.len = sizeof(uint32_t);
ipv4_build_header(IPv4BUF, dev->d_len, IP_PROTO_IGMP,
&dev->d_ipaddr, destipaddr, IGMP_TTL, &opt);
&dev->d_ipaddr, destipaddr, IGMP_TTL, 0, &opt);
/* Set up the IGMP message */

View file

@ -35,7 +35,7 @@ SOCK_CSRCS += ipv4_setsockopt.c ipv4_getsockopt.c ipv4_getsockname.c ipv4_getpee
endif
ifeq ($(CONFIG_NET_IPv6),y)
SOCK_CSRCS += ipv6_setsockopt.c ipv6_getsockname.c ipv6_getpeername.c ipv6_build_header.c
SOCK_CSRCS += ipv6_setsockopt.c ipv6_getsockname.c ipv6_getpeername.c ipv6_build_header.c ipv6_getsockopt.c
endif
# Include inet build support

View file

@ -192,6 +192,10 @@ int ipv6_setsockopt(FAR struct socket *psock, int option,
int ipv4_getsockopt(FAR struct socket *psock, int option,
FAR void *value, FAR socklen_t *value_len);
#endif
#ifdef CONFIG_NET_IPv6
int ipv6_getsockopt(FAR struct socket *psock, int option,
FAR void *value, FAR socklen_t *value_len);
#endif
/****************************************************************************
* Name: ipv4_getsockname and ipv6_sockname
@ -300,6 +304,7 @@ int inet_txdrain(FAR struct socket *psock, unsigned int timeout);
* src_ip Source IPv4 address
* dst_ip Destination IPv4 address
* ttl Time to live(IPv4)
* tos Type of Service(IPv4)
* opt IPv4 options
*
* Returned Value:
@ -311,7 +316,7 @@ int inet_txdrain(FAR struct socket *psock, unsigned int timeout);
uint16_t ipv4_build_header(FAR struct ipv4_hdr_s *ipv4, uint16_t total_len,
uint16_t prot, FAR const in_addr_t *src_ip,
FAR const in_addr_t *dst_ip, uint8_t ttl,
FAR struct ipv4_opt_s *opt);
uint8_t tos, FAR struct ipv4_opt_s *opt);
#endif
/****************************************************************************
@ -327,6 +332,7 @@ uint16_t ipv4_build_header(FAR struct ipv4_hdr_s *ipv4, uint16_t total_len,
* src_ip Source IPv6 address
* dst_ip Destination IPv6 address
* ttl hop limit(IPv6)
* tclass traffic class(IPv6)
*
* Returned Value:
* length of IPv6 header
@ -336,7 +342,8 @@ uint16_t ipv4_build_header(FAR struct ipv4_hdr_s *ipv4, uint16_t total_len,
#ifdef CONFIG_NET_IPv6
uint16_t ipv6_build_header(FAR struct ipv6_hdr_s *ipv6, uint16_t payload_len,
uint16_t prot, const net_ipv6addr_t src_ip,
const net_ipv6addr_t dst_ip, uint8_t ttl);
const net_ipv6addr_t dst_ip, uint8_t ttl,
uint8_t tclass);
#endif
#undef EXTERN

View file

@ -750,10 +750,15 @@ static int inet_getsockopt(FAR struct socket *psock, int level, int option,
#endif
#ifdef CONFIG_NET_IPv4
case IPPROTO_IP:
case IPPROTO_IP:/* IPv4 protocol socket options (see include/netinet/in.h) */
return ipv4_getsockopt(psock, option, value, value_len);
#endif
#ifdef CONFIG_NET_IPv6
case IPPROTO_IPV6:/* IPv6 protocol socket options (see include/netinet/in.h) */
return ipv6_getsockopt(psock, option, value, value_len);
#endif
default:
return -ENOPROTOOPT;
}
@ -1018,12 +1023,12 @@ static int inet_setsockopt(FAR struct socket *psock, int level, int option,
#endif
#ifdef CONFIG_NET_IPv4
case IPPROTO_IP:/* TCP protocol socket options (see include/netinet/in.h) */
case IPPROTO_IP:/* IPv4 protocol socket options (see include/netinet/in.h) */
return ipv4_setsockopt(psock, option, value, value_len);
#endif
#ifdef CONFIG_NET_IPv6
case IPPROTO_IPV6:/* TCP protocol socket options (see include/netinet/in.h) */
case IPPROTO_IPV6:/* IPv6 protocol socket options (see include/netinet/in.h) */
return ipv6_setsockopt(psock, option, value, value_len);
#endif
default:

View file

@ -67,12 +67,12 @@ static uint16_t g_ipid;
uint16_t ipv4_build_header(FAR struct ipv4_hdr_s *ipv4, uint16_t total_len,
uint16_t prot, FAR const in_addr_t *src_ip,
FAR const in_addr_t *dst_ip, uint8_t ttl,
FAR struct ipv4_opt_s *opt)
uint8_t tos, FAR struct ipv4_opt_s *opt)
{
/* Initialize the IP header. */
ipv4->vhl = 0x45; /* orginal initial value like this */
ipv4->tos = 0;
ipv4->tos = tos;
ipv4->len[0] = (total_len >> 8);
ipv4->len[1] = (total_len & 0xff);
++g_ipid;

View file

@ -84,6 +84,17 @@ int ipv4_getsockopt(FAR struct socket *psock, int option,
break;
#endif
case IP_TOS:
{
FAR struct socket_conn_s *conn =
(FAR struct socket_conn_s *)psock->s_conn;
*(FAR uint8_t *)value = conn->s_tos;
*value_len = 1;
ret = OK;
}
break;
default:
nerr("ERROR: Unrecognized IPv4 option: %d\n", option);
ret = -ENOPROTOOPT;

View file

@ -261,6 +261,26 @@ int ipv4_setsockopt(FAR struct socket *psock, int option,
}
break;
#endif
case IP_TOS:
{
FAR struct socket_conn_s *conn =
(FAR struct socket_conn_s *)psock->s_conn;
int tos;
tos = (value_len >= sizeof(int)) ?
*(FAR int *)value : (int)*(FAR unsigned char *)value;
if (tos < 0 || tos > 0xff)
{
nerr("ERROR: invalid tos:%d\n", tos);
ret = -EINVAL;
}
else
{
conn->s_tos = tos;
ret = OK;
}
}
break;
#ifdef CONFIG_NET_IPTABLES
case IPT_SO_SET_REPLACE:

View file

@ -48,6 +48,7 @@
* src_ip Source IPv6 address
* dst_ip Destination IPv6 address
* ttl Time to live(IPv4) hop limit(IPv6)
* tclass traffic class(IPv6)
*
* Returned Value:
* length of IPv6 header
@ -56,12 +57,13 @@
uint16_t ipv6_build_header(FAR struct ipv6_hdr_s *ipv6, uint16_t payload_len,
uint16_t prot, const net_ipv6addr_t src_ip,
const net_ipv6addr_t dst_ip, uint8_t ttl)
const net_ipv6addr_t dst_ip, uint8_t ttl,
uint8_t tclass)
{
/* Set up the IPv6 header */
ipv6->vtc = 0x60; /* Version/traffic class (MS) */
ipv6->tcf = 0; /* Traffic class(LS)/Flow label(MS) */
ipv6->tcf = tclass; /* Traffic class(LS)/Flow label(MS) */
ipv6->flow = 0; /* Flow label (LS) */
ipv6->len[0] = (payload_len >> 8); /* Length excludes the IPv6 header */
ipv6->len[1] = (payload_len & 0xff);

View file

@ -0,0 +1,99 @@
/****************************************************************************
* net/inet/ipv6_getsockopt.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <errno.h>
#include <debug.h>
#include <netinet/in.h>
#include <nuttx/net/net.h>
#include "mld/mld.h"
#include "inet/inet.h"
#include "udp/udp.h"
#ifdef CONFIG_NET_IPv6
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ipv6_getsockopt
*
* Description:
* ipv6_getsockopt() sets the IPv6-protocol socket option specified by the
* 'option' argument to the value pointed to by the 'value' argument for
* the socket specified by the 'psock' argument.
*
* See <netinet/in.h> for the a complete list of values of IPv6 protocol
* socket options.
*
* Input Parameters:
* psock Socket structure of socket to operate on
* option identifies the option to set
* value Points to the argument value
* value_len The length of the argument value
*
* Returned Value:
* Returns zero (OK) on success. On failure, it returns a negated errno
* value to indicate the nature of the error.
*
****************************************************************************/
int ipv6_getsockopt(FAR struct socket *psock, int option,
FAR void *value, FAR socklen_t *value_len)
{
int ret;
ninfo("option: %d\n", option);
net_lock();
switch (option)
{
case IPV6_TCLASS:
{
FAR struct socket_conn_s *conn =
(FAR struct socket_conn_s *)psock->s_conn;
*(FAR uint8_t *)value = conn->s_tclass;
*value_len = 1;
ret = OK;
}
break;
default:
nerr("ERROR: Unrecognized IPv6 option: %d\n", option);
ret = -ENOPROTOOPT;
break;
}
net_unlock();
return ret;
}
#endif /* CONFIG_NET_IPv6 */

View file

@ -69,16 +69,17 @@
int ipv6_setsockopt(FAR struct socket *psock, int option,
FAR const void *value, socklen_t value_len)
{
#ifdef CONFIG_NET_MLD
int ret;
ninfo("option: %d\n", option);
/* Handle MLD-related socket options */
net_lock();
switch (option)
{
#ifdef CONFIG_NET_MLD
/* Handle MLD-related socket options */
case IPV6_JOIN_GROUP: /* Join a multicast group */
{
FAR const struct ipv6_mreq *mrec ;
@ -111,6 +112,21 @@ int ipv6_setsockopt(FAR struct socket *psock, int option,
}
break;
/* The following IPv6 socket options are defined, but not implemented */
case IPV6_MULTICAST_HOPS: /* Multicast hop limit */
case IPV6_MULTICAST_IF: /* Interface to use for outgoing multicast
* packets */
case IPV6_MULTICAST_LOOP: /* Multicast packets are delivered back to
* the local application */
#endif
case IPV6_UNICAST_HOPS: /* Unicast hop limit */
case IPV6_V6ONLY: /* Restrict AF_INET6 socket to IPv6
* communications only */
nwarn("WARNING: Unimplemented IPv6 option: %d\n", option);
ret = -ENOSYS;
break;
#if defined(CONFIG_NET_UDP) && !defined(CONFIG_NET_UDP_NO_STACK)
case IPV6_PKTINFO:
case IPV6_RECVPKTINFO:
@ -142,18 +158,41 @@ int ipv6_setsockopt(FAR struct socket *psock, int option,
break;
#endif
/* The following IPv6 socket options are defined, but not implemented */
case IPV6_TCLASS:
{
FAR struct socket_conn_s *conn =
(FAR struct socket_conn_s *)psock->s_conn;
int tclass;
case IPV6_MULTICAST_HOPS: /* Multicast hop limit */
case IPV6_MULTICAST_IF: /* Interface to use for outgoing multicast
* packets */
case IPV6_MULTICAST_LOOP: /* Multicast packets are delivered back to
* the local application */
case IPV6_UNICAST_HOPS: /* Unicast hop limit */
case IPV6_V6ONLY: /* Restrict AF_INET6 socket to IPv6
* communications only */
nwarn("WARNING: Unimplemented IPv6 option: %d\n", option);
ret = -ENOSYS;
tclass = (value_len >= sizeof(int)) ?
*(FAR int *)value : (int)*(FAR unsigned char *)value;
/* According to RFC3542 6.5, the interpretation of the integer
* traffic class value is:
* x < -1: return an error of EINVAL
* x == -1: use kernel default
* 0 <= x <= 255: use x
* x >= 256: return an error of EINVAL
*/
if (tclass < -1 || tclass > 0xff)
{
nerr("ERROR: invalid tclass:%d\n", tclass);
ret = -EINVAL;
}
else
{
if (tclass == -1)
{
/* Default value is 0 */
tclass = 0;
}
conn->s_tclass = tclass;
ret = OK;
}
}
break;
default:
@ -164,9 +203,6 @@ int ipv6_setsockopt(FAR struct socket *psock, int option,
net_unlock();
return ret;
#else
return -ENOPROTOOPT;
#endif
}
#endif /* CONFIG_NET_IPv6 */

View file

@ -210,7 +210,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
destipaddr[4], destipaddr[5], destipaddr[6], destipaddr[7]);
ipv6_build_header(IPv6BUF, dev->d_sndlen, NEXT_HOPBYBOT_EH,
dev->d_ipv6addr, destipaddr, MLD_TTL);
dev->d_ipv6addr, destipaddr, MLD_TTL, 0);
/* Add the router alert IP header option.
*

View file

@ -1108,6 +1108,7 @@ ssize_t tcp_sendfile(FAR struct socket *psock, FAR struct file *infile,
*
* Input Parameters:
* dev - The device driver structure to use in the send operation
* conn - The TCP connection structure holding connection information
*
* Returned Value:
* None
@ -1117,7 +1118,7 @@ ssize_t tcp_sendfile(FAR struct socket *psock, FAR struct file *infile,
*
****************************************************************************/
void tcp_reset(FAR struct net_driver_s *dev);
void tcp_reset(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn);
/****************************************************************************
* Name: tcp_rx_mss

View file

@ -829,7 +829,7 @@ reset:
#ifdef CONFIG_NET_STATISTICS
g_netstats.tcp.synrst++;
#endif
tcp_reset(dev);
tcp_reset(dev, conn);
return;
found:
@ -1283,7 +1283,7 @@ found:
goto drop;
}
tcp_reset(dev);
tcp_reset(dev, conn);
return;
case TCP_ESTABLISHED:

View file

@ -182,7 +182,7 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
ninfo("do IPv6 IP header build!\n");
ipv6_build_header(IPv6BUF, dev->d_len - IPv6_HDRLEN,
IP_PROTO_TCP, dev->d_ipv6addr, conn->u.ipv6.raddr,
IP_TTL_DEFAULT);
IP_TTL_DEFAULT, conn->sconn.s_tclass);
/* Calculate TCP checksum. */
@ -202,7 +202,7 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
ninfo("do IPv4 IP header build!\n");
ipv4_build_header(IPv4BUF, dev->d_len, IP_PROTO_TCP,
&dev->d_ipaddr, &conn->u.ipv4.raddr,
IP_TTL_DEFAULT, NULL);
IP_TTL_DEFAULT, conn->sconn.s_tos, NULL);
/* Calculate TCP checksum. */
@ -360,7 +360,7 @@ void tcp_send(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
*
****************************************************************************/
void tcp_reset(FAR struct net_driver_s *dev)
void tcp_reset(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn)
{
FAR struct tcp_hdr_s *tcp;
uint32_t ackno;
@ -477,7 +477,7 @@ void tcp_reset(FAR struct net_driver_s *dev)
ipv6_build_header(ipv6, dev->d_len - IPv6_HDRLEN,
IP_PROTO_TCP, dev->d_ipv6addr, ipv6->srcipaddr,
IP_TTL_DEFAULT);
IP_TTL_DEFAULT, conn->sconn.s_tclass);
tcp->tcpchksum = 0;
tcp->tcpchksum = ~tcp_ipv6_chksum(dev);
@ -493,7 +493,7 @@ void tcp_reset(FAR struct net_driver_s *dev)
ipv4_build_header(IPv4BUF, dev->d_len, IP_PROTO_TCP,
&dev->d_ipaddr, (FAR in_addr_t *)ipv4->srcipaddr,
IP_TTL_DEFAULT, NULL);
IP_TTL_DEFAULT, conn->sconn.s_tos, NULL);
tcp->tcpchksum = 0;
tcp->tcpchksum = ~tcp_ipv4_chksum(dev);

View file

@ -124,7 +124,7 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn)
ipv4_build_header(IPv4BUF, dev->d_len, IP_PROTO_UDP,
&dev->d_ipaddr, &raddr, IP_TTL_DEFAULT,
NULL);
conn->sconn.s_tos, NULL);
#ifdef CONFIG_NET_STATISTICS
g_netstats.ipv4.sent++;
@ -149,7 +149,8 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn)
dev->d_len = dev->d_sndlen + UDP_HDRLEN;
ipv6_build_header(IPv6BUF, dev->d_len, IP_PROTO_UDP,
dev->d_ipv6addr, conn->u.ipv6.raddr, conn->ttl);
dev->d_ipv6addr, conn->u.ipv6.raddr, conn->ttl,
conn->sconn.s_tclass);
/* The total length to send is the size of the application data
* plus the IPv6 and UDP headers (and, eventually, the link layer