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