struct pfq_recycle_stat pfq_get_recycle_stats(void) { struct pfq_recycle_stat ret = { sparse_read(&os_alloc), sparse_read(&os_free), sparse_read(&rc_alloc), sparse_read(&rc_free), sparse_read(&rc_error)}; return ret; }
//ret copied length if successful, -1 if failed static int r_buf_cpy(RBuffer *b, ut64 addr, ut8 *dst, const ut8 *src, int len, int write) { int end; if (!b || b->empty) return 0; if (b->sparse) { if (write) { // create new with src + len if (sparse_write (b->sparse, addr, src, len) <0) return -1; } else { // read from sparse and write into dst memset (dst, 0xff, len); if (sparse_read (b->sparse, addr, dst, len) <0) return -1; } return len; } addr = (addr==R_BUF_CUR)? b->cur: addr-b->base; if (len<1 || dst == NULL || addr > b->length) return -1; end = (int)(addr+len); if (end > b->length) len -= end-b->length; if (write) dst += addr; else src += addr; memmove (dst, src, len); b->cur = addr + len; return len; }
static int pfq_proc_stats(struct seq_file *m, void *v) { seq_printf(m, "INPUT:\n"); seq_printf(m, " received : %ld\n", sparse_read(&global_stats, recv)); seq_printf(m, " lost : %ld\n", sparse_read(&global_stats, lost)); seq_printf(m, "OUTPUT:\n"); seq_printf(m, " sent : %ld\n", sparse_read(&global_stats, sent)); seq_printf(m, " kernel : %ld\n", sparse_read(&global_stats, kern)); seq_printf(m, " forwarded : %ld\n", sparse_read(&global_stats, frwd)); seq_printf(m, " discarded : %ld\n", sparse_read(&global_stats, disc)); seq_printf(m, " aborted : %ld\n", sparse_read(&global_stats, abrt)); seq_printf(m, "SCHEDULE:\n"); seq_printf(m, " poll : %ld\n", sparse_read(&global_stats, poll)); seq_printf(m, " wakeup : %ld\n", sparse_read(&global_stats, wake)); return 0; }
// ret copied length if successful, -1 if failed static int r_buf_cpy(RBuffer *b, ut64 addr, ut8 *dst, const ut8 *src, int len, int write) { int end; if (!b || b->empty) { return 0; } if (b->fd != -1) { if (r_sandbox_lseek (b->fd, addr, SEEK_SET) == -1) { // seek failed - print error here? // return 0; } if (write) { return r_sandbox_write (b->fd, src, len); } memset (dst, 0, len); return r_sandbox_read (b->fd, dst, len); } if (b->sparse) { if (write) { // create new with src + len if (sparse_write (b->sparse, addr, src, len) < 0) { return -1; } } else { // read from sparse and write into dst memset (dst, 0xff, len); if (sparse_read (b->sparse, addr, dst, len) < 0) { return -1; } } return len; } addr = (addr == R_BUF_CUR) ? b->cur : addr - b->base; if (len < 1 || !dst || addr > b->length) { return -1; } end = (int)(addr + len); if (end > b->length) { len -= end-b->length; } if (write) { dst += addr; } else { src += addr; } memmove (dst, src, len); b->cur = addr + len; return len; }
static int pfq_proc_groups(struct seq_file *m, void *v) { size_t n; seq_printf(m, "group: recv drop forward kernel disc aborted pol pid def. uplane cplane ctrl\n"); down(&group_sem); for(n = 0; n < Q_MAX_GID; n++) { pfq_gid_t gid = (__force pfq_gid_t)n; struct pfq_group *this_group = pfq_get_group(gid); if (!this_group->policy) continue; seq_printf(m, "%5zu: %-9lu %-9lu %-9lu %-9lu %-9lu %-9lu", n, sparse_read(this_group->stats, recv), sparse_read(this_group->stats, drop), sparse_read(this_group->stats, frwd), sparse_read(this_group->stats, kern), sparse_read(this_group->stats, disc), sparse_read(this_group->stats, abrt)); seq_printf(m, "%3d %3d ", this_group->policy, this_group->pid); seq_printf(m, "%08lx %08lx %08lx %08lx \n", atomic_long_read(&this_group->sock_mask[pfq_ctz(Q_CLASS_DEFAULT)]), atomic_long_read(&this_group->sock_mask[pfq_ctz(Q_CLASS_USER_PLANE)]), atomic_long_read(&this_group->sock_mask[pfq_ctz(Q_CLASS_CONTROL_PLANE)]), atomic_long_read(&this_group->sock_mask[63])); } up(&group_sem); return 0; }
int pfq_getsockopt(struct socket *sock, int level, int optname, char __user * optval, int __user * optlen) { struct pfq_sock *so = pfq_sk(sock->sk); struct pfq_rx_opt * ro; struct pfq_tx_opt * to; int len; if (so == NULL) return -EFAULT; ro = &so->rx_opt; to = &so->tx_opt; if (get_user(len, optlen)) return -EFAULT; if (len < 0) return -EINVAL; switch(optname) { case Q_SO_GROUP_JOIN: { struct pfq_group_join group; if (len != sizeof(group)) return -EINVAL; if (copy_from_user(&group, optval, sizeof(group))) return -EFAULT; if (group.class_mask == 0) { pr_devel("[PFQ|%d] join error: bad class_mask(%lx)!\n", so->id, group.class_mask); return -EINVAL; } if (group.gid == Q_ANY_GROUP) { group.gid = pfq_join_free_group(so->id, group.class_mask, group.policy); if (group.gid < 0) return -EFAULT; if (copy_to_user(optval, &group, len)) return -EFAULT; } else { CHECK_GROUP(so->id, group.gid, "group join"); if (pfq_join_group(group.gid, so->id, group.class_mask, group.policy) < 0) { pr_devel("[PFQ|%d] join error: permission denied (gid:%d)!\n", so->id, group.gid); return -EACCES; } } pr_devel("[PFQ|%d] join -> gid:%d class_mask:%lx\n", so->id, group.gid, group.class_mask); } break; case Q_SO_GET_ID: { if (len != sizeof(so->id)) return -EINVAL; if (copy_to_user(optval, &so->id, sizeof(so->id))) return -EFAULT; } break; case Q_SO_GET_STATUS: { int enabled; if (len != sizeof(int)) return -EINVAL; enabled = so->mem_addr == NULL ? 0 : 1; if (copy_to_user(optval, &enabled, sizeof(enabled))) return -EFAULT; } break; case Q_SO_GET_STATS: { struct pfq_stats stat; if (len != sizeof(struct pfq_stats)) return -EINVAL; stat.recv = sparse_read(&ro->stat.recv); stat.lost = sparse_read(&ro->stat.lost); stat.drop = sparse_read(&ro->stat.drop); stat.sent = sparse_read(&to->stat.sent); stat.disc = sparse_read(&to->stat.disc); if (copy_to_user(optval, &stat, sizeof(stat))) return -EFAULT; } break; case Q_SO_GET_RX_TSTAMP: { if (len != sizeof(ro->tstamp)) return -EINVAL; if (copy_to_user(optval, &ro->tstamp, sizeof(ro->tstamp))) return -EFAULT; } break; case Q_SO_GET_QUEUE_MEM: { if (len != sizeof(so->mem_size)) return -EINVAL; if (copy_to_user(optval, &so->mem_size, sizeof(so->mem_size))) return -EFAULT; } break; case Q_SO_GET_RX_CAPLEN: { if (len != sizeof(ro->caplen)) return -EINVAL; if (copy_to_user(optval, &ro->caplen, sizeof(ro->caplen))) return -EFAULT; } break; case Q_SO_GET_TX_MAXLEN: { if (len != sizeof(to->maxlen)) return -EINVAL; if (copy_to_user(optval, &to->maxlen, sizeof(to->maxlen))) return -EFAULT; } break; case Q_SO_GET_RX_SLOTS: { if (len != sizeof(ro->size)) return -EINVAL; if (copy_to_user(optval, &ro->size, sizeof(ro->size))) return -EFAULT; } break; case Q_SO_GET_TX_SLOTS: { if (len != sizeof(to->size)) return -EINVAL; if (copy_to_user(optval, &to->size, sizeof(to->size))) return -EFAULT; } break; case Q_SO_GET_GROUPS: { unsigned long grps; if(len != sizeof(unsigned long)) return -EINVAL; grps = pfq_get_groups(so->id); if (copy_to_user(optval, &grps, sizeof(grps))) return -EFAULT; } break; case Q_SO_GET_GROUP_STATS: { struct pfq_group *g; struct pfq_stats stat; int gid; if (len != sizeof(stat)) return -EINVAL; if (copy_from_user(&stat, optval, sizeof(stat))) return -EFAULT; gid = (int)stat.recv; CHECK_GROUP(so->id, gid, "group stat"); g = pfq_get_group(gid); if (!g) { pr_devel("[PFQ|%d] group error: invalid group id %d!\n", so->id, gid); return -EFAULT; } /* check whether the group is joinable.. */ if (!__pfq_group_access(gid, so->id, Q_POLICY_GROUP_UNDEFINED, false)) { pr_devel("[PFQ|%d] group stats error: permission denied (gid:%d)!\n", so->id, gid); return -EACCES; } stat.recv = sparse_read(&g->recv); stat.lost = sparse_read(&g->lost); stat.drop = sparse_read(&g->drop); stat.sent = 0; stat.disc = 0; if (copy_to_user(optval, &stat, sizeof(stat))) return -EFAULT; } break; case Q_SO_GET_GROUP_COUNTERS: { struct pfq_group *g; struct pfq_counters cs; int i, gid; if (len != sizeof(cs)) return -EINVAL; if (copy_from_user(&cs, optval, sizeof(cs))) return -EFAULT; gid = (int)cs.counter[0]; CHECK_GROUP(so->id, gid, "group stat"); g = pfq_get_group(gid); if (!g) { pr_devel("[PFQ|%d] group error: invalid group id %d!\n", so->id, gid); return -EFAULT; } /* check whether the group is joinable.. */ if (!__pfq_group_access(gid, so->id, Q_POLICY_GROUP_UNDEFINED, false)) { pr_devel("[PFQ|%d] group error: permission denied (gid:%d)!\n", so->id, gid); return -EACCES; } for(i = 0; i < Q_MAX_COUNTERS; i++) { cs.counter[i] = sparse_read(&g->ctx.counter[i]); } if (copy_to_user(optval, &cs, sizeof(cs))) return -EFAULT; } break; default: return -EFAULT; } return 0; }
int pfq_getsockopt(struct socket *sock, int level, int optname, char __user * optval, int __user * optlen) { struct pfq_sock *so = pfq_sk(sock->sk); int len; if (so == NULL) return -EFAULT; if (get_user(len, optlen)) return -EFAULT; if (len < 0) return -EINVAL; switch(optname) { case Q_SO_GROUP_JOIN: { struct pfq_group_join group; if (len != sizeof(group)) return -EINVAL; if (copy_from_user(&group, optval, sizeof(group))) return -EFAULT; if (group.class_mask == 0) { printk(KERN_INFO "[PFQ|%d] join error: bad class_mask (%lx)!\n", so->id.value, group.class_mask); return -EINVAL; } if (group.gid == Q_ANY_GROUP) { group.gid = pfq_join_free_group(so->id, group.class_mask, group.policy); if (group.gid < 0) return -EFAULT; if (copy_to_user(optval, &group, len)) return -EFAULT; } else { pfq_gid_t gid = { group.gid }; if (!pfq_get_group(gid)) { printk(KERN_INFO "[PFQ|%d] group error: invalid group id %d!\n", so->id.value, gid.value); return -EFAULT; } if (pfq_join_group(gid, so->id, group.class_mask, group.policy) < 0) { printk(KERN_INFO "[PFQ|%d] join error: permission denied (gid=%d)!\n", so->id.value, group.gid); return -EACCES; } } pr_devel("[PFQ|%d] join: gid=%d class_mask=%lx\n", so->id.value, group.gid, group.class_mask); } break; case Q_SO_GET_ID: { if (len != sizeof(so->id.value)) return -EINVAL; if (copy_to_user(optval, &so->id.value, sizeof(so->id.value))) return -EFAULT; } break; case Q_SO_GET_STATUS: { int enabled; if (len != sizeof(int)) return -EINVAL; enabled = so->shmem.addr == NULL ? 0 : 1; if (copy_to_user(optval, &enabled, sizeof(enabled))) return -EFAULT; } break; case Q_SO_GET_STATS: { struct pfq_stats stat; if (len != sizeof(struct pfq_stats)) return -EINVAL; stat.recv = sparse_read(&so->rx_opt.stats.recv); stat.lost = sparse_read(&so->rx_opt.stats.lost); stat.drop = sparse_read(&so->rx_opt.stats.drop); stat.frwd = 0; stat.kern = 0; stat.sent = sparse_read(&so->tx_opt.stats.sent); stat.disc = sparse_read(&so->tx_opt.stats.disc); if (copy_to_user(optval, &stat, sizeof(stat))) return -EFAULT; } break; case Q_SO_GET_RX_TSTAMP: { if (len != sizeof(so->rx_opt.tstamp)) return -EINVAL; if (copy_to_user(optval, &so->rx_opt.tstamp, sizeof(so->rx_opt.tstamp))) return -EFAULT; } break; case Q_SO_GET_SHMEM_SIZE: { size_t size = pfq_shared_memory_size(so); if (len != sizeof(size)) return -EINVAL; if (copy_to_user(optval, &size, sizeof(size))) return -EFAULT; } break; case Q_SO_GET_RX_CAPLEN: { if (len != sizeof(so->rx_opt.caplen)) return -EINVAL; if (copy_to_user(optval, &so->rx_opt.caplen, sizeof(so->rx_opt.caplen))) return -EFAULT; } break; case Q_SO_GET_TX_MAXLEN: { if (len != sizeof(max_len)) return -EINVAL; if (copy_to_user(optval, &max_len, sizeof(max_len))) return -EFAULT; } break; case Q_SO_GET_RX_SLOTS: { if (len != sizeof(so->rx_opt.queue_size)) return -EINVAL; if (copy_to_user(optval, &so->rx_opt.queue_size, sizeof(so->rx_opt.queue_size))) return -EFAULT; } break; case Q_SO_GET_TX_SLOTS: { if (len != sizeof(so->tx_opt.queue_size)) return -EINVAL; if (copy_to_user(optval, &so->tx_opt.queue_size, sizeof(so->tx_opt.queue_size))) return -EFAULT; } break; case Q_SO_GET_GROUPS: { unsigned long grps; if(len != sizeof(unsigned long)) return -EINVAL; grps = pfq_get_groups(so->id); if (copy_to_user(optval, &grps, sizeof(grps))) return -EFAULT; } break; case Q_SO_GET_GROUP_STATS: { struct pfq_group *g; struct pfq_stats stat; pfq_gid_t gid; if (len != sizeof(stat)) return -EINVAL; if (copy_from_user(&stat, optval, sizeof(stat))) return -EFAULT; gid.value = (int)stat.recv; g = pfq_get_group(gid); if (g == NULL) { printk(KERN_INFO "[PFQ|%d] group error: invalid group id %d!\n", so->id.value, gid.value); return -EFAULT; } if (pfq_group_is_free(gid)) { printk(KERN_INFO "[PFQ|%d] group stats error: gid=%d is a free group!\n", so->id.value, gid.value); return -EACCES; } if (!pfq_group_access(gid, so->id)) { printk(KERN_INFO "[PFQ|%d] group stats error: gid=%d permission denied!\n", so->id.value, gid.value); return -EACCES; } stat.recv = sparse_read(&g->stats.recv); stat.drop = sparse_read(&g->stats.drop); stat.frwd = sparse_read(&g->stats.frwd); stat.kern = sparse_read(&g->stats.kern); stat.lost = 0; stat.sent = 0; stat.disc = 0; if (copy_to_user(optval, &stat, sizeof(stat))) return -EFAULT; } break; case Q_SO_GET_GROUP_COUNTERS: { struct pfq_group *g; struct pfq_counters cs; pfq_gid_t gid; int i; if (len != sizeof(cs)) return -EINVAL; if (copy_from_user(&cs, optval, sizeof(cs))) return -EFAULT; gid.value = (int)cs.counter[0]; g = pfq_get_group(gid); if (g == NULL) { printk(KERN_INFO "[PFQ|%d] group error: invalid group id %d!\n", so->id.value, gid.value); return -EFAULT; } /* check whether the group is joinable.. */ if (!pfq_group_policy_access(gid, so->id, Q_POLICY_GROUP_UNDEFINED)) { printk(KERN_INFO "[PFQ|%d] group error: permission denied (gid=%d)!\n", so->id.value, gid.value); return -EACCES; } for(i = 0; i < Q_MAX_COUNTERS; i++) { cs.counter[i] = sparse_read(&g->context.counter[i]); } if (copy_to_user(optval, &cs, sizeof(cs))) return -EFAULT; } break; default: return -EFAULT; } return 0; }
static int pfq_proc_memory(struct seq_file *m, void *v) { long int push = sparse_read(&memory_stats, pool_push); long int pop = sparse_read(&memory_stats, pool_pop); seq_printf(m, "OS:\n"); seq_printf(m, " alloc : %ld\n", sparse_read(&memory_stats, os_alloc)); seq_printf(m, " free : %ld\n", sparse_read(&memory_stats, os_free)); seq_printf(m, "POOL:\n"); seq_printf(m, " alloc : %ld\n", sparse_read(&memory_stats, pool_alloc)); seq_printf(m, " free : %ld\n", sparse_read(&memory_stats, pool_free)); seq_printf(m, " push : %ld\n", push); seq_printf(m, " pop : %ld\n", pop); seq_printf(m, " size : %ld\n", push - pop); seq_printf(m, "ERROR:\n"); seq_printf(m, " error norecyl : %ld\n", sparse_read(&memory_stats, err_norecyl)); seq_printf(m, " error pop : %ld\n", sparse_read(&memory_stats, err_pop)); seq_printf(m, " error push : %ld\n", sparse_read(&memory_stats, err_push)); seq_printf(m, " error intdisab : %ld\n", sparse_read(&memory_stats, err_intdis)); seq_printf(m, " error shared : %ld\n", sparse_read(&memory_stats, err_shared)); seq_printf(m, " error cloned : %ld\n", sparse_read(&memory_stats, err_cloned)); seq_printf(m, " error memory : %ld\n", sparse_read(&memory_stats, err_memory)); return 0; }
struct pfq_pool_stat pfq_get_skb_pool_stats(void) { struct pfq_pool_stat ret = { sparse_read(&memory_stats.os_alloc), sparse_read(&memory_stats.os_free), sparse_read(&memory_stats.pool_alloc), sparse_read(&memory_stats.pool_free), sparse_read(&memory_stats.pool_push), sparse_read(&memory_stats.pool_pop), sparse_read(&memory_stats.err_norecyl), sparse_read(&memory_stats.err_pop), sparse_read(&memory_stats.err_push), sparse_read(&memory_stats.err_intdis), sparse_read(&memory_stats.err_shared), sparse_read(&memory_stats.err_cloned), sparse_read(&memory_stats.err_memory), }; return ret; }
int pfq_getsockopt(struct socket *sock, int level, int optname, char __user * optval, int __user * optlen) { struct pfq_sock *so = pfq_sk(sock->sk); int len; if (so == NULL) return -EFAULT; if (get_user(len, optlen)) return -EFAULT; if (len < 0) return -EINVAL; switch(optname) { case Q_SO_GROUP_JOIN: { struct pfq_group_join group; if (len != sizeof(group)) return -EINVAL; if (copy_from_user(&group, optval, sizeof(group))) return -EFAULT; if (group.class_mask == 0) { printk(KERN_INFO "[PFQ|%d] join group error: bad class_mask (%lx)!\n", so->id, group.class_mask); return -EINVAL; } if (group.gid == Q_ANY_GROUP) { group.gid = pfq_join_free_group(so->id, group.class_mask, group.policy); if (group.gid < 0) return -EFAULT; if (copy_to_user(optval, &group, len)) return -EFAULT; } else { pfq_gid_t gid = (__force pfq_gid_t)group.gid; if (!pfq_get_group(gid)) { printk(KERN_INFO "[PFQ|%d] join group error: invalid group id %d!\n", so->id, gid); return -EFAULT; } if (pfq_join_group(gid, so->id, group.class_mask, group.policy) < 0) { printk(KERN_INFO "[PFQ|%d] join group error: permission denied (gid=%d)!\n", so->id, group.gid); return -EACCES; } } pr_devel("[PFQ|%d] join group: gid=%d class_mask=%lx policy=%d\n", so->id, group.gid, group.class_mask, group.policy); } break; case Q_SO_GET_ID: { int ver; if (len != sizeof(so->id)) return -EINVAL; if (copy_from_user(&ver, optval, sizeof(ver))) return -EFAULT; if (ver != PFQ_VERSION_CODE) { printk(KERN_INFO "[PFQ] version mismatch: kernel version %d.%d.%d, library version = %d.%d.%d!\n", PFQ_MAJOR(PFQ_VERSION_CODE), PFQ_MINOR(PFQ_VERSION_CODE), PFQ_PATCHLEVEL(PFQ_VERSION_CODE), PFQ_MAJOR(ver), PFQ_MINOR(ver), PFQ_PATCHLEVEL(ver)); return -EPERM; } if (copy_to_user(optval, &so->id, sizeof(so->id))) return -EFAULT; } break; case Q_SO_GET_STATUS: { int enabled; if (len != sizeof(int)) return -EINVAL; enabled = so->shmem.addr == NULL ? 0 : 1; if (copy_to_user(optval, &enabled, sizeof(enabled))) return -EFAULT; } break; case Q_SO_GET_STATS: { struct pfq_stats stat; if (len != sizeof(struct pfq_stats)) return -EINVAL; stat.recv = sparse_read(so->stats, recv); stat.lost = sparse_read(so->stats, lost); stat.drop = sparse_read(so->stats, drop); stat.frwd = 0; stat.kern = 0; stat.sent = sparse_read(so->stats, sent); stat.disc = sparse_read(so->stats, disc); if (copy_to_user(optval, &stat, sizeof(stat))) return -EFAULT; } break; case Q_SO_GET_RX_TSTAMP: { if (len != sizeof(so->opt.tstamp)) return -EINVAL; if (copy_to_user(optval, &so->opt.tstamp, sizeof(so->opt.tstamp))) return -EFAULT; } break; case Q_SO_GET_SHMEM_SIZE: { size_t size = pfq_shared_memory_size(so); if (len != sizeof(size)) return -EINVAL; if (copy_to_user(optval, &size, sizeof(size))) return -EFAULT; } break; case Q_SO_GET_RX_CAPLEN: { if (len != sizeof(so->opt.caplen)) return -EINVAL; if (copy_to_user(optval, &so->opt.caplen, sizeof(so->opt.caplen))) return -EFAULT; } break; case Q_SO_GET_TX_MAXLEN: { if (len != sizeof(xmit_slot_size)) return -EINVAL; if (copy_to_user(optval, &xmit_slot_size, sizeof(xmit_slot_size))) return -EFAULT; } break; case Q_SO_GET_RX_SLOTS: { if (len != sizeof(so->opt.rx_queue_len)) return -EINVAL; if (copy_to_user(optval, &so->opt.rx_queue_len, sizeof(so->opt.rx_queue_len))) return -EFAULT; } break; case Q_SO_GET_TX_SLOTS: { if (len != sizeof(so->opt.tx_queue_len)) return -EINVAL; if (copy_to_user(optval, &so->opt.tx_queue_len, sizeof(so->opt.tx_queue_len))) return -EFAULT; } break; case Q_SO_GET_GROUPS: { unsigned long grps; if(len != sizeof(unsigned long)) return -EINVAL; grps = pfq_get_groups(so->id); if (copy_to_user(optval, &grps, sizeof(grps))) return -EFAULT; } break; case Q_SO_GET_GROUP_STATS: { struct pfq_group *group; struct pfq_stats stat; pfq_gid_t gid; if (len != sizeof(stat)) return -EINVAL; if (copy_from_user(&stat, optval, sizeof(stat))) return -EFAULT; gid = (__force pfq_gid_t)stat.recv; group = pfq_get_group(gid); if (group == NULL) { printk(KERN_INFO "[PFQ|%d] group error: invalid group id %d!\n", so->id, gid); return -EFAULT; } if (pfq_group_is_free(gid)) { printk(KERN_INFO "[PFQ|%d] group stats error: gid=%d is a free group!\n", so->id, gid); return -EACCES; } if (!pfq_group_access(gid, so->id)) { printk(KERN_INFO "[PFQ|%d] group stats error: gid=%d permission denied!\n", so->id, gid); return -EACCES; } stat.recv = sparse_read(group->stats, recv); stat.drop = sparse_read(group->stats, drop); stat.frwd = sparse_read(group->stats, frwd); stat.kern = sparse_read(group->stats, kern); stat.lost = 0; stat.sent = 0; stat.disc = 0; if (copy_to_user(optval, &stat, sizeof(stat))) return -EFAULT; } break; case Q_SO_GET_GROUP_COUNTERS: { struct pfq_group *group; struct pfq_counters cs; pfq_gid_t gid; int i; if (len != sizeof(cs)) return -EINVAL; if (copy_from_user(&cs, optval, sizeof(cs))) return -EFAULT; gid = (__force pfq_gid_t)cs.counter[0]; group = pfq_get_group(gid); if (group == NULL) { printk(KERN_INFO "[PFQ|%d] group error: invalid group id %d!\n", so->id, gid); return -EFAULT; } /* check whether the group is joinable.. */ if (!pfq_group_policy_access(gid, so->id, Q_POLICY_GROUP_UNDEFINED)) { printk(KERN_INFO "[PFQ|%d] group error: permission denied (gid=%d)!\n", so->id, gid); return -EACCES; } for(i = 0; i < Q_MAX_COUNTERS; i++) { cs.counter[i] = sparse_read(group->counters, value[i]); } if (copy_to_user(optval, &cs, sizeof(cs))) return -EFAULT; } break; case Q_SO_GET_WEIGHT: { if (len != sizeof(so->weight)) return -EINVAL; if (copy_to_user(optval, &so->weight, sizeof(so->weight))) return -EFAULT; } break; default: return -EFAULT; } return 0; }