Home | History | Annotate | Download | only in tcpdump
      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