1e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes/* 2e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 3e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * The Regents of the University of California. All rights reserved. 4e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * 5e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * Redistribution and use in source and binary forms, with or without 6e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * modification, are permitted provided that: (1) source code distributions 7e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * retain the above copyright notice and this paragraph in its entirety, (2) 8e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * distributions including binary code include the above copyright notice and 9e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * this paragraph in its entirety in the documentation or other materials 10e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * provided with the distribution, and (3) all advertising materials mentioning 11e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * features or use of this software display the following acknowledgement: 12e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * ``This product includes software developed by the University of California, 13e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * the University nor the names of its contributors may be used to endorse 15e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * or promote products derived from this software without specific prior 16e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * written permission. 17e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes */ 21e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 22e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes/* \summary: Marvell Extended Distributed Switch Architecture (MEDSA) printer */ 23e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 24e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#ifdef HAVE_CONFIG_H 25e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#include "config.h" 26e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#endif 27e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 28e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#include <netdissect-stdinc.h> 29e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 30e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#include "netdissect.h" 31e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#include "ether.h" 32e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#include "ethertype.h" 33e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#include "addrtoname.h" 34e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#include "extract.h" 35e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 36e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughesstatic const char tstr[] = "[|MEDSA]"; 37e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 38e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes/* 39e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * Marvell Extended Distributed Switch Archiecture. 40e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * 41e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * A Marvell propriatary header used for passing packets to/from 42e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * specific ports of a switch. There is no open specification of this 43e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * header, but is documented in the Marvell Switch data sheets. For 44e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * background, see: 45e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * 46e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * https://lwn.net/Articles/302333/ 47e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes */ 48e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughesstruct medsa_pkthdr { 49e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes u_char bytes[6]; 50e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes u_short ether_type; 51e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes}; 52e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 53e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes/* Bytes 0 and 1 are reserved and should contain 0 */ 54e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define TAG(medsa) (medsa->bytes[2] >> 6) 55e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define TAG_TO_CPU 0 56e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define TAG_FROM_CPU 1 57e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define TAG_FORWARD 3 58e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define SRC_TAG(medsa) ((medsa->bytes[2] >> 5) & 0x01) 59e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define SRC_DEV(medsa) (medsa->bytes[2] & 0x1f) 60e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define SRC_PORT(medsa) ((medsa->bytes[3] >> 3) & 0x01f) 61e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define TRUNK(medsa) ((medsa->bytes[3] >> 2) & 0x01) 62e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define CODE(medsa) ((medsa->bytes[3] & 0x06) | \ 63e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ((medsa->bytes[4] >> 4) & 0x01)) 64e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define CODE_BDPU 0 65e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define CODE_IGMP_MLD 2 66e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define CODE_ARP_MIRROR 4 67e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define CFI(medsa) (medsa->bytes[3] & 0x01) 68e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define PRI(medsa) (medsa->bytes[4] >> 5) 69e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes#define VID(medsa) (((u_short)(medsa->bytes[4] & 0xf) << 8 | \ 70e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes medsa->bytes[5])) 71e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 72e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughesstatic const struct tok tag_values[] = { 73e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes { TAG_TO_CPU, "To_CPU" }, 74e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes { TAG_FROM_CPU, "From_CPU" }, 75e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes { TAG_FORWARD, "Forward" }, 76e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes { 0, NULL }, 77e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes}; 78e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 79e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughesstatic const struct tok code_values[] = { 80e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes { CODE_BDPU, "BDPU" }, 81e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes { CODE_IGMP_MLD, "IGMP/MLD" }, 82e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes { CODE_ARP_MIRROR, "APR_Mirror" }, 83e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes { 0, NULL }, 84e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes}; 85e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 86e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughesstatic void 87e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughesmedsa_print_full(netdissect_options *ndo, 88e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes const struct medsa_pkthdr *medsa, 89e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes u_int caplen) 90e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes{ 91e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes u_char tag = TAG(medsa); 92e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 93e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, "%s", 94e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes tok2str(tag_values, "Unknown (%u)", tag))); 95e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 96e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes switch (tag) { 97e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes case TAG_TO_CPU: 98e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", %stagged", SRC_TAG(medsa) ? "" : "un")); 99e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", dev.port:vlan %d.%d:%d", 100e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa))); 101e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 102e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", %s", 103e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes tok2str(code_values, "Unknown (%u)", CODE(medsa)))); 104e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (CFI(medsa)) 105e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", CFI")); 106e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 107e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", pri %d: ", PRI(medsa))); 108e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes break; 109e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes case TAG_FROM_CPU: 110e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", %stagged", SRC_TAG(medsa) ? "" : "un")); 111e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", dev.port:vlan %d.%d:%d", 112e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa))); 113e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 114e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (CFI(medsa)) 115e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", CFI")); 116e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 117e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", pri %d: ", PRI(medsa))); 118e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes break; 119e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes case TAG_FORWARD: 120e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", %stagged", SRC_TAG(medsa) ? "" : "un")); 121e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (TRUNK(medsa)) 122e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", dev.trunk:vlan %d.%d:%d", 123e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa))); 124e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes else 125e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", dev.port:vlan %d.%d:%d", 126e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa))); 127e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 128e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (CFI(medsa)) 129e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", CFI")); 130e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 131e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, ", pri %d: ", PRI(medsa))); 132e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes break; 133e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes default: 134e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_DEFAULTPRINT((const u_char *)medsa, caplen); 135e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes return; 136e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes } 137e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes} 138e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 139e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughesvoid 140e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughesmedsa_print(netdissect_options *ndo, 141e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes const u_char *bp, u_int length, u_int caplen, 142e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes const struct lladdr_info *src, const struct lladdr_info *dst) 143e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes{ 144e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes const struct medsa_pkthdr *medsa; 145e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes u_short ether_type; 146e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 147e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes medsa = (const struct medsa_pkthdr *)bp; 148e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_TCHECK(*medsa); 149e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 150e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (!ndo->ndo_eflag) 151e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, "MEDSA %d.%d:%d: ", 152e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes SRC_DEV(medsa), SRC_PORT(medsa), VID(medsa))); 153e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes else 154e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes medsa_print_full(ndo, medsa, caplen); 155e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 156e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes bp += 8; 157e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes length -= 8; 158e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes caplen -= 8; 159e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 160e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ether_type = EXTRACT_16BITS(&medsa->ether_type); 161e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (ether_type <= ETHERMTU) { 162e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes /* Try to print the LLC-layer header & higher layers */ 163e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (llc_print(ndo, bp, length, caplen, src, dst) < 0) { 164e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes /* packet type not known, print raw packet */ 165e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (!ndo->ndo_suppress_default_print) 166e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_DEFAULTPRINT(bp, caplen); 167e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes } 168e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes } else { 169e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (ndo->ndo_eflag) 170e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, "ethertype %s (0x%04x) ", 171e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes tok2str(ethertype_values, "Unknown", 172e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ether_type), 173e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ether_type)); 174e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (ethertype_print(ndo, ether_type, bp, length, caplen, src, dst) == 0) { 175e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes /* ether_type not known, print raw packet */ 176e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (!ndo->ndo_eflag) 177e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, "ethertype %s (0x%04x) ", 178e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes tok2str(ethertype_values, "Unknown", 179e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ether_type), 180e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ether_type)); 181e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 182e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes if (!ndo->ndo_suppress_default_print) 183e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_DEFAULTPRINT(bp, caplen); 184e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes } 185e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes } 186e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes return; 187e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughestrunc: 188e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes ND_PRINT((ndo, "%s", tstr)); 189e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes} 190e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 191e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes/* 192e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * Local Variables: 193e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * c-style: bsd 194e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes * End: 195e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes */ 196e2e3bd11bd7561bc9d6686283a668fa94e1206b7Elliott Hughes 197