1/*
2 * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10#include "internal/internal.h"
11#include "internal/stack.h"
12#include <linux/filter.h>
13#include <stddef.h>		/* offsetof */
14
15#ifndef SKF_AD_NLATTR
16#define SKF_AD_NLATTR		12
17#endif
18
19/* this requires a Linux kernel >= 2.6.29 */
20#ifndef SKF_AD_NLATTR_NEST
21#define SKF_AD_NLATTR_NEST	16
22#endif
23
24#define NFCT_FILTER_REJECT	0U
25#define NFCT_FILTER_ACCEPT	~0U
26
27#if 0
28static char *code2str(uint16_t code)
29{
30	switch(code) {
31	case BPF_LD|BPF_IMM:
32		return "BPF_LD|BPF_IMM";
33		break;
34	case BPF_LDX|BPF_IMM:
35		return "BPF_LDX|BPF_IMM";
36		break;
37	case BPF_LD|BPF_B|BPF_ABS:
38		return "BPF_LD|BPF_B|BPF_ABS";
39		break;
40	case BPF_JMP|BPF_JEQ|BPF_K:
41		return "BPF_JMP|BPF_JEQ|BPF_K";
42		break;
43	case BPF_ALU|BPF_AND|BPF_K:
44		return "BPF_ALU|BPF_AND|BPF_K";
45		break;
46	case BPF_JMP|BPF_JA:
47		return "BPF_JMP|BPF_JA";
48		break;
49	case BPF_RET|BPF_K:
50		return "BPF_RET|BPF_K";
51		break;
52	case BPF_ALU|BPF_ADD|BPF_K:
53		return "BPF_ALU|BPF_ADD|BPF_K";
54		break;
55	case BPF_MISC|BPF_TAX:
56		return "BPF_MISC|BPF_TAX";
57		break;
58	case BPF_MISC|BPF_TXA:
59		return "BPF_MISC|BPF_TXA";
60		break;
61	case BPF_LD|BPF_B|BPF_IND:
62		return "BPF_LD|BPF_B|BPF_IND";
63		break;
64	case BPF_LD|BPF_H|BPF_IND:
65		return "BPF_LD|BPF_H|BPF_IND";
66		break;
67	case BPF_LD|BPF_W|BPF_IND:
68		return "BPF_LD|BPF_W|BPF_IND";
69		break;
70	}
71	return NULL;
72}
73
74static void show_filter(struct sock_filter *this, int from, int to, char *str)
75{
76	int i;
77
78	printf("%s\n", str);
79
80	for(i=from; i<to; i++) {
81		char *code_str = code2str(this[i].code & 0xFFFF);
82
83		if (!code_str) {
84			printf("(%.4x) code=%.4x\t\t\tjt=%.2x jf=%.2x k=%.8x\n",
85						i,
86						this[i].code & 0xFFFF,
87						this[i].jt   & 0xFF,
88						this[i].jf   & 0xFF,
89						this[i].k    & 0xFFFFFFFF);
90		} else {
91			printf("(%.4x) code=%30s\tjt=%.2x jf=%.2x k=%.8x\n",
92						i,
93						code_str,
94						this[i].jt   & 0xFF,
95						this[i].jf   & 0xFF,
96						this[i].k    & 0xFFFFFFFF);
97		}
98	}
99}
100#else
101static inline void
102show_filter(struct sock_filter *this, int from, int to, char *str) {}
103#endif
104
105#define NEW_POS(x) (sizeof(x)/sizeof(struct sock_filter))
106
107static int
108nfct_bsf_load_payload_offset(struct sock_filter *this, int pos)
109{
110	struct sock_filter __code = {
111		.code 	= BPF_LD|BPF_IMM,
112		.k 	= sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg),
113	};
114	memcpy(&this[pos], &__code, sizeof(__code));
115	return NEW_POS(__code);
116}
117
118static int
119nfct_bsf_find_attr(struct sock_filter *this, int attr, int pos)
120{
121	struct sock_filter __code[] = {
122		[0] = {
123			/* X = attribute type */
124			.code	= BPF_LDX|BPF_IMM,
125			.k	= attr,
126		},
127		[1] = {
128			/* A = netlink attribute offset */
129			.code	= BPF_LD|BPF_B|BPF_ABS,
130			.k	= SKF_AD_OFF + SKF_AD_NLATTR,
131		}
132	};
133	memcpy(&this[pos], __code, sizeof(__code));
134	return NEW_POS(__code);
135}
136
137/* like the previous, but limit the search to the bound of the nest */
138static int
139nfct_bsf_find_attr_nest(struct sock_filter *this, int attr, int pos)
140{
141	struct sock_filter __code[] = {
142		[0] = {
143			/* X = attribute type */
144			.code	= BPF_LDX|BPF_IMM,
145			.k	= attr,
146		},
147		[1] = {
148			/* A = netlink attribute offset */
149			.code	= BPF_LD|BPF_B|BPF_ABS,
150			.k	= SKF_AD_OFF + SKF_AD_NLATTR_NEST,
151		}
152	};
153	memcpy(&this[pos], __code, sizeof(__code));
154	return NEW_POS(__code);
155}
156
157struct jump {
158	int line;
159	uint8_t jt;
160	uint8_t jf;
161};
162
163static int
164nfct_bsf_cmp_k_stack(struct sock_filter *this, int k,
165	       int jump_true, int pos, struct stack *s)
166{
167	struct sock_filter __code = {
168		.code	= BPF_JMP|BPF_JEQ|BPF_K,
169		.k	= k,
170	};
171	struct jump jmp = {
172		.line	= pos,
173		.jt	= jump_true - 1,
174		.jf	= 0,
175	};
176	stack_push(s, &jmp);
177	memcpy(&this[pos], &__code, sizeof(__code));
178	return NEW_POS(__code);
179}
180
181/* like previous, but use jf instead of jt. We can merge both functions */
182static int
183nfct_bsf_cmp_k_stack_jf(struct sock_filter *this, int k,
184			int jump_false, int pos, struct stack *s)
185{
186	struct sock_filter __code = {
187		.code	= BPF_JMP|BPF_JEQ|BPF_K,
188		.k	= k,
189	};
190	struct jump jmp = {
191		.line	= pos,
192		.jt	= 0,
193		.jf	= jump_false - 1,
194	};
195	stack_push(s, &jmp);
196	memcpy(&this[pos], &__code, sizeof(__code));
197	return NEW_POS(__code);
198}
199
200static int
201nfct_bsf_alu_and(struct sock_filter *this, int k, int pos)
202{
203	struct sock_filter __code = {
204		.code 	= BPF_ALU|BPF_AND|BPF_K,
205		.k	= k,
206	};
207	memcpy(&this[pos], &__code, sizeof(__code));
208	return NEW_POS(__code);
209}
210
211static int
212nfct_bsf_add_attr_data_offset(struct sock_filter *this, int pos)
213{
214	struct sock_filter __code = {
215		/* A += sizeof(struct nfattr) */
216		.code	= BPF_ALU|BPF_ADD|BPF_K,
217		.k	= sizeof(struct nfattr),
218	};
219	memcpy(&this[pos], &__code, sizeof(__code));
220	return NEW_POS(__code);
221}
222
223static int
224nfct_bsf_x_equal_a(struct sock_filter *this, int pos)
225{
226	struct sock_filter __code = {
227		.code	= BPF_MISC|BPF_TAX,
228	};
229	memcpy(&this[pos], &__code, sizeof(__code));
230	return NEW_POS(__code);
231}
232
233static int
234nfct_bsf_a_equal_x(struct sock_filter *this, int pos)
235{
236	struct sock_filter __code = {
237		.code	= BPF_MISC|BPF_TXA,
238	};
239	memcpy(&this[pos], &__code, sizeof(__code));
240	return NEW_POS(__code);
241}
242
243static int
244nfct_bsf_load_attr(struct sock_filter *this, int word_size, int pos)
245{
246	struct sock_filter __code = {
247		/* A = skb->data[X + k:word_size] */
248		.code	= BPF_LD|word_size|BPF_IND,
249		.k	= sizeof(struct nfattr),
250
251	};
252	memcpy(&this[pos], &__code, sizeof(__code));
253	return NEW_POS(__code);
254}
255
256static int
257nfct_bsf_load_attr_offset(struct sock_filter *this, int word_size,
258			  int offset, int pos)
259{
260	struct sock_filter __code = {
261		/* A = skb->data[X + k:word_size] */
262		.code	= BPF_LD|word_size|BPF_IND,
263		.k	= sizeof(struct nfattr) + offset,
264	};
265	memcpy(&this[pos], &__code, sizeof(__code));
266	return NEW_POS(__code);
267}
268
269static int
270nfct_bsf_ret_verdict(struct sock_filter *this, int verdict, int pos)
271{
272	struct sock_filter __code = {
273		.code	= BPF_RET|BPF_K,
274		.k	= verdict,
275	};
276	memcpy(&this[pos], &__code, sizeof(__code));
277	return NEW_POS(__code);
278}
279
280static int
281nfct_bsf_jump_to(struct sock_filter *this, int line, int pos)
282{
283	struct sock_filter __code = {
284		.code	= BPF_JMP|BPF_JA,
285		.k	= line,
286	};
287	memcpy(&this[pos], &__code, sizeof(__code));
288	return NEW_POS(__code);
289};
290
291/* this helps to skip messages coming from the ctnetlink expectation subsys. */
292static int
293bsf_cmp_subsys(struct sock_filter *this, int pos, uint8_t subsys)
294{
295	struct sock_filter __code[] = {
296		[0] = {
297			/* X = offset to nlh->nlmsg_type */
298			.code	= BPF_LDX|BPF_IMM,
299			.k	= offsetof(struct nlmsghdr, nlmsg_type),
300		},
301		[1] = {
302			/* A = skb->data[X+k:B] (subsys_id) */
303			.code	= BPF_LD|BPF_B|BPF_IND,
304			.k	= sizeof(uint8_t),
305		},
306		[2] = {
307			/* A == subsys ? jump +1 : accept */
308			.code	= BPF_JMP|BPF_JEQ|BPF_K,
309			.k	= subsys,
310			.jt	= 1,
311			.jf	= 0,
312		},
313	};
314	memcpy(&this[pos], &__code, sizeof(__code));
315	return NEW_POS(__code);
316}
317
318static int
319add_state_filter_cta(struct sock_filter *this,
320		     unsigned int cta_protoinfo_proto,
321		     unsigned int cta_protoinfo_state,
322		     uint16_t state_flags,
323		     unsigned int logic)
324{
325	unsigned int i, j;
326	unsigned int label_continue, jt;
327	struct stack *s;
328	struct jump jmp;
329
330	/* XXX: 32 maximum states + 3 jumps in the three-level iteration */
331	s = stack_create(sizeof(struct jump), 3 + 32);
332	if (s == NULL) {
333		errno = ENOMEM;
334		return -1;
335	}
336
337	jt = 1;
338	if (logic == NFCT_FILTER_LOGIC_POSITIVE)
339		label_continue = 1;
340	else
341		label_continue = 2;
342
343	j = 0;
344	j += nfct_bsf_load_payload_offset(this, j);
345	j += nfct_bsf_find_attr(this, CTA_PROTOINFO, j);
346	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
347	j += nfct_bsf_add_attr_data_offset(this, j);
348	j += nfct_bsf_find_attr(this, cta_protoinfo_proto, j);
349	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
350	j += nfct_bsf_add_attr_data_offset(this, j);
351	j += nfct_bsf_find_attr(this, cta_protoinfo_state, j);
352	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
353	j += nfct_bsf_x_equal_a(this, j);
354	j += nfct_bsf_load_attr(this, BPF_B, j);
355
356	for (i = 0; i < sizeof(state_flags) * 8; i++) {
357		if (state_flags & (1 << i)) {
358			j += nfct_bsf_cmp_k_stack(this, i, jt - j, j, s);
359		}
360	}
361
362	while (stack_pop(s, &jmp) != -1)
363		this[jmp.line].jt += jmp.jt + j;
364
365	if (logic == NFCT_FILTER_LOGIC_NEGATIVE)
366		j += nfct_bsf_jump_to(this, 1, j);
367
368	j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
369
370	stack_destroy(s);
371
372	return j;
373}
374
375static int
376add_state_filter(struct sock_filter *this,
377		 int proto,
378		 uint16_t flags,
379		 unsigned int logic)
380{
381	static const struct {
382		unsigned int cta_protoinfo;
383		unsigned int cta_state;
384	} cta[IPPROTO_MAX] = {
385		[IPPROTO_TCP] = {
386			.cta_protoinfo = CTA_PROTOINFO_TCP,
387			.cta_state = CTA_PROTOINFO_TCP_STATE,
388		},
389		[IPPROTO_SCTP] = {
390			.cta_protoinfo = CTA_PROTOINFO_SCTP,
391			.cta_state = CTA_PROTOINFO_SCTP_STATE,
392		},
393		[IPPROTO_DCCP] = {
394			.cta_protoinfo = CTA_PROTOINFO_DCCP,
395			.cta_state = CTA_PROTOINFO_DCCP_STATE,
396		},
397	};
398
399	if (cta[proto].cta_protoinfo == 0 && cta[proto].cta_state == 0) {
400		errno = ENOTSUP;
401		return -1;
402	}
403
404	return add_state_filter_cta(this,
405				    cta[proto].cta_protoinfo,
406				    cta[proto].cta_state,
407				    flags,
408				    logic);
409}
410
411static int
412bsf_add_state_filter(const struct nfct_filter *filter, struct sock_filter *this)
413{
414	unsigned int i, j;
415
416	for (i = 0, j = 0; i < IPPROTO_MAX; i++) {
417		if (filter->l4proto_state[i].map &&
418		    filter->l4proto_state[i].len > 0) {
419			j += add_state_filter(
420				      this,
421				      i,
422				      filter->l4proto_state[i].map,
423				      filter->logic[NFCT_FILTER_L4PROTO_STATE]);
424		}
425	}
426
427	return j;
428}
429
430static int
431bsf_add_proto_filter(const struct nfct_filter *f, struct sock_filter *this)
432{
433	unsigned int i, j;
434	unsigned int label_continue, jt;
435	struct stack *s;
436	struct jump jmp;
437
438	/* nothing to filter, skip */
439	if (f->l4proto_len == 0)
440		return 0;
441
442	/* XXX: 255 maximum proto + 3 jumps in the three-level iteration */
443	s = stack_create(sizeof(struct jump), 3 + 255);
444	if (s == NULL) {
445		errno = ENOMEM;
446		return -1;
447	}
448
449	jt = 1;
450	if (f->logic[NFCT_FILTER_L4PROTO] == NFCT_FILTER_LOGIC_POSITIVE)
451		label_continue = 1;
452	else
453		label_continue = 2;
454
455	j = 0;
456	j += nfct_bsf_load_payload_offset(this, j);
457	j += nfct_bsf_find_attr(this, CTA_TUPLE_ORIG, j);
458	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
459	j += nfct_bsf_add_attr_data_offset(this, j);
460	j += nfct_bsf_find_attr(this, CTA_TUPLE_PROTO, j);
461	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
462	j += nfct_bsf_add_attr_data_offset(this, j);
463	j += nfct_bsf_find_attr(this, CTA_PROTO_NUM, j);
464	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
465	j += nfct_bsf_x_equal_a(this, j);
466	j += nfct_bsf_load_attr(this, BPF_B, j);
467
468	for (i = 0; i < IPPROTO_MAX; i++) {
469		if (test_bit(i, f->l4proto_map)) {
470			j += nfct_bsf_cmp_k_stack(this, i, jt - j, j, s);
471		}
472	}
473
474	while (stack_pop(s, &jmp) != -1)
475		this[jmp.line].jt += jmp.jt + j;
476
477	if (f->logic[NFCT_FILTER_L4PROTO] == NFCT_FILTER_LOGIC_NEGATIVE)
478		j += nfct_bsf_jump_to(this, 1, j);
479
480	j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
481
482	stack_destroy(s);
483
484	return j;
485}
486
487static int
488bsf_add_addr_ipv4_filter(const struct nfct_filter *f,
489		         struct sock_filter *this,
490			 unsigned int type)
491{
492	unsigned int i, j, dir, attr;
493	unsigned int label_continue, jt;
494	struct stack *s;
495	struct jump jmp;
496
497	switch(type) {
498	case CTA_IP_V4_SRC:
499		dir = __FILTER_ADDR_SRC;
500		attr = NFCT_FILTER_SRC_IPV4;
501		break;
502	case CTA_IP_V4_DST:
503		dir = __FILTER_ADDR_DST;
504		attr = NFCT_FILTER_DST_IPV4;
505		break;
506	default:
507		return 0;
508	}
509
510	/* nothing to filter, skip */
511	if (f->l3proto_elems[dir] == 0)
512		return 0;
513
514	/* XXX: 127 maximum IPs + 3 jumps in the three-level iteration */
515	s = stack_create(sizeof(struct jump), 3 + 127);
516	if (s == NULL) {
517		errno = ENOMEM;
518		return -1;
519	}
520
521	jt = 1;
522	if (f->logic[attr] == NFCT_FILTER_LOGIC_POSITIVE)
523		label_continue = 1;
524	else
525		label_continue = 2;
526
527	j = 0;
528	j += nfct_bsf_load_payload_offset(this, j);
529	j += nfct_bsf_find_attr(this, CTA_TUPLE_ORIG, j);
530	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
531	j += nfct_bsf_add_attr_data_offset(this, j);
532	j += nfct_bsf_find_attr(this, CTA_TUPLE_IP, j);
533	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
534	j += nfct_bsf_add_attr_data_offset(this, j);
535	j += nfct_bsf_find_attr(this, type, j);
536	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
537	j += nfct_bsf_x_equal_a(this, j);
538
539	for (i = 0; i < f->l3proto_elems[dir]; i++) {
540		int ip = f->l3proto[dir][i].addr & f->l3proto[dir][i].mask;
541
542		j += nfct_bsf_load_attr(this, BPF_W, j);
543		j += nfct_bsf_alu_and(this, f->l3proto[dir][i].mask, j);
544		j += nfct_bsf_cmp_k_stack(this, ip, jt - j, j, s);
545	}
546
547	while (stack_pop(s, &jmp) != -1)
548		this[jmp.line].jt += jmp.jt + j;
549
550	if (f->logic[attr] == NFCT_FILTER_LOGIC_NEGATIVE)
551		j += nfct_bsf_jump_to(this, 1, j);
552
553	j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
554
555	stack_destroy(s);
556
557	return j;
558}
559
560static int
561bsf_add_saddr_ipv4_filter(const struct nfct_filter *f, struct sock_filter *this)
562{
563	return bsf_add_addr_ipv4_filter(f, this, CTA_IP_V4_SRC);
564}
565
566static int
567bsf_add_daddr_ipv4_filter(const struct nfct_filter *f, struct sock_filter *this)
568{
569	return bsf_add_addr_ipv4_filter(f, this, CTA_IP_V4_DST);
570}
571
572static int
573bsf_add_addr_ipv6_filter(const struct nfct_filter *f,
574		         struct sock_filter *this,
575			 unsigned int type)
576{
577	unsigned int i, j, dir, attr;
578	unsigned int label_continue, jf;
579	struct stack *s;
580	struct jump jmp;
581
582	switch(type) {
583	case CTA_IP_V6_SRC:
584		dir = __FILTER_ADDR_SRC;
585		attr = NFCT_FILTER_SRC_IPV6;
586		break;
587	case CTA_IP_V6_DST:
588		dir = __FILTER_ADDR_DST;
589		attr = NFCT_FILTER_DST_IPV6;
590		break;
591	default:
592		return 0;
593	}
594
595	/* nothing to filter, skip */
596	if (f->l3proto_elems_ipv6[dir] == 0)
597		return 0;
598
599	/* XXX: 80 jumps (4*20) + 3 jumps in the three-level iteration */
600	s = stack_create(sizeof(struct jump), 3 + 80);
601	if (s == NULL) {
602		errno = ENOMEM;
603		return -1;
604	}
605
606	jf = 1;
607	if (f->logic[attr] == NFCT_FILTER_LOGIC_POSITIVE) {
608		label_continue = 1;
609	} else {
610		label_continue = 2;
611	}
612
613	j = 0;
614	j += nfct_bsf_load_payload_offset(this, j);
615	j += nfct_bsf_find_attr(this, CTA_TUPLE_ORIG, j);
616	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
617	/* no need to access attribute payload, we are using nest-based finder
618	 * j += nfct_bsf_add_attr_data_offset(this, j); */
619	j += nfct_bsf_find_attr_nest(this, CTA_TUPLE_IP, j);
620	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
621	j += nfct_bsf_find_attr_nest(this, type, j);
622	j += nfct_bsf_cmp_k_stack(this, 0, label_continue - j, j, s);
623	j += nfct_bsf_x_equal_a(this, j);
624
625	for (i = 0; i < f->l3proto_elems_ipv6[dir]; i++) {
626		int k, offset;
627
628		for (k = 0, offset = 0; k < 4; k++, offset += 4) {
629			int ip = f->l3proto_ipv6[dir][i].addr[k] &
630				 f->l3proto_ipv6[dir][i].mask[k];
631
632			j += nfct_bsf_load_attr_offset(this, BPF_W, offset, j);
633			j += nfct_bsf_alu_and(this,
634					      f->l3proto_ipv6[dir][i].mask[k],
635					      j);
636			if (k < 3) {
637				j += nfct_bsf_cmp_k_stack_jf(this, ip,
638						jf - j - 1,
639						j, s);
640			} else {
641				/* last word: jump if true */
642				j += nfct_bsf_cmp_k_stack(this, ip, jf - j,
643							  j, s);
644			}
645		}
646	}
647
648	while (stack_pop(s, &jmp) != -1) {
649		if (jmp.jt) {
650			this[jmp.line].jt += jmp.jt + j;
651		}
652		if (jmp.jf) {
653			this[jmp.line].jf += jmp.jf + j;
654		}
655	}
656
657	if (f->logic[attr] == NFCT_FILTER_LOGIC_NEGATIVE)
658		j += nfct_bsf_jump_to(this, 1, j);
659
660	j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
661
662	stack_destroy(s);
663
664	return j;
665}
666
667static int
668bsf_add_saddr_ipv6_filter(const struct nfct_filter *f, struct sock_filter *this)
669{
670	return bsf_add_addr_ipv6_filter(f, this, CTA_IP_V6_SRC);
671}
672
673static int
674bsf_add_daddr_ipv6_filter(const struct nfct_filter *f, struct sock_filter *this)
675{
676	return bsf_add_addr_ipv6_filter(f, this, CTA_IP_V6_DST);
677}
678
679static int
680bsf_add_mark_filter(const struct nfct_filter *f, struct sock_filter *this)
681{
682	unsigned int i, j;
683	unsigned int jt;
684	struct stack *s;
685	struct jump jmp;
686	struct sock_filter __code = {
687		/* if (A == 0) skip next two */
688		.code = BPF_JMP|BPF_JEQ|BPF_K,
689		.k = 0,
690		.jt = 2,
691		.jf = 0,
692	};
693
694	/* nothing to filter, skip */
695	if (f->mark_elems == 0)
696		return 0;
697
698	/* XXX: see bsf_add_addr_ipv4_filter() */
699	s = stack_create(sizeof(struct jump), 3 + 127);
700	if (s == NULL) {
701		errno = ENOMEM;
702		return -1;
703	}
704
705	jt = 1;
706	j = 0;
707	j += nfct_bsf_load_payload_offset(this, j);	/* A = nla header offset 		*/
708	j += nfct_bsf_find_attr(this, CTA_MARK, j);	/* A = CTA_MARK offset, started from A	*/
709	memcpy(&this[j], &__code, sizeof(__code));	/* if A == 0 skip next two op		*/
710	j += NEW_POS(__code);
711	j += nfct_bsf_x_equal_a(this, j);		/* X = A <CTA_MARK offset>		*/
712	j += nfct_bsf_load_attr(this, BPF_W, j);	/* A = skb->data[X:X + BPF_W]		*/
713	j += nfct_bsf_x_equal_a(this, j);		/* X = A <CTA_MARK value>		*/
714
715	for (i = 0; i < f->mark_elems; i++) {
716		int mark = f->mark[i].val & f->mark[i].mask;
717
718		j += nfct_bsf_alu_and(this, f->mark[i].mask, j);
719		j += nfct_bsf_cmp_k_stack(this, mark, jt - j, j, s);
720		j += nfct_bsf_a_equal_x(this, j);
721	}
722
723	while (stack_pop(s, &jmp) != -1)
724		this[jmp.line].jt += jmp.jt + j;
725
726	if (f->logic[NFCT_FILTER_MARK] == NFCT_FILTER_LOGIC_NEGATIVE)
727		j += nfct_bsf_jump_to(this, 1, j);
728
729	j += nfct_bsf_ret_verdict(this, NFCT_FILTER_REJECT, j);
730
731	stack_destroy(s);
732
733	return j;
734}
735
736/* this buffer must be big enough to store all the autogenerated lines */
737#define BSF_BUFFER_SIZE 	2048
738
739int __setup_netlink_socket_filter(int fd, struct nfct_filter *f)
740{
741	struct sock_filter bsf[BSF_BUFFER_SIZE];
742	struct sock_fprog sf;
743	unsigned int j = 0, from = 0;
744
745	memset(bsf, 0, sizeof(bsf));
746
747	j += bsf_cmp_subsys(&bsf[j], j, NFNL_SUBSYS_CTNETLINK);
748	j += nfct_bsf_ret_verdict(bsf, NFCT_FILTER_ACCEPT, j);
749	show_filter(bsf, from, j, "--- check subsys ---");
750	from = j;
751	j += bsf_add_proto_filter(f, &bsf[j]);
752	show_filter(bsf, from, j, "---- check proto ----");
753	from = j;
754	j += bsf_add_saddr_ipv4_filter(f, &bsf[j]);
755	show_filter(bsf, from, j, "---- check src IPv4 ----");
756	from = j;
757	j += bsf_add_daddr_ipv4_filter(f, &bsf[j]);
758	show_filter(bsf, from, j, "---- check dst IPv4 ----");
759	from = j;
760	j += bsf_add_saddr_ipv6_filter(f, &bsf[j]);
761	show_filter(bsf, from, j, "---- check src IPv6 ----");
762	from = j;
763	j += bsf_add_daddr_ipv6_filter(f, &bsf[j]);
764	show_filter(bsf, from, j, "---- check dst IPv6 ----");
765	from = j;
766	j += bsf_add_state_filter(f, &bsf[j]);
767	show_filter(bsf, from, j, "---- check state ----");
768	from = j;
769	j += bsf_add_mark_filter(f, &bsf[j]);
770	show_filter(bsf, from, j, "---- check mark ----");
771	from = j;
772
773	/* nothing to filter, skip */
774	if (j == 0)
775		return 0;
776
777	j += nfct_bsf_ret_verdict(bsf, NFCT_FILTER_ACCEPT, j);
778	show_filter(bsf, from, j, "---- final verdict ----");
779	from = j;
780
781	sf.len = (sizeof(struct sock_filter) * j) / sizeof(bsf[0]);
782	sf.filter = bsf;
783
784	return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &sf, sizeof(sf));
785}
786