1/*
2 * Copyright (c) 1990, 1991, 1992, 1994, 1995, 1996
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#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include <pcap-types.h>
27
28#include <stdio.h>
29#include <string.h>
30
31#ifdef __linux__
32#include <linux/types.h>
33#include <linux/if_packet.h>
34#include <linux/filter.h>
35
36/*
37 * We want our versions of these #defines, not Linux's version.
38 * (The two should be the same; if not, we have a problem; all BPF
39 * implementations *should* be source-compatible supersets of ours.)
40 */
41#undef BPF_STMT
42#undef BPF_JUMP
43#endif
44
45#include "pcap-int.h"
46
47#ifdef HAVE_OS_PROTO_H
48#include "os-proto.h"
49#endif
50
51#ifdef SKF_AD_OFF
52/*
53 * Symbolic names for offsets that refer to the special Linux BPF locations.
54 */
55static const char *offsets[SKF_AD_MAX] = {
56#ifdef SKF_AD_PROTOCOL
57	[SKF_AD_PROTOCOL] = "proto",
58#endif
59#ifdef SKF_AD_PKTTYPE
60	[SKF_AD_PKTTYPE] = "type",
61#endif
62#ifdef SKF_AD_IFINDEX
63	[SKF_AD_IFINDEX] = "ifidx",
64#endif
65#ifdef SKF_AD_NLATTR
66	[SKF_AD_NLATTR] = "nla",
67#endif
68#ifdef SKF_AD_NLATTR_NEST
69	[SKF_AD_NLATTR_NEST] = "nlan",
70#endif
71#ifdef SKF_AD_MARK
72	[SKF_AD_MARK] = "mark",
73#endif
74#ifdef SKF_AD_QUEUE
75	[SKF_AD_QUEUE] = "queue",
76#endif
77#ifdef SKF_AD_HATYPE
78	[SKF_AD_HATYPE] = "hatype",
79#endif
80#ifdef SKF_AD_RXHASH
81	[SKF_AD_RXHASH] = "rxhash",
82#endif
83#ifdef SKF_AD_CPU
84	[SKF_AD_CPU] = "cpu",
85#endif
86#ifdef SKF_AD_ALU_XOR_X
87	[SKF_AD_ALU_XOR_X] = "xor_x",
88#endif
89#ifdef SKF_AD_VLAN_TAG
90	[SKF_AD_VLAN_TAG] = "vlan_tci",
91#endif
92#ifdef SKF_AD_VLAN_TAG_PRESENT
93	[SKF_AD_VLAN_TAG_PRESENT] = "vlanp",
94#endif
95#ifdef SKF_AD_PAY_OFFSET
96	[SKF_AD_PAY_OFFSET] = "poff",
97#endif
98#ifdef SKF_AD_RANDOM
99	[SKF_AD_RANDOM] = "random",
100#endif
101#ifdef SKF_AD_VLAN_TPID
102	[SKF_AD_VLAN_TPID] = "vlan_tpid"
103#endif
104};
105#endif
106
107static void
108bpf_print_abs_load_operand(char *buf, size_t bufsize, const struct bpf_insn *p)
109{
110#ifdef SKF_AD_OFF
111	const char *sym;
112
113	/*
114	 * It's an absolute load.
115	 * Is the offset a special Linux offset that we know about?
116	 */
117	if (p->k >= (bpf_u_int32)SKF_AD_OFF &&
118	    p->k < (bpf_u_int32)(SKF_AD_OFF + SKF_AD_MAX) &&
119	    (sym = offsets[p->k - (bpf_u_int32)SKF_AD_OFF]) != NULL) {
120		/*
121		 * Yes.  Print the offset symbolically.
122		 */
123		(void)snprintf(buf, bufsize, "[%s]", sym);
124	} else
125#endif
126		(void)snprintf(buf, bufsize, "[%d]", p->k);
127}
128
129char *
130bpf_image(const struct bpf_insn *p, int n)
131{
132	const char *op;
133	static char image[256];
134	char operand_buf[64];
135	const char *operand;
136
137	switch (p->code) {
138
139	default:
140		op = "unimp";
141		(void)snprintf(operand_buf, sizeof operand_buf, "0x%x", p->code);
142		operand = operand_buf;
143		break;
144
145	case BPF_RET|BPF_K:
146		op = "ret";
147		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
148		operand = operand_buf;
149		break;
150
151	case BPF_RET|BPF_A:
152		op = "ret";
153		operand = "";
154		break;
155
156	case BPF_LD|BPF_W|BPF_ABS:
157		op = "ld";
158		bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
159		operand = operand_buf;
160		break;
161
162	case BPF_LD|BPF_H|BPF_ABS:
163		op = "ldh";
164		bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
165		operand = operand_buf;
166		break;
167
168	case BPF_LD|BPF_B|BPF_ABS:
169		op = "ldb";
170		bpf_print_abs_load_operand(operand_buf, sizeof operand_buf, p);
171		operand = operand_buf;
172		break;
173
174	case BPF_LD|BPF_W|BPF_LEN:
175		op = "ld";
176		operand = "#pktlen";
177		break;
178
179	case BPF_LD|BPF_W|BPF_IND:
180		op = "ld";
181		(void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
182		operand = operand_buf;
183		break;
184
185	case BPF_LD|BPF_H|BPF_IND:
186		op = "ldh";
187		(void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
188		operand = operand_buf;
189		break;
190
191	case BPF_LD|BPF_B|BPF_IND:
192		op = "ldb";
193		(void)snprintf(operand_buf, sizeof operand_buf, "[x + %d]", p->k);
194		operand = operand_buf;
195		break;
196
197	case BPF_LD|BPF_IMM:
198		op = "ld";
199		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
200		operand = operand_buf;
201		break;
202
203	case BPF_LDX|BPF_IMM:
204		op = "ldx";
205		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
206		operand = operand_buf;
207		break;
208
209	case BPF_LDX|BPF_MSH|BPF_B:
210		op = "ldxb";
211		(void)snprintf(operand_buf, sizeof operand_buf, "4*([%d]&0xf)", p->k);
212		operand = operand_buf;
213		break;
214
215	case BPF_LD|BPF_MEM:
216		op = "ld";
217		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
218		operand = operand_buf;
219		break;
220
221	case BPF_LDX|BPF_MEM:
222		op = "ldx";
223		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
224		operand = operand_buf;
225		break;
226
227	case BPF_ST:
228		op = "st";
229		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
230		operand = operand_buf;
231		break;
232
233	case BPF_STX:
234		op = "stx";
235		(void)snprintf(operand_buf, sizeof operand_buf, "M[%d]", p->k);
236		operand = operand_buf;
237		break;
238
239	case BPF_JMP|BPF_JA:
240		op = "ja";
241		(void)snprintf(operand_buf, sizeof operand_buf, "%d", n + 1 + p->k);
242		operand = operand_buf;
243		break;
244
245	case BPF_JMP|BPF_JGT|BPF_K:
246		op = "jgt";
247		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
248		operand = operand_buf;
249		break;
250
251	case BPF_JMP|BPF_JGE|BPF_K:
252		op = "jge";
253		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
254		operand = operand_buf;
255		break;
256
257	case BPF_JMP|BPF_JEQ|BPF_K:
258		op = "jeq";
259		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
260		operand = operand_buf;
261		break;
262
263	case BPF_JMP|BPF_JSET|BPF_K:
264		op = "jset";
265		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
266		operand = operand_buf;
267		break;
268
269	case BPF_JMP|BPF_JGT|BPF_X:
270		op = "jgt";
271		operand = "x";
272		break;
273
274	case BPF_JMP|BPF_JGE|BPF_X:
275		op = "jge";
276		operand = "x";
277		break;
278
279	case BPF_JMP|BPF_JEQ|BPF_X:
280		op = "jeq";
281		operand = "x";
282		break;
283
284	case BPF_JMP|BPF_JSET|BPF_X:
285		op = "jset";
286		operand = "x";
287		break;
288
289	case BPF_ALU|BPF_ADD|BPF_X:
290		op = "add";
291		operand = "x";
292		break;
293
294	case BPF_ALU|BPF_SUB|BPF_X:
295		op = "sub";
296		operand = "x";
297		break;
298
299	case BPF_ALU|BPF_MUL|BPF_X:
300		op = "mul";
301		operand = "x";
302		break;
303
304	case BPF_ALU|BPF_DIV|BPF_X:
305		op = "div";
306		operand = "x";
307		break;
308
309	case BPF_ALU|BPF_MOD|BPF_X:
310		op = "mod";
311		operand = "x";
312		break;
313
314	case BPF_ALU|BPF_AND|BPF_X:
315		op = "and";
316		operand = "x";
317		break;
318
319	case BPF_ALU|BPF_OR|BPF_X:
320		op = "or";
321		operand = "x";
322		break;
323
324	case BPF_ALU|BPF_XOR|BPF_X:
325		op = "xor";
326		operand = "x";
327		break;
328
329	case BPF_ALU|BPF_LSH|BPF_X:
330		op = "lsh";
331		operand = "x";
332		break;
333
334	case BPF_ALU|BPF_RSH|BPF_X:
335		op = "rsh";
336		operand = "x";
337		break;
338
339	case BPF_ALU|BPF_ADD|BPF_K:
340		op = "add";
341		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
342		operand = operand_buf;
343		break;
344
345	case BPF_ALU|BPF_SUB|BPF_K:
346		op = "sub";
347		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
348		operand = operand_buf;
349		break;
350
351	case BPF_ALU|BPF_MUL|BPF_K:
352		op = "mul";
353		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
354		operand = operand_buf;
355		break;
356
357	case BPF_ALU|BPF_DIV|BPF_K:
358		op = "div";
359		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
360		operand = operand_buf;
361		break;
362
363	case BPF_ALU|BPF_MOD|BPF_K:
364		op = "mod";
365		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
366		operand = operand_buf;
367		break;
368
369	case BPF_ALU|BPF_AND|BPF_K:
370		op = "and";
371		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
372		operand = operand_buf;
373		break;
374
375	case BPF_ALU|BPF_OR|BPF_K:
376		op = "or";
377		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
378		operand = operand_buf;
379		break;
380
381	case BPF_ALU|BPF_XOR|BPF_K:
382		op = "xor";
383		(void)snprintf(operand_buf, sizeof operand_buf, "#0x%x", p->k);
384		operand = operand_buf;
385		break;
386
387	case BPF_ALU|BPF_LSH|BPF_K:
388		op = "lsh";
389		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
390		operand = operand_buf;
391		break;
392
393	case BPF_ALU|BPF_RSH|BPF_K:
394		op = "rsh";
395		(void)snprintf(operand_buf, sizeof operand_buf, "#%d", p->k);
396		operand = operand_buf;
397		break;
398
399	case BPF_ALU|BPF_NEG:
400		op = "neg";
401		operand = "";
402		break;
403
404	case BPF_MISC|BPF_TAX:
405		op = "tax";
406		operand = "";
407		break;
408
409	case BPF_MISC|BPF_TXA:
410		op = "txa";
411		operand = "";
412		break;
413	}
414	if (BPF_CLASS(p->code) == BPF_JMP && BPF_OP(p->code) != BPF_JA) {
415		(void)snprintf(image, sizeof image,
416			      "(%03d) %-8s %-16s jt %d\tjf %d",
417			      n, op, operand, n + 1 + p->jt, n + 1 + p->jf);
418	} else {
419		(void)snprintf(image, sizeof image,
420			      "(%03d) %-8s %s",
421			      n, op, operand);
422	}
423	return image;
424}
425