|
|
|
|
@ -153,6 +153,16 @@ struct mediaproxy_target {
|
|
|
|
|
struct mp_crypto_context encrypt;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct mp_bitfield {
|
|
|
|
|
unsigned long b[256 / (sizeof(unsigned long) * 8)];
|
|
|
|
|
unsigned int used;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct mp_bucket {
|
|
|
|
|
struct mp_bitfield targets;
|
|
|
|
|
struct mediaproxy_target *target[256];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct mediaproxy_table {
|
|
|
|
|
atomic_t refcnt;
|
|
|
|
|
rwlock_t target_lock;
|
|
|
|
|
@ -165,9 +175,9 @@ struct mediaproxy_table {
|
|
|
|
|
struct proc_dir_entry *list;
|
|
|
|
|
struct proc_dir_entry *blist;
|
|
|
|
|
|
|
|
|
|
struct mediaproxy_target **target[256];
|
|
|
|
|
struct mp_bitfield buckets;
|
|
|
|
|
struct mp_bucket *bucket[256];
|
|
|
|
|
|
|
|
|
|
unsigned int buckets;
|
|
|
|
|
unsigned int targets;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@ -481,6 +491,7 @@ static void clear_proc(struct proc_dir_entry **e) {
|
|
|
|
|
|
|
|
|
|
static void table_push(struct mediaproxy_table *t) {
|
|
|
|
|
int i, j;
|
|
|
|
|
struct mp_bucket *b;
|
|
|
|
|
|
|
|
|
|
if (!t)
|
|
|
|
|
return;
|
|
|
|
|
@ -491,19 +502,20 @@ static void table_push(struct mediaproxy_table *t) {
|
|
|
|
|
DBG("Freeing table\n");
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
|
|
|
if (!t->target[i])
|
|
|
|
|
b = t->bucket[i];
|
|
|
|
|
if (!b)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < 256; j++) {
|
|
|
|
|
if (!t->target[i][j])
|
|
|
|
|
if (!b->target[j])
|
|
|
|
|
continue;
|
|
|
|
|
t->target[i][j]->table = -1;
|
|
|
|
|
target_push(t->target[i][j]);
|
|
|
|
|
t->target[i][j] = NULL;
|
|
|
|
|
b->target[j]->table = -1;
|
|
|
|
|
target_push(b->target[j]);
|
|
|
|
|
b->target[j] = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kfree(t->target[i]);
|
|
|
|
|
t->target[i] = NULL;
|
|
|
|
|
kfree(b);
|
|
|
|
|
t->bucket[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clear_proc(&t->status);
|
|
|
|
|
@ -599,7 +611,7 @@ static ssize_t proc_status(struct file *f, char __user *b, size_t l, loff_t *o)
|
|
|
|
|
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);
|
|
|
|
|
len += sprintf(buf + len, "Buckets: %u\n", t->buckets.used);
|
|
|
|
|
read_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
table_push(t);
|
|
|
|
|
@ -664,6 +676,105 @@ static int proc_main_list_show(struct seq_file *f, void *v) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline unsigned char bitfield_next_slot(unsigned int slot) {
|
|
|
|
|
unsigned char c;
|
|
|
|
|
c = slot * (sizeof(unsigned long) * 8);
|
|
|
|
|
c += sizeof(unsigned long) * 8;
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
static inline unsigned int bitfield_slot(unsigned char i) {
|
|
|
|
|
return i / (sizeof(unsigned long) * 8);
|
|
|
|
|
}
|
|
|
|
|
static inline unsigned int bitfield_bit(unsigned char i) {
|
|
|
|
|
return i % (sizeof(unsigned long) * 8);
|
|
|
|
|
}
|
|
|
|
|
static inline void bitfield_set(struct mp_bitfield *bf, unsigned char i) {
|
|
|
|
|
unsigned int b, m;
|
|
|
|
|
unsigned long k;
|
|
|
|
|
|
|
|
|
|
b = bitfield_slot(i);
|
|
|
|
|
m = bitfield_bit(i);
|
|
|
|
|
k = 1 << m;
|
|
|
|
|
if ((bf->b[b] & k))
|
|
|
|
|
return;
|
|
|
|
|
bf->b[b] |= k;
|
|
|
|
|
bf->used++;
|
|
|
|
|
}
|
|
|
|
|
static inline void bitfield_clear(struct mp_bitfield *bf, unsigned char i) {
|
|
|
|
|
unsigned int b, m;
|
|
|
|
|
unsigned long k;
|
|
|
|
|
|
|
|
|
|
b = bitfield_slot(i);
|
|
|
|
|
m = bitfield_bit(i);
|
|
|
|
|
k = 1 << m;
|
|
|
|
|
if (!(bf->b[b] & k))
|
|
|
|
|
return;
|
|
|
|
|
bf->b[b] &= ~k;
|
|
|
|
|
bf->used--;
|
|
|
|
|
}
|
|
|
|
|
static inline struct mediaproxy_target *find_next_target(struct mediaproxy_table *t, int *port) {
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
struct mp_bucket *b;
|
|
|
|
|
unsigned char hi, lo;
|
|
|
|
|
unsigned int hi_b, lo_b;
|
|
|
|
|
struct mediaproxy_target *g;
|
|
|
|
|
|
|
|
|
|
if (*port < 0 || *port > 0xffff)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
hi = (*port & 0xff00) >> 8;
|
|
|
|
|
lo = *port & 0xff;
|
|
|
|
|
|
|
|
|
|
read_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
hi_b = bitfield_slot(hi);
|
|
|
|
|
if (!t->buckets.b[hi_b]) {
|
|
|
|
|
hi = bitfield_next_slot(hi_b);
|
|
|
|
|
lo = 0;
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b = t->bucket[hi];
|
|
|
|
|
if (!b) {
|
|
|
|
|
hi++;
|
|
|
|
|
lo = 0;
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lo_b = bitfield_slot(lo);
|
|
|
|
|
if (!b->targets.b[lo_b]) {
|
|
|
|
|
lo = bitfield_next_slot(lo_b);
|
|
|
|
|
goto next_lo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g = b->target[lo];
|
|
|
|
|
if (!g) {
|
|
|
|
|
lo++;
|
|
|
|
|
goto next_lo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
target_hold(g);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
next_lo:
|
|
|
|
|
if (!lo)
|
|
|
|
|
hi++;
|
|
|
|
|
next:
|
|
|
|
|
if (!hi && !lo)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
read_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
*port = (hi << 8) | lo;
|
|
|
|
|
(*port)++;
|
|
|
|
|
|
|
|
|
|
return g;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int proc_blist_open(struct inode *i, struct file *f) {
|
|
|
|
|
u_int32_t id;
|
|
|
|
|
struct mediaproxy_table *t;
|
|
|
|
|
@ -700,6 +811,7 @@ static ssize_t proc_blist_read(struct file *f, char __user *b, size_t l, loff_t
|
|
|
|
|
int err;
|
|
|
|
|
struct mediaproxy_target *g;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
int port;
|
|
|
|
|
|
|
|
|
|
if (l != sizeof(op))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
@ -712,15 +824,12 @@ static ssize_t proc_blist_read(struct file *f, char __user *b, size_t l, loff_t
|
|
|
|
|
if (!t)
|
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
err = 0;
|
|
|
|
|
if (*o > 0xffff)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
g = get_target(t, (*o)++);
|
|
|
|
|
if (g)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
port = (int) *o;
|
|
|
|
|
g = find_next_target(t, &port);
|
|
|
|
|
*o = port;
|
|
|
|
|
err = 0;
|
|
|
|
|
if (!g)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
memset(&op, 0, sizeof(op));
|
|
|
|
|
memcpy(&op.target, &g->target, sizeof(op.target));
|
|
|
|
|
@ -789,46 +898,19 @@ static void proc_list_stop(struct seq_file *f, void *v) {
|
|
|
|
|
|
|
|
|
|
static void *proc_list_next(struct seq_file *f, void *v, loff_t *o) { /* v is invalid */
|
|
|
|
|
u_int32_t id = (u_int32_t) (unsigned long) f->private;
|
|
|
|
|
struct mediaproxy_target *g = NULL;
|
|
|
|
|
struct mediaproxy_table *t;
|
|
|
|
|
u_int16_t port;
|
|
|
|
|
unsigned char hi, lo;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
struct mediaproxy_target *g;
|
|
|
|
|
int port;
|
|
|
|
|
|
|
|
|
|
if (*o < 0 || *o > 0xffff)
|
|
|
|
|
return NULL;
|
|
|
|
|
port = (u_int16_t) *o;
|
|
|
|
|
port = (int) *o;
|
|
|
|
|
|
|
|
|
|
t = get_table(id);
|
|
|
|
|
if (!t)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
hi = (port & 0xff00) >> 8;
|
|
|
|
|
lo = port & 0xff;
|
|
|
|
|
|
|
|
|
|
read_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
for (;;) {
|
|
|
|
|
lo++; /* will make the iteration start from 1 */
|
|
|
|
|
if (lo == 0) {
|
|
|
|
|
hi++;
|
|
|
|
|
if (hi == 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!t->target[hi]) {
|
|
|
|
|
lo = 0xff;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g = t->target[hi][lo];
|
|
|
|
|
if (!g)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
target_hold(g);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
read_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
g = find_next_target(t, &port);
|
|
|
|
|
|
|
|
|
|
*o = (hi << 8) | lo;
|
|
|
|
|
*o = port;
|
|
|
|
|
table_push(t);
|
|
|
|
|
|
|
|
|
|
return g;
|
|
|
|
|
@ -902,7 +984,8 @@ static int proc_list_show(struct seq_file *f, void *v) {
|
|
|
|
|
|
|
|
|
|
static int table_del_target(struct mediaproxy_table *t, u_int16_t port) {
|
|
|
|
|
unsigned char hi, lo;
|
|
|
|
|
struct mediaproxy_target *g;
|
|
|
|
|
struct mp_bucket *b;
|
|
|
|
|
struct mediaproxy_target *g = NULL;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
if (!port)
|
|
|
|
|
@ -912,15 +995,30 @@ static int table_del_target(struct mediaproxy_table *t, u_int16_t port) {
|
|
|
|
|
lo = port & 0xff;
|
|
|
|
|
|
|
|
|
|
write_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
g = t->target[hi] ? t->target[hi][lo] : NULL;
|
|
|
|
|
if (g) {
|
|
|
|
|
t->target[hi][lo] = NULL;
|
|
|
|
|
t->targets--;
|
|
|
|
|
b = t->bucket[hi];
|
|
|
|
|
if (!b)
|
|
|
|
|
goto out;
|
|
|
|
|
g = b->target[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);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
b = NULL;
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
write_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
if (!g)
|
|
|
|
|
return -ENOENT;
|
|
|
|
|
if (b)
|
|
|
|
|
kfree(b);
|
|
|
|
|
|
|
|
|
|
target_push(g);
|
|
|
|
|
|
|
|
|
|
@ -1247,6 +1345,7 @@ error:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void crypto_context_init(struct mp_crypto_context *c, struct mediaproxy_srtp *s) {
|
|
|
|
|
c->cipher = &mp_ciphers[s->cipher];
|
|
|
|
|
c->hmac = &mp_hmacs[s->hmac];
|
|
|
|
|
@ -1255,7 +1354,7 @@ static void crypto_context_init(struct mp_crypto_context *c, struct mediaproxy_s
|
|
|
|
|
static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target_info *i, int update) {
|
|
|
|
|
unsigned char hi, lo;
|
|
|
|
|
struct mediaproxy_target *g;
|
|
|
|
|
struct mediaproxy_target **gp;
|
|
|
|
|
struct mp_bucket *b, *ba = NULL;
|
|
|
|
|
struct mediaproxy_target *og = NULL;
|
|
|
|
|
int err;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
@ -1302,31 +1401,37 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target
|
|
|
|
|
if (err)
|
|
|
|
|
goto fail2;
|
|
|
|
|
|
|
|
|
|
err = -ENOMEM;
|
|
|
|
|
if (update)
|
|
|
|
|
gp = NULL;
|
|
|
|
|
else {
|
|
|
|
|
gp = kmalloc(sizeof(void *) * 256, GFP_KERNEL);
|
|
|
|
|
if (!gp)
|
|
|
|
|
goto fail2;
|
|
|
|
|
memset(gp, 0, sizeof(void *) * 256);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hi = (i->target_port & 0xff00) >> 8;
|
|
|
|
|
lo = i->target_port & 0xff;
|
|
|
|
|
|
|
|
|
|
write_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
if (!t->target[hi]) {
|
|
|
|
|
if (!(b = t->bucket[hi])) {
|
|
|
|
|
err = -ENOENT;
|
|
|
|
|
if (update)
|
|
|
|
|
goto fail4;
|
|
|
|
|
t->target[hi] = gp;
|
|
|
|
|
gp = NULL;
|
|
|
|
|
t->buckets++;
|
|
|
|
|
|
|
|
|
|
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 (!t->bucket[hi]) {
|
|
|
|
|
t->bucket[hi] = b;
|
|
|
|
|
bitfield_set(&t->buckets, hi);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ba = b;
|
|
|
|
|
b = t->bucket[hi];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (update) {
|
|
|
|
|
err = -ENOENT;
|
|
|
|
|
og = t->target[hi][lo];
|
|
|
|
|
og = b->target[lo];
|
|
|
|
|
if (!og)
|
|
|
|
|
goto fail4;
|
|
|
|
|
|
|
|
|
|
@ -1336,18 +1441,18 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
err = -EEXIST;
|
|
|
|
|
if (t->target[hi][lo])
|
|
|
|
|
if (b->target[lo])
|
|
|
|
|
goto fail4;
|
|
|
|
|
bitfield_set(&b->targets, lo);
|
|
|
|
|
t->targets++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t->target[hi][lo] = g;
|
|
|
|
|
b->target[lo] = g;
|
|
|
|
|
g = NULL;
|
|
|
|
|
if (!update)
|
|
|
|
|
t->targets++;
|
|
|
|
|
write_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
|
|
|
|
|
if (gp)
|
|
|
|
|
kfree(gp);
|
|
|
|
|
if (ba)
|
|
|
|
|
kfree(ba);
|
|
|
|
|
if (og)
|
|
|
|
|
target_push(og);
|
|
|
|
|
|
|
|
|
|
@ -1355,8 +1460,8 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target
|
|
|
|
|
|
|
|
|
|
fail4:
|
|
|
|
|
write_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
if (gp)
|
|
|
|
|
kfree(gp);
|
|
|
|
|
if (ba)
|
|
|
|
|
kfree(ba);
|
|
|
|
|
fail2:
|
|
|
|
|
kfree(g);
|
|
|
|
|
fail1:
|
|
|
|
|
@ -1381,7 +1486,7 @@ static struct mediaproxy_target *get_target(struct mediaproxy_table *t, u_int16_
|
|
|
|
|
lo = port & 0xff;
|
|
|
|
|
|
|
|
|
|
read_lock_irqsave(&t->target_lock, flags);
|
|
|
|
|
r = t->target[hi] ? t->target[hi][lo] : NULL;
|
|
|
|
|
r = t->bucket[hi] ? t->bucket[hi]->target[lo] : NULL;
|
|
|
|
|
if (r)
|
|
|
|
|
target_hold(r);
|
|
|
|
|
read_unlock_irqrestore(&t->target_lock, flags);
|
|
|
|
|
|