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