|
|
|
@ -216,6 +216,7 @@ static ssize_t proc_control_read(struct file *, char __user *, size_t, loff_t *) |
|
|
|
static ssize_t proc_control_write(struct file *, const char __user *, size_t, loff_t *); |
|
|
|
static int proc_control_open(struct inode *, struct file *); |
|
|
|
static int proc_control_close(struct inode *, struct file *); |
|
|
|
static int proc_control_mmap(struct file *, struct vm_area_struct *); |
|
|
|
|
|
|
|
static ssize_t proc_status(struct file *, char __user *, size_t, loff_t *); |
|
|
|
|
|
|
|
@ -436,6 +437,9 @@ struct rtpengine_table { |
|
|
|
struct hlist_head calls_hash[1 << RE_HASH_BITS]; |
|
|
|
spinlock_t streams_hash_lock[1 << RE_HASH_BITS]; |
|
|
|
struct hlist_head streams_hash[1 << RE_HASH_BITS]; |
|
|
|
|
|
|
|
spinlock_t shm_lock; |
|
|
|
struct list_head shm_list; |
|
|
|
}; |
|
|
|
|
|
|
|
struct re_cipher { |
|
|
|
@ -460,6 +464,13 @@ struct re_hmac { |
|
|
|
const char *tfm_name; |
|
|
|
}; |
|
|
|
|
|
|
|
struct re_shm { |
|
|
|
void *head; |
|
|
|
size_t size; |
|
|
|
unsigned int order; |
|
|
|
struct list_head list_entry; |
|
|
|
}; |
|
|
|
|
|
|
|
/* XXX shared */ |
|
|
|
struct rtp_header { |
|
|
|
unsigned char v_p_x_cc; |
|
|
|
@ -511,9 +522,6 @@ static struct re_auto_array streams; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0) |
|
|
|
# define PROC_OP_STRUCT file_operations |
|
|
|
# define PROC_OWNER \ |
|
|
|
@ -524,6 +532,7 @@ static struct re_auto_array streams; |
|
|
|
# define PROC_RELEASE release |
|
|
|
# define PROC_LSEEK llseek |
|
|
|
# define PROC_POLL poll |
|
|
|
# define PROC_MMAP mmap |
|
|
|
#else |
|
|
|
# define PROC_OP_STRUCT proc_ops |
|
|
|
# define PROC_OWNER |
|
|
|
@ -533,6 +542,7 @@ static struct re_auto_array streams; |
|
|
|
# define PROC_RELEASE proc_release |
|
|
|
# define PROC_LSEEK proc_lseek |
|
|
|
# define PROC_POLL proc_poll |
|
|
|
# define PROC_MMAP proc_mmap |
|
|
|
#endif |
|
|
|
|
|
|
|
static const struct PROC_OP_STRUCT proc_control_ops = { |
|
|
|
@ -541,6 +551,7 @@ static const struct PROC_OP_STRUCT proc_control_ops = { |
|
|
|
.PROC_WRITE = proc_control_write, |
|
|
|
.PROC_OPEN = proc_control_open, |
|
|
|
.PROC_RELEASE = proc_control_close, |
|
|
|
.PROC_MMAP = proc_control_mmap, |
|
|
|
}; |
|
|
|
|
|
|
|
static const struct PROC_OP_STRUCT proc_main_control_ops = { |
|
|
|
@ -761,6 +772,8 @@ static struct rtpengine_table *new_table(void) { |
|
|
|
atomic_set(&t->refcnt, 1); |
|
|
|
rwlock_init(&t->target_lock); |
|
|
|
INIT_LIST_HEAD(&t->calls); |
|
|
|
INIT_LIST_HEAD(&t->shm_list); |
|
|
|
spin_lock_init(&t->shm_lock); |
|
|
|
t->id = -1; |
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(t->calls_hash); i++) { |
|
|
|
@ -971,6 +984,7 @@ static void table_put(struct rtpengine_table *t) { |
|
|
|
int i, j, k; |
|
|
|
struct re_dest_addr *rda; |
|
|
|
struct re_bucket *b; |
|
|
|
struct re_shm *shm; |
|
|
|
|
|
|
|
if (!t) |
|
|
|
return; |
|
|
|
@ -1006,6 +1020,13 @@ static void table_put(struct rtpengine_table *t) { |
|
|
|
t->dest_addr_hash.addrs[k] = NULL; |
|
|
|
} |
|
|
|
|
|
|
|
while (!list_empty(&t->shm_list)) { |
|
|
|
shm = list_first_entry(&t->shm_list, struct re_shm, list_entry); |
|
|
|
list_del_init(&shm->list_entry); |
|
|
|
free_pages((unsigned long) shm->head, shm->order); |
|
|
|
kfree(shm); |
|
|
|
} |
|
|
|
|
|
|
|
clear_table_proc_files(t); |
|
|
|
kfree(t); |
|
|
|
|
|
|
|
@ -2715,6 +2736,84 @@ static ssize_t proc_main_control_write(struct file *file, const char __user *buf |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int proc_control_mmap(struct file *file, struct vm_area_struct *vma) { |
|
|
|
size_t size, order; |
|
|
|
unsigned long pfn; |
|
|
|
struct page *page; |
|
|
|
void *pages; |
|
|
|
uint32_t id; |
|
|
|
struct rtpengine_table *t; |
|
|
|
int ret; |
|
|
|
struct re_shm *shm; |
|
|
|
struct inode *inode; |
|
|
|
|
|
|
|
// verify arguments |
|
|
|
if ((vma->vm_flags & VM_EXEC)) |
|
|
|
return -EPERM; |
|
|
|
if (vma->vm_pgoff) |
|
|
|
return -EINVAL; |
|
|
|
|
|
|
|
// verify size |
|
|
|
size = vma->vm_end - vma->vm_start; |
|
|
|
if (size == 0) |
|
|
|
return -EINVAL; |
|
|
|
|
|
|
|
// determine and verify order (1<<n) |
|
|
|
// is a power of 2? |
|
|
|
if ((size & (size - 1)) != 0) |
|
|
|
return -EIO; |
|
|
|
|
|
|
|
order = __fls((unsigned long) size); // size = 256 -> order = 8 |
|
|
|
if (1 << order != size) |
|
|
|
return -ENXIO; |
|
|
|
|
|
|
|
// adjust order to page size |
|
|
|
if (order < PAGE_SHIFT) |
|
|
|
return -E2BIG; |
|
|
|
order -= PAGE_SHIFT; |
|
|
|
|
|
|
|
// ok, allocate pages |
|
|
|
page = alloc_pages(GFP_KERNEL_ACCOUNT, order); |
|
|
|
if (!page) |
|
|
|
return -ENOMEM; |
|
|
|
|
|
|
|
pages = page_address(page); |
|
|
|
|
|
|
|
shm = kzalloc(sizeof(*shm), GFP_KERNEL); |
|
|
|
if (!shm) { |
|
|
|
free_pages((unsigned long) pages, order); |
|
|
|
return -ENOMEM; |
|
|
|
} |
|
|
|
|
|
|
|
shm->head = pages; |
|
|
|
shm->size = size; |
|
|
|
shm->order = order; |
|
|
|
|
|
|
|
// get our table |
|
|
|
inode = file->f_path.dentry->d_inode; |
|
|
|
id = (uint32_t) (unsigned long) PDE_DATA(inode); |
|
|
|
t = get_table(id); |
|
|
|
if (!t) { |
|
|
|
free_pages((unsigned long) pages, order); |
|
|
|
kfree(shm); |
|
|
|
return -ENOENT; |
|
|
|
} |
|
|
|
|
|
|
|
pfn = virt_to_phys(pages) >> PAGE_SHIFT; |
|
|
|
vma->vm_private_data = pages; // remember kernel-space address |
|
|
|
|
|
|
|
ret = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot); |
|
|
|
|
|
|
|
if (ret == 0) { |
|
|
|
spin_lock(&t->shm_lock); |
|
|
|
list_add(&shm->list_entry, &t->shm_list); |
|
|
|
spin_unlock(&t->shm_lock); |
|
|
|
} |
|
|
|
|
|
|
|
table_put(t); |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static int proc_control_open(struct inode *inode, struct file *file) { |
|
|
|
uint32_t id; |
|
|
|
|