diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2020-04-08 11:41:12 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2020-04-08 11:41:12 +0000 |
commit | 6b564a7014af2d4d9f000ed39a4fed77fd5245e0 (patch) | |
tree | 3805c7d1cab7ee8faf746ed3a1f0d1a448d4a8da /usr/src/uts/common/io/mac | |
parent | 4fc8237742a380d4833394892fb148e1a34acb28 (diff) | |
parent | 62366fbbe8edca853fee6c14327d822239ba914f (diff) | |
download | illumos-joyent-release-20200409.tar.gz |
[illumos-gate merge]release-20200409
commit 62366fbbe8edca853fee6c14327d822239ba914f
12466 Enable IPv6 TSO Support for vioif
commit d240edaf609c558d5a1f981b09a577823b54fae2
12465 vioif needs length for tso checksum
commit 425251fd07ab465313fb50dea0f1ac795be10e05
9059 Simplify SMAP relocations with krtld
commit 28e0ac9c914344194ef919b0271895d33f83d396
12433 efcode: NULL pointer errors
commit 31aa620247ae407b2bee2dccd71693d1938f54d6
12452 Want support for AMD Zen 2 CPC Events
Conflicts:
usr/src/uts/i86pc/os/machdep.c
usr/src/uts/common/io/dld/dld_proto.c
usr/src/uts/common/inet/ip/ip_if.c
Diffstat (limited to 'usr/src/uts/common/io/mac')
-rw-r--r-- | usr/src/uts/common/io/mac/mac_provider.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/usr/src/uts/common/io/mac/mac_provider.c b/usr/src/uts/common/io/mac/mac_provider.c index 0f917cd8ca..7f193f68eb 100644 --- a/usr/src/uts/common/io/mac/mac_provider.c +++ b/usr/src/uts/common/io/mac/mac_provider.c @@ -58,6 +58,10 @@ #include <sys/pattr.h> #include <sys/strsun.h> #include <sys/vlan.h> +#include <inet/ip.h> +#include <inet/tcp.h> +#include <netinet/udp.h> +#include <netinet/sctp.h> /* * MAC Provider Interface. @@ -1653,3 +1657,155 @@ mac_transceiver_info_set_usable(mac_transceiver_info_t *infop, { infop->mti_usable = usable; } + +/* + * We should really keep track of our offset and not walk everything every + * time. I can't imagine that this will be kind to us at high packet rates; + * however, for the moment, let's leave that. + * + * This walks a message block chain without pulling up to fill in the context + * information. Note that the data we care about could be hidden across more + * than one mblk_t. + */ +static int +mac_meoi_get_uint8(mblk_t *mp, off_t off, uint8_t *out) +{ + size_t mpsize; + uint8_t *bp; + + mpsize = msgsize(mp); + /* Check for overflow */ + if (off + sizeof (uint16_t) > mpsize) + return (-1); + + mpsize = MBLKL(mp); + while (off >= mpsize) { + mp = mp->b_cont; + off -= mpsize; + mpsize = MBLKL(mp); + } + + bp = mp->b_rptr + off; + *out = *bp; + return (0); + +} + +static int +mac_meoi_get_uint16(mblk_t *mp, off_t off, uint16_t *out) +{ + size_t mpsize; + uint8_t *bp; + + mpsize = msgsize(mp); + /* Check for overflow */ + if (off + sizeof (uint16_t) > mpsize) + return (-1); + + mpsize = MBLKL(mp); + while (off >= mpsize) { + mp = mp->b_cont; + off -= mpsize; + mpsize = MBLKL(mp); + } + + /* + * Data is in network order. Note the second byte of data might be in + * the next mp. + */ + bp = mp->b_rptr + off; + *out = *bp << 8; + if (off + 1 == mpsize) { + mp = mp->b_cont; + bp = mp->b_rptr; + } else { + bp++; + } + + *out |= *bp; + return (0); + +} + + +int +mac_ether_offload_info(mblk_t *mp, mac_ether_offload_info_t *meoi) +{ + size_t off; + uint16_t ether; + uint8_t ipproto, iplen, l4len, maclen; + + bzero(meoi, sizeof (mac_ether_offload_info_t)); + + meoi->meoi_len = msgsize(mp); + off = offsetof(struct ether_header, ether_type); + if (mac_meoi_get_uint16(mp, off, ðer) != 0) + return (-1); + + if (ether == ETHERTYPE_VLAN) { + off = offsetof(struct ether_vlan_header, ether_type); + if (mac_meoi_get_uint16(mp, off, ðer) != 0) + return (-1); + meoi->meoi_flags |= MEOI_VLAN_TAGGED; + maclen = sizeof (struct ether_vlan_header); + } else { + maclen = sizeof (struct ether_header); + } + meoi->meoi_flags |= MEOI_L2INFO_SET; + meoi->meoi_l2hlen = maclen; + meoi->meoi_l3proto = ether; + + switch (ether) { + case ETHERTYPE_IP: + /* + * For IPv4 we need to get the length of the header, as it can + * be variable. + */ + off = offsetof(ipha_t, ipha_version_and_hdr_length) + maclen; + if (mac_meoi_get_uint8(mp, off, &iplen) != 0) + return (-1); + iplen &= 0x0f; + if (iplen < 5 || iplen > 0x0f) + return (-1); + iplen *= 4; + off = offsetof(ipha_t, ipha_protocol) + maclen; + if (mac_meoi_get_uint8(mp, off, &ipproto) == -1) + return (-1); + break; + case ETHERTYPE_IPV6: + iplen = 40; + off = offsetof(ip6_t, ip6_nxt) + maclen; + if (mac_meoi_get_uint8(mp, off, &ipproto) == -1) + return (-1); + break; + default: + return (0); + } + meoi->meoi_l3hlen = iplen; + meoi->meoi_l4proto = ipproto; + meoi->meoi_flags |= MEOI_L3INFO_SET; + + switch (ipproto) { + case IPPROTO_TCP: + off = offsetof(tcph_t, th_offset_and_rsrvd) + maclen + iplen; + if (mac_meoi_get_uint8(mp, off, &l4len) == -1) + return (-1); + l4len = (l4len & 0xf0) >> 4; + if (l4len < 5 || l4len > 0xf) + return (-1); + l4len *= 4; + break; + case IPPROTO_UDP: + l4len = sizeof (struct udphdr); + break; + case IPPROTO_SCTP: + l4len = sizeof (sctp_hdr_t); + break; + default: + return (0); + } + + meoi->meoi_l4hlen = l4len; + meoi->meoi_flags |= MEOI_L4INFO_SET; + return (0); +} |