|
|
|
@ -34,6 +34,7 @@ |
|
|
|
#include <linux/math64.h> |
|
|
|
#include <linux/kthread.h> |
|
|
|
#include <linux/wait.h> |
|
|
|
#include <linux/sort.h> |
|
|
|
#ifdef CONFIG_BTREE |
|
|
|
#include <linux/btree.h> |
|
|
|
#define KERNEL_PLAYER |
|
|
|
@ -230,7 +231,6 @@ 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 *); |
|
|
|
|
|
|
|
@ -418,7 +418,17 @@ struct re_stream { |
|
|
|
int eof; /* protected by packet_list_lock */ |
|
|
|
}; |
|
|
|
|
|
|
|
struct re_shm { |
|
|
|
unsigned long uaddr; |
|
|
|
size_t size; |
|
|
|
struct page **pages; |
|
|
|
unsigned int npages; |
|
|
|
void *kaddr; |
|
|
|
}; |
|
|
|
|
|
|
|
#define RE_HASH_BITS 8 /* make configurable? */ |
|
|
|
#define MAX_SHM_AREAS 16 |
|
|
|
|
|
|
|
struct rtpengine_table { |
|
|
|
atomic_t refcnt; |
|
|
|
rwlock_t target_lock; |
|
|
|
@ -443,7 +453,9 @@ struct rtpengine_table { |
|
|
|
struct hlist_head streams_hash[1 << RE_HASH_BITS]; |
|
|
|
|
|
|
|
spinlock_t shm_lock; |
|
|
|
struct list_head shm_list; |
|
|
|
struct re_shm shms[MAX_SHM_AREAS]; |
|
|
|
unsigned int nshms; |
|
|
|
unsigned long shm_total; |
|
|
|
|
|
|
|
struct global_stats_counter *rtpe_stats; |
|
|
|
|
|
|
|
@ -476,12 +488,6 @@ struct re_hmac { |
|
|
|
const char *tfm_name; |
|
|
|
}; |
|
|
|
|
|
|
|
struct re_shm { |
|
|
|
void *head; |
|
|
|
struct rtpengine_table *table; |
|
|
|
struct list_head list_entry; |
|
|
|
}; |
|
|
|
|
|
|
|
/* XXX shared */ |
|
|
|
struct rtp_header { |
|
|
|
unsigned char v_p_x_cc; |
|
|
|
@ -615,7 +621,6 @@ static atomic_t last_timer_thread_idx; |
|
|
|
# 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 |
|
|
|
@ -625,7 +630,6 @@ static atomic_t last_timer_thread_idx; |
|
|
|
# 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 = { |
|
|
|
@ -634,7 +638,6 @@ 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 = { |
|
|
|
@ -848,8 +851,6 @@ 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); |
|
|
|
INIT_LIST_HEAD(&t->packet_streams); |
|
|
|
INIT_LIST_HEAD(&t->play_streams); |
|
|
|
t->id = -1; |
|
|
|
@ -1113,11 +1114,17 @@ static void clear_table_player(struct rtpengine_table *t) { |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
static void release_shm(struct re_shm *rmm) { |
|
|
|
if (rmm->kaddr) |
|
|
|
vunmap(rmm->kaddr); |
|
|
|
unpin_user_pages(rmm->pages, rmm->npages); |
|
|
|
kvfree(rmm->pages); |
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
@ -1153,12 +1160,8 @@ 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); |
|
|
|
vfree(shm->head); |
|
|
|
kfree(shm); |
|
|
|
} |
|
|
|
for (unsigned int i = 0; i < t->nshms; i++) |
|
|
|
release_shm(&t->shms[i]); |
|
|
|
|
|
|
|
clear_table_proc_files(t); |
|
|
|
#ifdef KERNEL_PLAYER |
|
|
|
@ -1340,6 +1343,8 @@ static ssize_t proc_status(struct file *f, char __user *b, size_t l, loff_t *o) |
|
|
|
// unlocked/unsafe read |
|
|
|
len += sprintf(buf + len, "Players: %u\n", t->num_play_streams); |
|
|
|
len += sprintf(buf + len, "PStreams: %u\n", t->num_packet_streams); |
|
|
|
len += sprintf(buf + len, "Memory pins: %u\n", t->nshms); |
|
|
|
len += sprintf(buf + len, "Memory: %lu\n",t->shm_total); |
|
|
|
|
|
|
|
table_put(t); |
|
|
|
|
|
|
|
@ -2031,63 +2036,43 @@ static int is_valid_address(const struct re_address *rea) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
static void vm_mmap_open(struct vm_area_struct *vma); |
|
|
|
static void vm_mmap_close(struct vm_area_struct *vma); |
|
|
|
|
|
|
|
static const struct vm_operations_struct vm_mmap_ops = { |
|
|
|
.open = vm_mmap_open, |
|
|
|
.close = vm_mmap_close, |
|
|
|
}; |
|
|
|
|
|
|
|
static void vm_mmap_open(struct vm_area_struct *vma) { |
|
|
|
struct re_shm *shm; |
|
|
|
static int search_shm(const void *p, const void *m) { |
|
|
|
const struct re_shm *M = m; |
|
|
|
unsigned long a = (unsigned long) p; |
|
|
|
if (a < M->uaddr) |
|
|
|
return -1; |
|
|
|
if (a >= M->uaddr + M->size) |
|
|
|
return 1; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
if (vma->vm_ops != &vm_mmap_ops) |
|
|
|
return; |
|
|
|
if (!(shm = vma->vm_private_data)) |
|
|
|
return; |
|
|
|
static void *shm_map_resolve(struct rtpengine_table *t, void *p, size_t size) { |
|
|
|
spin_lock(&t->shm_lock); |
|
|
|
|
|
|
|
ref_get(shm->table); |
|
|
|
} |
|
|
|
struct re_shm *rmm = bsearch(p, &t->shms, t->nshms, sizeof(t->shms[0]), search_shm); |
|
|
|
|
|
|
|
static void vm_mmap_close(struct vm_area_struct *vma) { |
|
|
|
struct re_shm *shm; |
|
|
|
void *ret = NULL; |
|
|
|
|
|
|
|
if (vma->vm_ops != &vm_mmap_ops) |
|
|
|
return; |
|
|
|
if (!(shm = vma->vm_private_data)) |
|
|
|
return; |
|
|
|
if (!rmm) |
|
|
|
goto out; |
|
|
|
|
|
|
|
vma->vm_private_data = NULL; |
|
|
|
// start address is within range - check end address |
|
|
|
if ((unsigned long) p + size >= rmm->uaddr + rmm->size) |
|
|
|
goto out; |
|
|
|
|
|
|
|
table_put(shm->table); |
|
|
|
} |
|
|
|
ret = rmm->kaddr + ((unsigned long) p - rmm->uaddr); |
|
|
|
|
|
|
|
static void *shm_map_resolve(void *p, size_t size) { |
|
|
|
struct vm_area_struct *vma; |
|
|
|
struct re_shm *shm; |
|
|
|
out: |
|
|
|
spin_unlock(&t->shm_lock); |
|
|
|
|
|
|
|
// XXX is there a better way to map this to the kernel address? |
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,14,0) |
|
|
|
vma = vma_lookup(current->mm, (unsigned long) p); |
|
|
|
#else |
|
|
|
vma = find_vma(current->mm, (unsigned long) p); |
|
|
|
if (vma && (unsigned long) p < vma->vm_start) |
|
|
|
vma = NULL; |
|
|
|
#endif |
|
|
|
if (!vma) |
|
|
|
return NULL; |
|
|
|
if (!(shm = vma->vm_private_data)) |
|
|
|
return NULL; |
|
|
|
if ((unsigned long) p + size > vma->vm_end || (unsigned long) p + size < vma->vm_start) |
|
|
|
return NULL; |
|
|
|
if (vma->vm_ops != &vm_mmap_ops) |
|
|
|
return NULL; |
|
|
|
return shm->head + ((unsigned long) p - (unsigned long) vma->vm_start); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int validate_srtp(const struct rtpengine_srtp *s) { |
|
|
|
if (s->cipher <= REC_INVALID) |
|
|
|
return -1; |
|
|
|
@ -2521,14 +2506,14 @@ static int table_new_target(struct rtpengine_table *t, struct rtpengine_target_i |
|
|
|
if (validate_srtp(&i->decrypt)) |
|
|
|
return -EINVAL; |
|
|
|
|
|
|
|
iface_stats = shm_map_resolve(i->iface_stats, sizeof(*iface_stats)); |
|
|
|
iface_stats = shm_map_resolve(t, i->iface_stats, sizeof(*iface_stats)); |
|
|
|
if (!iface_stats) |
|
|
|
return -EFAULT; |
|
|
|
stats = shm_map_resolve(i->stats, sizeof(*stats)); |
|
|
|
stats = shm_map_resolve(t, i->stats, sizeof(*stats)); |
|
|
|
if (!stats) |
|
|
|
return -EFAULT; |
|
|
|
for (u = 0; u < i->num_payload_types; u++) { |
|
|
|
pt_stats[u] = shm_map_resolve(i->pt_stats[u], sizeof(*pt_stats[u])); |
|
|
|
pt_stats[u] = shm_map_resolve(t, i->pt_stats[u], sizeof(*pt_stats[u])); |
|
|
|
if (!pt_stats[u]) |
|
|
|
return -EFAULT; |
|
|
|
if (i->pt_media_idx[u] > RTPE_NUM_OUTPUT_MEDIA) |
|
|
|
@ -2539,7 +2524,7 @@ static int table_new_target(struct rtpengine_table *t, struct rtpengine_target_i |
|
|
|
break; |
|
|
|
if (!i->ssrc_stats[u]) |
|
|
|
return -EFAULT; |
|
|
|
ssrc_stats[u] = shm_map_resolve(i->ssrc_stats[u], sizeof(*ssrc_stats[u])); |
|
|
|
ssrc_stats[u] = shm_map_resolve(t, i->ssrc_stats[u], sizeof(*ssrc_stats[u])); |
|
|
|
if (!ssrc_stats[u]) |
|
|
|
return -EFAULT; |
|
|
|
} |
|
|
|
@ -2701,10 +2686,10 @@ static int table_add_destination(struct rtpengine_table *t, struct rtpengine_des |
|
|
|
if (validate_srtp(&i->output.encrypt)) |
|
|
|
return -EINVAL; |
|
|
|
|
|
|
|
iface_stats = shm_map_resolve(i->output.iface_stats, sizeof(*iface_stats)); |
|
|
|
iface_stats = shm_map_resolve(t, i->output.iface_stats, sizeof(*iface_stats)); |
|
|
|
if (!iface_stats) |
|
|
|
return -EFAULT; |
|
|
|
stats = shm_map_resolve(i->output.stats, sizeof(*stats)); |
|
|
|
stats = shm_map_resolve(t, i->output.stats, sizeof(*stats)); |
|
|
|
if (!stats) |
|
|
|
return -EFAULT; |
|
|
|
for (u = 0; u < RTPE_NUM_SSRC_TRACKING; u++) { |
|
|
|
@ -2712,7 +2697,7 @@ static int table_add_destination(struct rtpengine_table *t, struct rtpengine_des |
|
|
|
// XXX validate if target->ssrc[u] is set? |
|
|
|
if (!i->output.ssrc_stats[u]) |
|
|
|
break; |
|
|
|
ssrc_stats[u] = shm_map_resolve(i->output.ssrc_stats[u], sizeof(*ssrc_stats[u])); |
|
|
|
ssrc_stats[u] = shm_map_resolve(t, i->output.ssrc_stats[u], sizeof(*ssrc_stats[u])); |
|
|
|
if (!ssrc_stats[u]) |
|
|
|
return -EFAULT; |
|
|
|
} |
|
|
|
@ -2882,93 +2867,6 @@ 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; |
|
|
|
unsigned long pfn; |
|
|
|
void *pages; |
|
|
|
uint32_t id; |
|
|
|
struct rtpengine_table *t; |
|
|
|
int ret; |
|
|
|
struct re_shm *shm; |
|
|
|
struct inode *inode; |
|
|
|
size_t offset; |
|
|
|
|
|
|
|
// 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; |
|
|
|
|
|
|
|
// is it a multiple of the page size? |
|
|
|
if ((size & (PAGE_SIZE - 1)) != 0) |
|
|
|
return -EIO; |
|
|
|
|
|
|
|
// ok, allocate |
|
|
|
pages = vmalloc(size); |
|
|
|
if (!pages) |
|
|
|
return -ENOMEM; |
|
|
|
|
|
|
|
// make sure what we got is page-aligned |
|
|
|
if (((size_t) pages & (PAGE_SIZE - 1)) != 0) { |
|
|
|
vfree(pages); |
|
|
|
return -EAGAIN; |
|
|
|
} |
|
|
|
|
|
|
|
shm = kzalloc(sizeof(*shm), GFP_KERNEL); |
|
|
|
if (!shm) { |
|
|
|
vfree(pages); |
|
|
|
return -ENOMEM; |
|
|
|
} |
|
|
|
|
|
|
|
// get our table |
|
|
|
inode = file->f_path.dentry->d_inode; |
|
|
|
id = (uint32_t) (unsigned long) PDE_DATA(inode); |
|
|
|
t = get_table(id); |
|
|
|
if (!t) { |
|
|
|
vfree(pages); |
|
|
|
kfree(shm); |
|
|
|
return -ENOENT; |
|
|
|
} |
|
|
|
|
|
|
|
shm->head = pages; |
|
|
|
shm->table = t; // not a reference |
|
|
|
|
|
|
|
vma->vm_private_data = shm; |
|
|
|
vma->vm_ops = &vm_mmap_ops; |
|
|
|
|
|
|
|
// remap to userspace, page by page |
|
|
|
for (offset = 0; offset < size; offset += PAGE_SIZE) { |
|
|
|
pfn = vmalloc_to_pfn(pages + offset); |
|
|
|
ret = remap_pfn_range(vma, vma->vm_start + offset, pfn, PAGE_SIZE, vma->vm_page_prot); |
|
|
|
|
|
|
|
if (ret) { |
|
|
|
vfree(pages); |
|
|
|
kfree(shm); |
|
|
|
table_put(t); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// all done |
|
|
|
|
|
|
|
spin_lock(&t->shm_lock); |
|
|
|
list_add(&shm->list_entry, &t->shm_list); |
|
|
|
spin_unlock(&t->shm_lock); |
|
|
|
|
|
|
|
// retain reference on table - belongs to the shm list now |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int proc_control_open(struct inode *inode, struct file *file) { |
|
|
|
uint32_t id; |
|
|
|
@ -3854,6 +3752,94 @@ static void parse_rtcp(struct rtp_parsed *rtp, struct sk_buff *skb) { |
|
|
|
rtp->rtcp = 1; |
|
|
|
} |
|
|
|
|
|
|
|
static int cmp_shm(const void *a, const void *b) { |
|
|
|
const struct re_shm *A = a, *B = b; |
|
|
|
if (A->uaddr < B->uaddr) |
|
|
|
return -1; |
|
|
|
if (A->uaddr > B->uaddr) |
|
|
|
return 1; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int cmd_pin_memory(struct rtpengine_table *t, struct rtpengine_pin_memory_info *mi) { |
|
|
|
// verify size |
|
|
|
if (mi->size == 0) |
|
|
|
return -EINVAL; |
|
|
|
|
|
|
|
// is it a multiple of the page size? |
|
|
|
if ((mi->size & (PAGE_SIZE - 1)) != 0) |
|
|
|
return -EIO; |
|
|
|
|
|
|
|
// address is page-aligned? |
|
|
|
unsigned long addr = (unsigned long) mi->addr; |
|
|
|
if ((addr & (PAGE_SIZE - 1)) != 0) |
|
|
|
return -ENXIO; |
|
|
|
|
|
|
|
// full pages? |
|
|
|
int npages = mi->size / PAGE_SIZE; |
|
|
|
if (npages <= 0) |
|
|
|
return -EMSGSIZE; |
|
|
|
|
|
|
|
// primary object |
|
|
|
struct re_shm rmm = {0}; |
|
|
|
|
|
|
|
// fill in basics |
|
|
|
rmm.uaddr = addr; |
|
|
|
rmm.size = mi->size; |
|
|
|
|
|
|
|
// array for page pointers |
|
|
|
rmm.pages = kvmalloc(sizeof(*rmm.pages) * npages, GFP_KERNEL); |
|
|
|
if (!rmm.pages) { |
|
|
|
release_shm(&rmm); |
|
|
|
return -ENOMEM; |
|
|
|
} |
|
|
|
|
|
|
|
// pin pages |
|
|
|
int ret = pin_user_pages_fast(addr, npages, WRITE, rmm.pages); |
|
|
|
|
|
|
|
// successful? |
|
|
|
if (ret != npages) { |
|
|
|
if (ret > 0) |
|
|
|
rmm.npages = ret; |
|
|
|
release_shm(&rmm); |
|
|
|
return -EFAULT; |
|
|
|
} |
|
|
|
|
|
|
|
// got our pages |
|
|
|
rmm.npages = npages; |
|
|
|
|
|
|
|
// map to kernel |
|
|
|
rmm.kaddr = vmap(rmm.pages, npages, VM_MAP, PAGE_KERNEL); |
|
|
|
|
|
|
|
// successful? |
|
|
|
if (!rmm.kaddr) { |
|
|
|
release_shm(&rmm); |
|
|
|
return -ENOBUFS; |
|
|
|
} |
|
|
|
|
|
|
|
// ok, add to our list |
|
|
|
|
|
|
|
spin_lock(&t->shm_lock); |
|
|
|
|
|
|
|
if (t->nshms >= MAX_SHM_AREAS) { |
|
|
|
spin_unlock(&t->shm_lock); |
|
|
|
release_shm(&rmm); |
|
|
|
return -E2BIG; |
|
|
|
} |
|
|
|
|
|
|
|
// add to end |
|
|
|
t->shms[t->nshms] = rmm; |
|
|
|
t->nshms++; |
|
|
|
t->shm_total += mi->size; |
|
|
|
|
|
|
|
// sort it by user address |
|
|
|
sort(t->shms, t->nshms, sizeof(t->shms[0]), cmp_shm, NULL); |
|
|
|
|
|
|
|
spin_unlock(&t->shm_lock); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef KERNEL_PLAYER |
|
|
|
|
|
|
|
static void shut_threads(struct timer_thread **thr, unsigned int nt) { |
|
|
|
@ -4459,13 +4445,13 @@ static int play_stream(struct rtpengine_table *t, const struct rtpengine_play_st |
|
|
|
if (validate_srtp(&info->encrypt)) |
|
|
|
return -EINVAL; |
|
|
|
|
|
|
|
iface_stats = shm_map_resolve(info->iface_stats, sizeof(*iface_stats)); |
|
|
|
iface_stats = shm_map_resolve(t, info->iface_stats, sizeof(*iface_stats)); |
|
|
|
if (!iface_stats) |
|
|
|
return -EFAULT; |
|
|
|
stats = shm_map_resolve(info->stats, sizeof(*stats)); |
|
|
|
stats = shm_map_resolve(t, info->stats, sizeof(*stats)); |
|
|
|
if (!stats) |
|
|
|
return -EFAULT; |
|
|
|
ssrc_stats = shm_map_resolve(info->ssrc_stats, sizeof(*ssrc_stats)); |
|
|
|
ssrc_stats = shm_map_resolve(t, info->ssrc_stats, sizeof(*ssrc_stats)); |
|
|
|
if (!ssrc_stats) |
|
|
|
return -EFAULT; |
|
|
|
|
|
|
|
@ -4740,6 +4726,7 @@ static const size_t min_req_sizes[__REMG_LAST] = { |
|
|
|
[REMG_PLAY_STREAM] = sizeof(struct rtpengine_command_play_stream), |
|
|
|
[REMG_STOP_STREAM] = sizeof(struct rtpengine_command_stop_stream), |
|
|
|
[REMG_FREE_PACKET_STREAM]= sizeof(struct rtpengine_command_free_packet_stream), |
|
|
|
[REMG_PIN_MEMORY] = sizeof(struct rtpengine_command_pin_memory), |
|
|
|
|
|
|
|
}; |
|
|
|
static const size_t max_req_sizes[__REMG_LAST] = { |
|
|
|
@ -4758,6 +4745,7 @@ static const size_t max_req_sizes[__REMG_LAST] = { |
|
|
|
[REMG_PLAY_STREAM] = sizeof(struct rtpengine_command_play_stream), |
|
|
|
[REMG_STOP_STREAM] = sizeof(struct rtpengine_command_stop_stream), |
|
|
|
[REMG_FREE_PACKET_STREAM]= sizeof(struct rtpengine_command_free_packet_stream), |
|
|
|
[REMG_PIN_MEMORY] = sizeof(struct rtpengine_command_pin_memory), |
|
|
|
}; |
|
|
|
|
|
|
|
static int rtpengine_init_table(struct rtpengine_table *t, struct rtpengine_init_info *init) { |
|
|
|
@ -4765,7 +4753,7 @@ static int rtpengine_init_table(struct rtpengine_table *t, struct rtpengine_init |
|
|
|
|
|
|
|
if (t->rtpe_stats) |
|
|
|
return -EBUSY; |
|
|
|
t->rtpe_stats = shm_map_resolve(init->rtpe_stats, sizeof(*t->rtpe_stats)); |
|
|
|
t->rtpe_stats = shm_map_resolve(t, init->rtpe_stats, sizeof(*t->rtpe_stats)); |
|
|
|
if (!t->rtpe_stats) |
|
|
|
return -EFAULT; |
|
|
|
if (init->last_cmd != __REMG_LAST) |
|
|
|
@ -4796,6 +4784,7 @@ static inline ssize_t proc_control_read_write(struct file *file, char __user *ub |
|
|
|
struct rtpengine_command_add_stream *add_stream; |
|
|
|
struct rtpengine_command_del_stream *del_stream; |
|
|
|
struct rtpengine_command_packet *packet; |
|
|
|
struct rtpengine_command_pin_memory *pin_memory; |
|
|
|
#ifdef KERNEL_PLAYER |
|
|
|
struct rtpengine_command_init_play_streams *init_play_streams; |
|
|
|
struct rtpengine_command_get_packet_stream *get_packet_stream; |
|
|
|
@ -4894,6 +4883,10 @@ static inline ssize_t proc_control_read_write(struct file *file, char __user *ub |
|
|
|
err = stream_packet(t, &msg.packet->packet, buflen - sizeof(*msg.packet)); |
|
|
|
break; |
|
|
|
|
|
|
|
case REMG_PIN_MEMORY: |
|
|
|
err = cmd_pin_memory(t, &msg.pin_memory->pin_memory); |
|
|
|
break; |
|
|
|
|
|
|
|
#ifdef KERNEL_PLAYER |
|
|
|
|
|
|
|
case REMG_INIT_PLAY_STREAMS: |
|
|
|
|