blob: 8599d4853ef6d51732abf23259c0b0f21e7f9823 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001/*
2 * communication.c, v2.0 April 2002
3 *
4 * Author: Bart De Schuymer
5 *
6 */
7
8// All the userspace/kernel communication is in this file.
9// The other code should not have to know anything about the way the
10// kernel likes the structure of the table data.
11// The other code works with linked lists, lots of linked lists.
12// So, the translation is done here.
13
14#include <getopt.h>
15#include <string.h>
16#include <errno.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <sys/socket.h>
20#include <linux/netfilter_bridge/ebtables.h>
21#include <linux/br_db.h> // the database
22#include <netinet/in.h> // IPPROTO_IP
23#include <asm/types.h>
24#include "include/ebtables_u.h"
25
26extern char* hooknames[NF_BR_NUMHOOKS];
27
28int sockfd = -1;
29
30void get_sockfd()
31{
32 if (sockfd == -1) {
33 sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
34 if (sockfd < 0)
35 print_error("Problem getting a socket");
36 }
37}
38
39static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
40{
41 struct ebt_replace *new;
42 struct ebt_u_entry *e;
43 struct ebt_u_match_list *m_l;
44 struct ebt_u_watcher_list *w_l;
Bart De Schuymer60332e02002-06-23 08:01:47 +000045 struct ebt_u_chain_list *cl;
46 struct ebt_u_entries *entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000047 char *p, *base;
48 int i, j;
Bart De Schuymer60332e02002-06-23 08:01:47 +000049 unsigned int entries_size = 0, *chain_offsets;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000050
51 new = (struct ebt_replace *)malloc(sizeof(struct ebt_replace));
52 if (!new)
53 print_memory();
54 new->valid_hooks = u_repl->valid_hooks;
55 memcpy(new->name, u_repl->name, sizeof(new->name));
56 new->nentries = u_repl->nentries;
57 new->num_counters = u_repl->num_counters;
58 new->counters = u_repl->counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +000059 // determine nr of udc
60 i = 0;
61 cl = u_repl->udc;
62 while (cl) {
63 i++;
64 cl = cl->next;
65 }
66 i += NF_BR_NUMHOOKS;
67 chain_offsets = (unsigned int *)malloc(i * sizeof(unsigned int));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000068 // determine size
Bart De Schuymer60332e02002-06-23 08:01:47 +000069 i = 0;
70 cl = u_repl->udc;
71 while (1) {
72 if (i < NF_BR_NUMHOOKS) {
73 if (!(new->valid_hooks & (1 << i))) {
74 i++;
75 continue;
76 }
77 entries = u_repl->hook_entry[i];
78 } else {
79 if (!cl)
80 break;
81 entries = cl->udc;
82 }
83 chain_offsets[i] = entries_size;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000084 entries_size += sizeof(struct ebt_entries);
85 j = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +000086 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000087 while (e) {
88 j++;
89 entries_size += sizeof(struct ebt_entry);
90 m_l = e->m_list;
91 while (m_l) {
92 entries_size += m_l->m->match_size +
93 sizeof(struct ebt_entry_match);
94 m_l = m_l->next;
95 }
96 w_l = e->w_list;
97 while (w_l) {
98 entries_size += w_l->w->watcher_size +
99 sizeof(struct ebt_entry_watcher);
100 w_l = w_l->next;
101 }
102 entries_size += e->t->target_size +
103 sizeof(struct ebt_entry_target);
104 e = e->next;
105 }
106 // a little sanity check
Bart De Schuymer60332e02002-06-23 08:01:47 +0000107 if (j != entries->nentries)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000108 print_bug("Wrong nentries: %d != %d, hook = %s", j,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000109 entries->nentries, entries->name);
110 if (i >= NF_BR_NUMHOOKS)
111 cl = cl->next;
112 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000113 }
114
115 new->entries_size = entries_size;
116 new->entries = (char *)malloc(entries_size);
117 if (!new->entries)
118 print_memory();
119
120 // put everything in one block
121 p = new->entries;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000122 i = 0;
123 cl = u_repl->udc;
124 while (1) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000125 struct ebt_entries *hlp;
126
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000127 hlp = (struct ebt_entries *)p;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000128 if (i < NF_BR_NUMHOOKS) {
129 if (!(new->valid_hooks & (1 << i))) {
130 i++;
131 continue;
132 }
133 entries = u_repl->hook_entry[i];
134 new->hook_entry[i] = hlp;
135 } else {
136 if (!cl)
137 break;
138 entries = cl->udc;
139 }
140 hlp->nentries = entries->nentries;
141 hlp->policy = entries->policy;
142 strcpy(hlp->name, entries->name);
143 hlp->counter_offset = entries->counter_offset;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000144 hlp->distinguisher = 0; // make the kernel see the light
145 p += sizeof(struct ebt_entries);
Bart De Schuymer60332e02002-06-23 08:01:47 +0000146 e = entries->entries;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000147 while (e) {
148 struct ebt_entry *tmp = (struct ebt_entry *)p;
149
150 tmp->bitmask = e->bitmask | EBT_ENTRY_OR_ENTRIES;
151 tmp->invflags = e->invflags;
152 tmp->ethproto = e->ethproto;
153 memcpy(tmp->in, e->in, sizeof(tmp->in));
154 memcpy(tmp->out, e->out, sizeof(tmp->out));
155 memcpy(tmp->logical_in, e->logical_in,
156 sizeof(tmp->logical_in));
157 memcpy(tmp->logical_out, e->logical_out,
158 sizeof(tmp->logical_out));
159 memcpy(tmp->sourcemac, e->sourcemac,
160 sizeof(tmp->sourcemac));
161 memcpy(tmp->sourcemsk, e->sourcemsk,
162 sizeof(tmp->sourcemsk));
163 memcpy(tmp->destmac, e->destmac, sizeof(tmp->destmac));
164 memcpy(tmp->destmsk, e->destmsk, sizeof(tmp->destmsk));
165
166 base = p;
167 p += sizeof(struct ebt_entry);
168 m_l = e->m_list;
169 while (m_l) {
170 memcpy(p, m_l->m, m_l->m->match_size +
171 sizeof(struct ebt_entry_match));
172 p += m_l->m->match_size +
173 sizeof(struct ebt_entry_match);
174 m_l = m_l->next;
175 }
176 tmp->watchers_offset = p - base;
177 w_l = e->w_list;
178 while (w_l) {
179 memcpy(p, w_l->w, w_l->w->watcher_size +
180 sizeof(struct ebt_entry_watcher));
181 p += w_l->w->watcher_size +
182 sizeof(struct ebt_entry_watcher);
183 w_l = w_l->next;
184 }
185 tmp->target_offset = p - base;
186 memcpy(p, e->t, e->t->target_size +
187 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000188 if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
189 struct ebt_standard_target *st =
190 (struct ebt_standard_target *)p;
191 // translate the jump to a udc
192 if (st->verdict >= 0)
Bart De Schuymer1ab41562002-06-23 17:09:54 +0000193 st->verdict = chain_offsets[st->verdict + NF_BR_NUMHOOKS];
Bart De Schuymer60332e02002-06-23 08:01:47 +0000194 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000195 p += e->t->target_size +
196 sizeof(struct ebt_entry_target);
197 tmp->next_offset = p - base;
198 e = e->next;
199 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000200 if (i >= NF_BR_NUMHOOKS)
201 cl = cl->next;
202 i++;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000203 }
204
205 // sanity check
206 if (p - new->entries != new->entries_size)
207 print_bug("Entries_size bug");
Bart De Schuymer60332e02002-06-23 08:01:47 +0000208 free(chain_offsets);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000209 return new;
210}
211
212void deliver_table(struct ebt_u_replace *u_repl)
213{
214 socklen_t optlen;
215 struct ebt_replace *repl;
216
217 // translate the struct ebt_u_replace to a struct ebt_replace
218 repl = translate_user2kernel(u_repl);
219 get_sockfd();
220 // give the data to the kernel
221 optlen = sizeof(struct ebt_replace) + repl->entries_size;
222 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
Bart De Schuymer73564dc2002-06-05 18:13:51 +0000223 print_error("The kernel doesn't support a certain ebtables"
224 " extension, consider recompiling your kernel or insmod"
225 " the extension");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000226}
227
228// gets executed after deliver_table
229void
230deliver_counters(struct ebt_u_replace *u_repl, unsigned short *counterchanges)
231{
232 unsigned short *point;
233 struct ebt_counter *old, *new, *newcounters;
234 socklen_t optlen;
235 struct ebt_replace repl;
236
237 if (u_repl->nentries == 0)
238 return;
239
240 newcounters = (struct ebt_counter *)
241 malloc(u_repl->nentries * sizeof(struct ebt_counter));
242 if (!newcounters)
243 print_memory();
244 memset(newcounters, 0, u_repl->nentries * sizeof(struct ebt_counter));
245 old = u_repl->counters;
246 new = newcounters;
247 point = counterchanges;
248 while (*point != CNT_END) {
249 if (*point == CNT_NORM) {
250 // 'normal' rule, meaning we didn't do anything to it
251 // So, we just copy
252 new->pcnt = old->pcnt;
253 // we've used an old counter
254 old++;
255 // we've set a new counter
256 new++;
257 } else
258 if (*point == CNT_DEL) {
259 // don't use this old counter
260 old++;
261 } else if (*point == CNT_ADD) {
262 // new counter, let it stay 0
263 new++;
264 } else {
265 // zero it
266 new->pcnt = 0;
267 old++;
268 new++;
269 }
270 point++;
271 }
272
273 free(u_repl->counters);
274 u_repl->counters = newcounters;
275 u_repl->num_counters = u_repl->nentries;
276 optlen = u_repl->nentries * sizeof(struct ebt_counter) +
277 sizeof(struct ebt_replace);
278 // now put the stuff in the kernel's struct ebt_replace
279 repl.counters = u_repl->counters;
280 repl.num_counters = u_repl->num_counters;
281 memcpy(repl.name, u_repl->name, sizeof(repl.name));
282
283 get_sockfd();
284 if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
285 print_bug("couldn't update kernel counters");
286}
287
288static int
289ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
290{
291 struct ebt_u_match_list *new;
292
293 new = (struct ebt_u_match_list *)
294 malloc(sizeof(struct ebt_u_match_list));
295 if (!new)
296 print_memory();
297 new->m = (struct ebt_entry_match *)
298 malloc(m->match_size + sizeof(struct ebt_entry_match));
299 if (!new->m)
300 print_memory();
301 memcpy(new->m, m, m->match_size + sizeof(struct ebt_entry_match));
302 new->next = NULL;
303 **l = new;
304 *l = &new->next;
305 if (find_match(new->m->u.name) == NULL)
306 print_error("Kernel match %s unsupported by userspace tool",
307 new->m->u.name);
308 return 0;
309}
310
311static int
312ebt_translate_watcher(struct ebt_entry_watcher *w,
313 struct ebt_u_watcher_list ***l)
314{
315 struct ebt_u_watcher_list *new;
316
317 new = (struct ebt_u_watcher_list *)
318 malloc(sizeof(struct ebt_u_watcher_list));
319 if (!new)
320 print_memory();
321 new->w = (struct ebt_entry_watcher *)
322 malloc(w->watcher_size + sizeof(struct ebt_entry_watcher));
323 if (!new->w)
324 print_memory();
325 memcpy(new->w, w, w->watcher_size + sizeof(struct ebt_entry_watcher));
326 new->next = NULL;
327 **l = new;
328 *l = &new->next;
329 if (find_watcher(new->w->u.name) == NULL)
330 print_error("Kernel watcher %s unsupported by userspace tool",
331 new->w->u.name);
332 return 0;
333}
334
335static int
336ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
337 int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000338 unsigned int valid_hooks, char *base)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000339{
340 // an entry
341 if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
342 struct ebt_u_entry *new;
343 struct ebt_u_match_list **m_l;
344 struct ebt_u_watcher_list **w_l;
345 struct ebt_entry_target *t;
346
347 new = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
348 if (!new)
349 print_memory();
350 new->bitmask = e->bitmask;
351 // plain userspace code doesn't know about EBT_ENTRY_OR_ENTRIES
352 new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
353 new->invflags = e->invflags;
354 new->ethproto = e->ethproto;
355 memcpy(new->in, e->in, sizeof(new->in));
356 memcpy(new->out, e->out, sizeof(new->out));
357 memcpy(new->logical_in, e->logical_in,
358 sizeof(new->logical_in));
359 memcpy(new->logical_out, e->logical_out,
360 sizeof(new->logical_out));
361 memcpy(new->sourcemac, e->sourcemac, sizeof(new->sourcemac));
362 memcpy(new->sourcemsk, e->sourcemsk, sizeof(new->sourcemsk));
363 memcpy(new->destmac, e->destmac, sizeof(new->destmac));
364 memcpy(new->destmsk, e->destmsk, sizeof(new->destmsk));
365 new->m_list = NULL;
366 new->w_list = NULL;
367 new->next = NULL;
368 m_l = &new->m_list;
369 EBT_MATCH_ITERATE(e, ebt_translate_match, &m_l);
370 w_l = &new->w_list;
371 EBT_WATCHER_ITERATE(e, ebt_translate_watcher, &w_l);
372
373 t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
374 new->t = (struct ebt_entry_target *)
375 malloc(t->target_size + sizeof(struct ebt_entry_target));
376 if (!new->t)
377 print_memory();
378 if (find_target(t->u.name) == NULL)
379 print_error("Kernel target %s unsupported by "
380 "userspace tool", t->u.name);
381 memcpy(new->t, t, t->target_size +
382 sizeof(struct ebt_entry_target));
Bart De Schuymer60332e02002-06-23 08:01:47 +0000383 // deal with jumps to udc
384 if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
385 char *tmp = base;
386 int verdict = ((struct ebt_standard_target *)t)->verdict;
387 int i;
388 struct ebt_u_chain_list *cl;
389
390 if (verdict >= 0) {
391 tmp += verdict;
392 cl = u_repl->udc;
393 i = 0;
394 while (cl && cl->kernel_start != tmp) {
395 i++;
396 cl = cl->next;
397 }
398 if (!cl)
399 print_bug("can't find udc for jump");
400 ((struct ebt_standard_target *)new->t)->verdict = i;
401 }
402 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000403
404 // I love pointers
405 **u_e = new;
406 *u_e = &new->next;
407 (*cnt)++;
408 (*totalcnt)++;
409 return 0;
410 } else { // a new chain
411 int i;
412 struct ebt_entries *entries = (struct ebt_entries *)e;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000413 struct ebt_u_chain_list *cl;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000414
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000415 if (*n != *cnt)
416 print_bug("Nr of entries in the chain is wrong");
417 *n = entries->nentries;
418 *cnt = 0;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000419 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
420 if (valid_hooks & (1 << i))
421 break;
422 *hook = i;
423 // makes use of fact that standard chains come before udc
424 if (i >= NF_BR_NUMHOOKS) { // udc
425 i -= NF_BR_NUMHOOKS;
426 cl = u_repl->udc;
427 while (i-- > 0)
428 cl = cl->next;
429 *u_e = &(cl->udc->entries);
430 } else {
431 *u_e = &(u_repl->hook_entry[*hook]->entries);
432 }
433 return 0;
434 }
435}
436
437// initialize all chain headers
438static int
439ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
440 struct ebt_u_replace *u_repl, unsigned int valid_hooks)
441{
442 int i;
443 struct ebt_entries *entries = (struct ebt_entries *)e;
444 struct ebt_u_entries *new;
445 struct ebt_u_chain_list **chain_list;
446
447 if (!(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
448 for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
449 if (valid_hooks & (1 << i))
450 break;
451 // makes use of fact that standard chains come before udc
452 if (i >= NF_BR_NUMHOOKS) { // udc
453 chain_list = &u_repl->udc;
454 // add in the back
455 while (*chain_list)
456 chain_list = &((*chain_list)->next);
457 *chain_list = (struct ebt_u_chain_list *)
458 malloc(sizeof(struct ebt_u_chain_list));
459 if (!(*chain_list))
460 print_memory();
461 (*chain_list)->next = NULL;
462 (*chain_list)->udc = (struct ebt_u_entries *)
463 malloc(sizeof(struct ebt_u_entries));
464 if (!((*chain_list)->udc))
465 print_memory();
466 new = (*chain_list)->udc;
467 // ebt_translate_entry depends on this for knowing
468 // to which chain is being jumped
469 (*chain_list)->kernel_start = (char *)e;
470 } else {
471 *hook = i;
472 new = (struct ebt_u_entries *)
473 malloc(sizeof(struct ebt_u_entries));
474 if (!new)
475 print_memory();
476 u_repl->hook_entry[*hook] = new;
477 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000478 new->nentries = entries->nentries;
479 new->policy = entries->policy;
480 new->entries = NULL;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000481 new->counter_offset = entries->counter_offset;
482 strcpy(new->name, entries->name);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000483 }
Bart De Schuymer60332e02002-06-23 08:01:47 +0000484 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000485}
486
487// talk with kernel to receive the kernel's table
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000488int get_table(struct ebt_u_replace *u_repl)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000489{
490 int i, j, k, hook;
491 socklen_t optlen;
492 struct ebt_replace repl;
493 struct ebt_u_entry **u_e;
494
495 get_sockfd();
496
497 optlen = sizeof(struct ebt_replace);
498 strcpy(repl.name, u_repl->name);
499 if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_INFO, &repl, &optlen))
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000500 return -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000501
502 if ( !(repl.entries = (char *) malloc(repl.entries_size)) )
503 print_memory();
504 if (repl.nentries) {
505 if (!(repl.counters = (struct ebt_counter *)
506 malloc(repl.nentries * sizeof(struct ebt_counter))) )
507 print_memory();
508 }
509 else
510 repl.counters = NULL;
511
512 // we want to receive the counters
513 repl.num_counters = repl.nentries;
514 optlen += repl.entries_size + repl.num_counters *
515 sizeof(struct ebt_counter);
516 if (getsockopt(sockfd, IPPROTO_IP, EBT_SO_GET_ENTRIES, &repl, &optlen))
517 print_bug("hmm, what is wrong??? bug#1");
518
519 // translate the struct ebt_replace to a struct ebt_u_replace
520 memcpy(u_repl->name, repl.name, sizeof(u_repl->name));
521 u_repl->valid_hooks = repl.valid_hooks;
522 u_repl->nentries = repl.nentries;
523 u_repl->num_counters = repl.num_counters;
524 u_repl->counters = repl.counters;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000525 u_repl->udc = NULL;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000526 hook = -1;
Bart De Schuymer60332e02002-06-23 08:01:47 +0000527 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
528 &hook, u_repl, u_repl->valid_hooks);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000529 i = 0; // holds the expected nr. of entries for the chain
530 j = 0; // holds the up to now counted entries for the chain
531 k = 0; // holds the total nr. of entries,
532 // should equal u_repl->nentries afterwards
Bart De Schuymer60332e02002-06-23 08:01:47 +0000533 hook = -1;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000534 EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_entry,
Bart De Schuymer60332e02002-06-23 08:01:47 +0000535 &hook, &i, &j, &k, &u_e, u_repl, u_repl->valid_hooks, repl.entries);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000536 if (k != u_repl->nentries)
537 print_bug("Wrong total nentries");
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000538 return 0;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000539}
540
541void get_dbinfo(struct brdb_dbinfo *nr)
542{
543 socklen_t optlen = sizeof(struct brdb_dbinfo);
544
545 get_sockfd();
Bart De Schuymer9ce6ee92002-06-14 21:56:35 +0000546
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000547 if (getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DBINFO, nr, &optlen))
548 print_error("Sorry, br_db code probably not in kernel, "
549 "try insmod br_db");
550}
551
552void get_db(int len, struct brdb_dbentry *db)
553{
554 socklen_t optlen = len;
555
556 get_sockfd();
557
558 if ( getsockopt(sockfd, IPPROTO_IP, BRDB_SO_GET_DB, db, &optlen) ) {
559 print_bug("hmm, what is wrong??? bug#2");
560 }
561}
562
563void deliver_allowdb(__u16 *decision)
564{
565 socklen_t optlen = sizeof(__u16);
566
567 get_sockfd();
568
569 if (setsockopt(sockfd, IPPROTO_IP, BRDB_SO_SET_ALLOWDB,
570 decision, optlen))
571 print_error("Sorry, br_db code probably not in kernel, "
572 "try insmod br_db");
573}