summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/mac
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2020-04-08 11:41:12 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2020-04-08 11:41:12 +0000
commit6b564a7014af2d4d9f000ed39a4fed77fd5245e0 (patch)
tree3805c7d1cab7ee8faf746ed3a1f0d1a448d4a8da /usr/src/uts/common/io/mac
parent4fc8237742a380d4833394892fb148e1a34acb28 (diff)
parent62366fbbe8edca853fee6c14327d822239ba914f (diff)
downloadillumos-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.c156
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, &ether) != 0)
+ return (-1);
+
+ if (ether == ETHERTYPE_VLAN) {
+ off = offsetof(struct ether_vlan_header, ether_type);
+ if (mac_meoi_get_uint16(mp, off, &ether) != 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);
+}