|
|
|
|
@ -132,7 +132,8 @@ static void *proc_main_list_next(struct seq_file *, void *, loff_t *);
|
|
|
|
|
static int proc_main_list_show(struct seq_file *, void *);
|
|
|
|
|
|
|
|
|
|
static void table_push(struct rtpengine_table *);
|
|
|
|
|
static struct rtpengine_target *get_target(struct rtpengine_table *, u_int16_t);
|
|
|
|
|
static struct rtpengine_target *get_target(struct rtpengine_table *, const struct re_address *);
|
|
|
|
|
static int is_valid_address(const struct re_address *rea);
|
|
|
|
|
|
|
|
|
|
static int aes_f8_session_key_init(struct re_crypto_context *, struct rtpengine_srtp *);
|
|
|
|
|
static int srtp_encrypt_aes_cm(struct re_crypto_context *, struct rtpengine_srtp *,
|
|
|
|
|
@ -188,8 +189,19 @@ struct re_bitfield {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct re_bucket {
|
|
|
|
|
struct re_bitfield targets;
|
|
|
|
|
struct rtpengine_target *target[256];
|
|
|
|
|
struct re_bitfield ports_lo_bf;
|
|
|
|
|
struct rtpengine_target *ports_lo[256];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct re_dest_addr {
|
|
|
|
|
struct re_address destination;
|
|
|
|
|
struct re_bitfield ports_hi_bf;
|
|
|
|
|
struct re_bucket *ports_hi[256];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct re_dest_addr_hash {
|
|
|
|
|
struct re_bitfield addrs_bf;
|
|
|
|
|
struct re_dest_addr *addrs[256];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct rtpengine_table {
|
|
|
|
|
@ -204,10 +216,9 @@ struct rtpengine_table {
|
|
|
|
|
struct proc_dir_entry *list;
|
|
|
|
|
struct proc_dir_entry *blist;
|
|
|
|
|
|
|
|
|
|
struct re_bitfield buckets;
|
|
|
|
|
struct re_bucket *bucket[256];
|
|
|
|
|
struct re_dest_addr_hash dest_addr_hash;
|
|
|
|
|
|
|
|
|
|
unsigned int targets;
|
|
|
|
|
unsigned int num_targets;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct re_cipher {
|
|
|
|
|
@ -536,7 +547,8 @@ static void clear_proc(struct proc_dir_entry **e) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void table_push(struct rtpengine_table *t) {
|
|
|
|
|
int i, j;
|
|
|
|
|
int i, j, k;
|
|
|
|
|
struct re_dest_addr *rda;
|
|
|
|
|
struct re_bucket *b;
|
|
|
|
|
|
|
|
|
|
if (!t)
|
|
|
|
|
@ -547,23 +559,33 @@ static void table_push(struct rtpengine_table *t) {
|
|
|
|
|
|
|
|
|
|
DBG("Freeing table\n");
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
|
|
|
b = t->bucket[i];
|
|
|
|
|
if (!b)
|
|
|
|
|
for (k = 0; k < 256; k++) {
|
|
|
|
|
rda = t->dest_addr_hash.addrs[k];
|
|
|
|
|
if (!rda)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < 256; j++) {
|
|
|
|
|
if (!b->target[j])
|
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
|
|
|
b = rda->ports_hi[i];
|
|
|
|
|
if (!b)
|
|
|
|
|
continue;
|
|
|
|
|
b->target[j]->table = -1;
|
|
|
|
|
target_push(b->target[j]);
|
|
|
|
|
b->target[j] = NULL;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < 256; j++) {
|
|
|
|
|
if (!b->ports_lo[j])
|
|
|
|
|
continue;
|
|
|
|
|
b->ports_lo[j]->table = -1;
|
|
|
|
|
target_push(b->ports_lo[j]);
|
|
|
|
|
b->ports_lo[j] = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kfree(b);
|
|
|
|
|
rda->ports_hi[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kfree(b);
|
|
|
|
|
t->bucket[i] = NULL;
|
|
|
|
|
kfree(rda);
|
|
|
|
|
t->dest_addr_hash.addrs[k] = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
clear_proc(&t->status);
|
|
|
|
|
clear_proc(&t->control);
|
|
|
|
|
clear_proc(&t->list);
|
|
|
|
|
@ -656,8 +678,7 @@ static ssize_t proc_status(struct file *f, char __user *b, size_t l, loff_t *o)
|
|
|
|
|
read_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
len += sprintf(buf + len, "Refcount: %u\n", atomic_read(&t->refcnt) - 1);
|
|
|
|
|
len += sprintf(buf + len, "Control PID: %u\n", t->pid);
|
|
|
|
|
len += sprintf(buf + len, "Targets: %u\n", t->targets);
|
|
|
|
|
len += sprintf(buf + len, "Buckets: %u\n", t->buckets.used);
|
|
|
|
|
len += sprintf(buf + len, "Targets: %u\n", t->num_targets);
|
|
|
|
|
read_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
table_push(t);
|
|
|
|
|
@ -758,43 +779,69 @@ static inline void bitfield_clear(struct re_bitfield *bf, unsigned char i) {
|
|
|
|
|
bf->b[b] &= ~k;
|
|
|
|
|
bf->used--;
|
|
|
|
|
}
|
|
|
|
|
static inline struct rtpengine_target *find_next_target(struct rtpengine_table *t, int *port) {
|
|
|
|
|
static inline struct rtpengine_target *find_next_target(struct rtpengine_table *t, int *addr_bucket,
|
|
|
|
|
int *port)
|
|
|
|
|
{
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
struct re_dest_addr *rda;
|
|
|
|
|
struct re_bucket *b;
|
|
|
|
|
unsigned char hi, lo;
|
|
|
|
|
unsigned int hi_b, lo_b;
|
|
|
|
|
unsigned char hi, lo, ab;
|
|
|
|
|
unsigned int rda_b, hi_b, lo_b;
|
|
|
|
|
struct rtpengine_target *g;
|
|
|
|
|
|
|
|
|
|
if (*port < 0 || *port > 0xffff)
|
|
|
|
|
if (*port < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (*port > 0xffff) {
|
|
|
|
|
*port = 0;
|
|
|
|
|
(*addr_bucket)++;
|
|
|
|
|
}
|
|
|
|
|
if (*addr_bucket < 0 || *addr_bucket > 255)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
hi = (*port & 0xff00) >> 8;
|
|
|
|
|
lo = *port & 0xff;
|
|
|
|
|
ab = *addr_bucket;
|
|
|
|
|
|
|
|
|
|
read_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
rda_b = bitfield_slot(ab);
|
|
|
|
|
if (!t->dest_addr_hash.addrs_bf.b[rda_b]) {
|
|
|
|
|
ab = bitfield_next_slot(rda_b);
|
|
|
|
|
hi = 0;
|
|
|
|
|
lo = 0;
|
|
|
|
|
goto next_rda;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rda = t->dest_addr_hash.addrs[ab];
|
|
|
|
|
if (!rda) {
|
|
|
|
|
ab++;
|
|
|
|
|
hi = 0;
|
|
|
|
|
lo = 0;
|
|
|
|
|
goto next_rda;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hi_b = bitfield_slot(hi);
|
|
|
|
|
if (!t->buckets.b[hi_b]) {
|
|
|
|
|
if (!rda->ports_hi_bf.b[hi_b]) {
|
|
|
|
|
hi = bitfield_next_slot(hi_b);
|
|
|
|
|
lo = 0;
|
|
|
|
|
goto next;
|
|
|
|
|
goto next_hi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b = t->bucket[hi];
|
|
|
|
|
b = rda->ports_hi[hi];
|
|
|
|
|
if (!b) {
|
|
|
|
|
hi++;
|
|
|
|
|
lo = 0;
|
|
|
|
|
goto next;
|
|
|
|
|
goto next_hi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lo_b = bitfield_slot(lo);
|
|
|
|
|
if (!b->targets.b[lo_b]) {
|
|
|
|
|
if (!b->ports_lo_bf.b[lo_b]) {
|
|
|
|
|
lo = bitfield_next_slot(lo_b);
|
|
|
|
|
goto next_lo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g = b->target[lo];
|
|
|
|
|
g = b->ports_lo[lo];
|
|
|
|
|
if (!g) {
|
|
|
|
|
lo++;
|
|
|
|
|
goto next_lo;
|
|
|
|
|
@ -806,13 +853,17 @@ static inline struct rtpengine_target *find_next_target(struct rtpengine_table *
|
|
|
|
|
next_lo:
|
|
|
|
|
if (!lo)
|
|
|
|
|
hi++;
|
|
|
|
|
next:
|
|
|
|
|
next_hi:
|
|
|
|
|
if (!hi && !lo)
|
|
|
|
|
ab++;
|
|
|
|
|
next_rda:
|
|
|
|
|
if (!ab && !hi && !lo)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
read_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
*addr_bucket = ab;
|
|
|
|
|
*port = (hi << 8) | lo;
|
|
|
|
|
(*port)++;
|
|
|
|
|
|
|
|
|
|
@ -854,7 +905,7 @@ static ssize_t proc_blist_read(struct file *f, char __user *b, size_t l, loff_t
|
|
|
|
|
u_int32_t id;
|
|
|
|
|
struct rtpengine_table *t;
|
|
|
|
|
struct rtpengine_list_entry op;
|
|
|
|
|
int err, port, i;
|
|
|
|
|
int err, port, addr_bucket, i;
|
|
|
|
|
struct rtpengine_target *g;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
@ -869,9 +920,10 @@ static ssize_t proc_blist_read(struct file *f, char __user *b, size_t l, loff_t
|
|
|
|
|
if (!t)
|
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
|
|
port = (int) *o;
|
|
|
|
|
g = find_next_target(t, &port);
|
|
|
|
|
*o = port;
|
|
|
|
|
addr_bucket = ((int) *o) >> 17;
|
|
|
|
|
port = ((int) *o) & 0x1ffff;
|
|
|
|
|
g = find_next_target(t, &addr_bucket, &port);
|
|
|
|
|
*o = (addr_bucket << 17) | port;
|
|
|
|
|
err = 0;
|
|
|
|
|
if (!g)
|
|
|
|
|
goto err;
|
|
|
|
|
@ -950,34 +1002,34 @@ static void *proc_list_next(struct seq_file *f, void *v, loff_t *o) { /* v is in
|
|
|
|
|
u_int32_t id = (u_int32_t) (unsigned long) f->private;
|
|
|
|
|
struct rtpengine_table *t;
|
|
|
|
|
struct rtpengine_target *g;
|
|
|
|
|
int port;
|
|
|
|
|
int port, addr_bucket;
|
|
|
|
|
|
|
|
|
|
port = (int) *o;
|
|
|
|
|
addr_bucket = ((int) *o) >> 17;
|
|
|
|
|
port = ((int) *o) & 0x1ffff;
|
|
|
|
|
|
|
|
|
|
t = get_table(id);
|
|
|
|
|
if (!t)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
g = find_next_target(t, &port);
|
|
|
|
|
g = find_next_target(t, &addr_bucket, &port);
|
|
|
|
|
|
|
|
|
|
*o = port;
|
|
|
|
|
*o = (addr_bucket << 17) | port;
|
|
|
|
|
table_push(t);
|
|
|
|
|
|
|
|
|
|
return g;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void proc_list_addr_print(struct seq_file *f, const char *s, const struct re_address *a) {
|
|
|
|
|
static void seq_addr_print(struct seq_file *f, const struct re_address *a) {
|
|
|
|
|
if (!a->family)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
seq_printf(f, " %6s ", s);
|
|
|
|
|
switch (a->family) {
|
|
|
|
|
case AF_INET:
|
|
|
|
|
seq_printf(f, "inet4 %u.%u.%u.%u:%u\n", a->u.u8[0], a->u.u8[1], a->u.u8[2],
|
|
|
|
|
seq_printf(f, "inet4 %u.%u.%u.%u:%u", a->u.u8[0], a->u.u8[1], a->u.u8[2],
|
|
|
|
|
a->u.u8[3], a->port);
|
|
|
|
|
break;
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
seq_printf(f, "inet6 [%x:%x:%x:%x:%x:%x:%x:%x]:%u\n",
|
|
|
|
|
seq_printf(f, "inet6 [%x:%x:%x:%x:%x:%x:%x:%x]:%u",
|
|
|
|
|
htons(a->u.u16[0]), htons(a->u.u16[1]),
|
|
|
|
|
htons(a->u.u16[2]), htons(a->u.u16[3]), htons(a->u.u16[4]), htons(a->u.u16[5]),
|
|
|
|
|
htons(a->u.u16[6]), htons(a->u.u16[7]), a->port);
|
|
|
|
|
@ -988,6 +1040,15 @@ static void proc_list_addr_print(struct seq_file *f, const char *s, const struct
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void proc_list_addr_print(struct seq_file *f, const char *s, const struct re_address *a) {
|
|
|
|
|
if (!a->family)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
seq_printf(f, " %6s ", s);
|
|
|
|
|
seq_addr_print(f, a);
|
|
|
|
|
seq_printf(f, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void proc_list_crypto_print(struct seq_file *f, struct re_crypto_context *c,
|
|
|
|
|
struct rtpengine_srtp *s, const char *label)
|
|
|
|
|
{
|
|
|
|
|
@ -1015,7 +1076,9 @@ static int proc_list_show(struct seq_file *f, void *v) {
|
|
|
|
|
struct rtpengine_target *g = v;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
seq_printf(f, "port %5u:\n", g->target.target_port);
|
|
|
|
|
seq_printf(f, "local ");
|
|
|
|
|
seq_addr_print(f, &g->target.local);
|
|
|
|
|
seq_printf(f, "\n");
|
|
|
|
|
proc_list_addr_print(f, "src", &g->target.src_addr);
|
|
|
|
|
proc_list_addr_print(f, "dst", &g->target.dst_addr);
|
|
|
|
|
proc_list_addr_print(f, "mirror", &g->target.mirror_addr);
|
|
|
|
|
@ -1046,37 +1109,119 @@ static int proc_list_show(struct seq_file *f, void *v) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static unsigned int re_address_hash(const struct re_address *a) {
|
|
|
|
|
u_int32_t ret = 0;
|
|
|
|
|
|
|
|
|
|
if (!a)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
ret += a->family;
|
|
|
|
|
|
|
|
|
|
switch (a->family) {
|
|
|
|
|
case AF_INET:
|
|
|
|
|
ret += a->u.ipv4;
|
|
|
|
|
break;
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
ret += a->u.u32[0];
|
|
|
|
|
ret += a->u.u32[1];
|
|
|
|
|
ret += a->u.u32[2];
|
|
|
|
|
ret += a->u.u32[3];
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = (ret & 0xffff) ^ ((ret & 0xffff0000) >> 16);
|
|
|
|
|
ret = (ret & 0xff) ^ ((ret & 0xff00) >> 8);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int re_address_match(const struct re_address *a, const struct re_address *b) {
|
|
|
|
|
if (!a || !b)
|
|
|
|
|
return 0;
|
|
|
|
|
if (a->family != b->family)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
switch (a->family) {
|
|
|
|
|
case AF_INET:
|
|
|
|
|
if (a->u.ipv4 == b->u.ipv4)
|
|
|
|
|
return 1;
|
|
|
|
|
break;
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
if (!memcmp(a->u.ipv6, b->u.ipv6, sizeof(a->u.ipv6)))
|
|
|
|
|
return 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct re_dest_addr *find_dest_addr(const struct re_dest_addr_hash *h, const struct re_address *local) {
|
|
|
|
|
unsigned int rda_hash, i;
|
|
|
|
|
struct re_dest_addr *rda;
|
|
|
|
|
|
|
|
|
|
i = rda_hash = re_address_hash(local);
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
rda = h->addrs[i];
|
|
|
|
|
if (!rda)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (re_address_match(local, &rda->destination))
|
|
|
|
|
return rda;
|
|
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
if (i >= 256)
|
|
|
|
|
i = 0;
|
|
|
|
|
if (i == rda_hash)
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int table_del_target(struct rtpengine_table *t, u_int16_t port) {
|
|
|
|
|
static int table_del_target(struct rtpengine_table *t, const struct re_address *local) {
|
|
|
|
|
unsigned char hi, lo;
|
|
|
|
|
struct re_dest_addr *rda;
|
|
|
|
|
struct re_bucket *b;
|
|
|
|
|
struct rtpengine_target *g = NULL;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
if (!port)
|
|
|
|
|
if (!local || !is_valid_address(local))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
hi = (port & 0xff00) >> 8;
|
|
|
|
|
lo = port & 0xff;
|
|
|
|
|
hi = (local->port & 0xff00) >> 8;
|
|
|
|
|
lo = local->port & 0xff;
|
|
|
|
|
|
|
|
|
|
write_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
b = t->bucket[hi];
|
|
|
|
|
|
|
|
|
|
rda = find_dest_addr(&t->dest_addr_hash, local);
|
|
|
|
|
if (!rda)
|
|
|
|
|
goto out;
|
|
|
|
|
b = rda->ports_hi[hi];
|
|
|
|
|
if (!b)
|
|
|
|
|
goto out;
|
|
|
|
|
g = b->target[lo];
|
|
|
|
|
g = b->ports_lo[lo];
|
|
|
|
|
if (!g)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
b->target[lo] = NULL;
|
|
|
|
|
bitfield_clear(&b->targets, lo);
|
|
|
|
|
t->targets--;
|
|
|
|
|
if (!b->targets.used) {
|
|
|
|
|
t->bucket[hi] = NULL;
|
|
|
|
|
bitfield_clear(&t->buckets, hi);
|
|
|
|
|
b->ports_lo[lo] = NULL;
|
|
|
|
|
bitfield_clear(&b->ports_lo_bf, lo);
|
|
|
|
|
t->num_targets--;
|
|
|
|
|
if (!b->ports_lo_bf.used) {
|
|
|
|
|
rda->ports_hi[hi] = NULL;
|
|
|
|
|
bitfield_clear(&rda->ports_hi_bf, hi);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
b = NULL;
|
|
|
|
|
|
|
|
|
|
/* not freeing or NULLing the re_dest_addr due to hash collision logic */
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
write_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
@ -1093,7 +1238,7 @@ out:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int is_valid_address(struct re_address *rea) {
|
|
|
|
|
static int is_valid_address(const struct re_address *rea) {
|
|
|
|
|
switch (rea->family) {
|
|
|
|
|
case AF_INET:
|
|
|
|
|
if (!rea->u.ipv4)
|
|
|
|
|
@ -1418,13 +1563,17 @@ static void crypto_context_init(struct re_crypto_context *c, struct rtpengine_sr
|
|
|
|
|
|
|
|
|
|
static int table_new_target(struct rtpengine_table *t, struct rtpengine_target_info *i, int update) {
|
|
|
|
|
unsigned char hi, lo;
|
|
|
|
|
unsigned int rda_hash, rh_it;
|
|
|
|
|
struct rtpengine_target *g;
|
|
|
|
|
struct re_dest_addr *rda;
|
|
|
|
|
struct re_bucket *b, *ba = NULL;
|
|
|
|
|
struct rtpengine_target *og = NULL;
|
|
|
|
|
int err, j;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
if (!i->target_port)
|
|
|
|
|
/* validation */
|
|
|
|
|
|
|
|
|
|
if (!is_valid_address(&i->local))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
if (!is_valid_address(&i->src_addr))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
@ -1445,6 +1594,8 @@ static int table_new_target(struct rtpengine_table *t, struct rtpengine_target_i
|
|
|
|
|
|
|
|
|
|
DBG("Creating new target\n");
|
|
|
|
|
|
|
|
|
|
/* initializing */
|
|
|
|
|
|
|
|
|
|
err = -ENOMEM;
|
|
|
|
|
g = kmalloc(sizeof(*g), GFP_KERNEL);
|
|
|
|
|
if (!g)
|
|
|
|
|
@ -1465,37 +1616,86 @@ static int table_new_target(struct rtpengine_table *t, struct rtpengine_target_i
|
|
|
|
|
if (err)
|
|
|
|
|
goto fail2;
|
|
|
|
|
|
|
|
|
|
hi = (i->target_port & 0xff00) >> 8;
|
|
|
|
|
lo = i->target_port & 0xff;
|
|
|
|
|
/* find or allocate re_dest_addr */
|
|
|
|
|
|
|
|
|
|
rda_hash = re_address_hash(&i->local);
|
|
|
|
|
hi = (i->local.port & 0xff00) >> 8;
|
|
|
|
|
lo = i->local.port & 0xff;
|
|
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
rh_it = rda_hash;
|
|
|
|
|
write_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
if (!(b = t->bucket[hi])) {
|
|
|
|
|
err = -ENOENT;
|
|
|
|
|
if (update)
|
|
|
|
|
|
|
|
|
|
rda = t->dest_addr_hash.addrs[rh_it];
|
|
|
|
|
while (rda) {
|
|
|
|
|
if (re_address_match(&rda->destination, &i->local))
|
|
|
|
|
goto got_rda;
|
|
|
|
|
rh_it++;
|
|
|
|
|
if (rh_it >= 256)
|
|
|
|
|
rh_it = 0;
|
|
|
|
|
err = -ENXIO;
|
|
|
|
|
if (rh_it == rda_hash)
|
|
|
|
|
goto fail4;
|
|
|
|
|
rda = t->dest_addr_hash.addrs[rh_it];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = -ENOENT;
|
|
|
|
|
if (update)
|
|
|
|
|
goto fail4;
|
|
|
|
|
|
|
|
|
|
write_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
rda = kmalloc(sizeof(*rda), GFP_KERNEL);
|
|
|
|
|
err = -ENOMEM;
|
|
|
|
|
if (!rda)
|
|
|
|
|
goto fail2;
|
|
|
|
|
memset(rda, 0, sizeof(*rda));
|
|
|
|
|
memcpy(&rda->destination, &i->local, sizeof(rda->destination));
|
|
|
|
|
|
|
|
|
|
write_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
if (t->dest_addr_hash.addrs[rh_it]) {
|
|
|
|
|
write_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
kfree(rda);
|
|
|
|
|
goto retry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t->dest_addr_hash.addrs[rh_it] = rda;
|
|
|
|
|
bitfield_set(&t->dest_addr_hash.addrs_bf, rh_it);
|
|
|
|
|
|
|
|
|
|
b = kmalloc(sizeof(*b), GFP_KERNEL);
|
|
|
|
|
err = -ENOMEM;
|
|
|
|
|
if (!b)
|
|
|
|
|
goto fail2;
|
|
|
|
|
memset(b, 0, sizeof(*b));
|
|
|
|
|
got_rda:
|
|
|
|
|
/* find or allocate re_bucket */
|
|
|
|
|
|
|
|
|
|
write_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
if ((b = rda->ports_hi[hi]))
|
|
|
|
|
goto got_bucket;
|
|
|
|
|
|
|
|
|
|
if (!t->bucket[hi]) {
|
|
|
|
|
t->bucket[hi] = b;
|
|
|
|
|
bitfield_set(&t->buckets, hi);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ba = b;
|
|
|
|
|
b = t->bucket[hi];
|
|
|
|
|
}
|
|
|
|
|
err = -ENOENT;
|
|
|
|
|
if (update)
|
|
|
|
|
goto fail4;
|
|
|
|
|
|
|
|
|
|
write_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
b = kmalloc(sizeof(*b), GFP_KERNEL);
|
|
|
|
|
err = -ENOMEM;
|
|
|
|
|
if (!b)
|
|
|
|
|
goto fail2;
|
|
|
|
|
memset(b, 0, sizeof(*b));
|
|
|
|
|
|
|
|
|
|
write_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
if (!rda->ports_hi[hi]) {
|
|
|
|
|
rda->ports_hi[hi] = b;
|
|
|
|
|
bitfield_set(&rda->ports_hi_bf, hi);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ba = b;
|
|
|
|
|
b = rda->ports_hi[hi];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
got_bucket:
|
|
|
|
|
if (update) {
|
|
|
|
|
err = -ENOENT;
|
|
|
|
|
og = b->target[lo];
|
|
|
|
|
og = b->ports_lo[lo];
|
|
|
|
|
if (!og)
|
|
|
|
|
goto fail4;
|
|
|
|
|
|
|
|
|
|
@ -1514,13 +1714,13 @@ static int table_new_target(struct rtpengine_table *t, struct rtpengine_target_i
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
err = -EEXIST;
|
|
|
|
|
if (b->target[lo])
|
|
|
|
|
if (b->ports_lo[lo])
|
|
|
|
|
goto fail4;
|
|
|
|
|
bitfield_set(&b->targets, lo);
|
|
|
|
|
t->targets++;
|
|
|
|
|
bitfield_set(&b->ports_lo_bf, lo);
|
|
|
|
|
t->num_targets++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b->target[lo] = g;
|
|
|
|
|
b->ports_lo[lo] = g;
|
|
|
|
|
g = NULL;
|
|
|
|
|
write_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
@ -1545,21 +1745,24 @@ fail1:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct rtpengine_target *get_target(struct rtpengine_table *t, u_int16_t port) {
|
|
|
|
|
static struct rtpengine_target *get_target(struct rtpengine_table *t, const struct re_address *local) {
|
|
|
|
|
unsigned char hi, lo;
|
|
|
|
|
struct re_dest_addr *rda;
|
|
|
|
|
struct rtpengine_target *r;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
if (!t)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (!port)
|
|
|
|
|
if (!local)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
hi = (port & 0xff00) >> 8;
|
|
|
|
|
lo = port & 0xff;
|
|
|
|
|
hi = (local->port & 0xff00) >> 8;
|
|
|
|
|
lo = local->port & 0xff;
|
|
|
|
|
|
|
|
|
|
read_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
r = t->bucket[hi] ? t->bucket[hi]->target[lo] : NULL;
|
|
|
|
|
|
|
|
|
|
rda = find_dest_addr(&t->dest_addr_hash, local);
|
|
|
|
|
r = rda ? (rda->ports_hi[hi] ? rda->ports_hi[hi]->ports_lo[lo] : NULL) : NULL;
|
|
|
|
|
if (r)
|
|
|
|
|
target_hold(r);
|
|
|
|
|
read_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
@ -1706,7 +1909,7 @@ static ssize_t proc_control_write(struct file *file, const char __user *buf, siz
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MMG_DEL:
|
|
|
|
|
err = table_del_target(t, msg.target.target_port);
|
|
|
|
|
err = table_del_target(t, &msg.target.local);
|
|
|
|
|
if (err)
|
|
|
|
|
goto err;
|
|
|
|
|
break;
|
|
|
|
|
@ -2225,7 +2428,9 @@ static inline int rtp_payload_type(const struct rtp_header *hdr, const struct rt
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, struct re_address *src, u_int8_t in_tos) {
|
|
|
|
|
static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, struct re_address *src,
|
|
|
|
|
struct re_address *dst, u_int8_t in_tos)
|
|
|
|
|
{
|
|
|
|
|
struct udphdr *uh;
|
|
|
|
|
struct rtpengine_target *g;
|
|
|
|
|
struct sk_buff *skb2;
|
|
|
|
|
@ -2254,8 +2459,9 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t,
|
|
|
|
|
skb_trim(skb, datalen);
|
|
|
|
|
|
|
|
|
|
src->port = ntohs(uh->source);
|
|
|
|
|
dst->port = ntohs(uh->dest);
|
|
|
|
|
|
|
|
|
|
g = get_target(t, ntohs(uh->dest));
|
|
|
|
|
g = get_target(t, dst);
|
|
|
|
|
if (!g)
|
|
|
|
|
goto skip2;
|
|
|
|
|
|
|
|
|
|
@ -2428,7 +2634,7 @@ static unsigned int rtpengine4(struct sk_buff *oskb, const struct xt_action_para
|
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
struct iphdr *ih;
|
|
|
|
|
struct rtpengine_table *t;
|
|
|
|
|
struct re_address src;
|
|
|
|
|
struct re_address src, dst;
|
|
|
|
|
|
|
|
|
|
t = get_table(pinfo->id);
|
|
|
|
|
if (!t)
|
|
|
|
|
@ -2447,8 +2653,10 @@ static unsigned int rtpengine4(struct sk_buff *oskb, const struct xt_action_para
|
|
|
|
|
memset(&src, 0, sizeof(src));
|
|
|
|
|
src.family = AF_INET;
|
|
|
|
|
src.u.ipv4 = ih->saddr;
|
|
|
|
|
dst.family = AF_INET;
|
|
|
|
|
dst.u.ipv4 = ih->daddr;
|
|
|
|
|
|
|
|
|
|
return rtpengine46(skb, t, &src, (u_int8_t)ih->tos);
|
|
|
|
|
return rtpengine46(skb, t, &src, &dst, (u_int8_t)ih->tos);
|
|
|
|
|
|
|
|
|
|
skip2:
|
|
|
|
|
kfree_skb(skb);
|
|
|
|
|
@ -2470,7 +2678,7 @@ static unsigned int rtpengine6(struct sk_buff *oskb, const struct xt_action_para
|
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
struct ipv6hdr *ih;
|
|
|
|
|
struct rtpengine_table *t;
|
|
|
|
|
struct re_address src;
|
|
|
|
|
struct re_address src, dst;
|
|
|
|
|
|
|
|
|
|
t = get_table(pinfo->id);
|
|
|
|
|
if (!t)
|
|
|
|
|
@ -2490,8 +2698,10 @@ static unsigned int rtpengine6(struct sk_buff *oskb, const struct xt_action_para
|
|
|
|
|
memset(&src, 0, sizeof(src));
|
|
|
|
|
src.family = AF_INET6;
|
|
|
|
|
memcpy(&src.u.ipv6, &ih->saddr, sizeof(src.u.ipv6));
|
|
|
|
|
dst.family = AF_INET6;
|
|
|
|
|
memcpy(&dst.u.ipv6, &ih->daddr, sizeof(dst.u.ipv6));
|
|
|
|
|
|
|
|
|
|
return rtpengine46(skb, t, &src, ipv6_get_dsfield(ih));
|
|
|
|
|
return rtpengine46(skb, t, &src, &dst, ipv6_get_dsfield(ih));
|
|
|
|
|
|
|
|
|
|
skip2:
|
|
|
|
|
kfree_skb(skb);
|
|
|
|
|
|