static int __pfq_join_group(int gid, int id, unsigned long class_mask, int policy) { struct pfq_group * g = pfq_get_group(gid); unsigned long tmp = 0; unsigned long bit; if (!g) { pr_devel("[PFQ] get_group: invalid group id %d!\n", gid); return -EINVAL; } /* if this group is unused, initializes it */ if (!g->pid) __pfq_group_init(gid); if (!__pfq_group_access(gid, id, policy, true)) { pr_devel("[PFQ] gid:%d is not joinable with policy %d\n", gid, policy); return -1; } pfq_bitwise_foreach(class_mask, bit, { int class = pfq_ctz(bit); tmp = atomic_long_read(&g->sock_mask[class]); tmp |= 1L << id; atomic_long_set(&g->sock_mask[class], tmp); }) if (g->owner == -1) {
static int __pfq_join_group(int gid, int id, unsigned long class_mask, int policy) { unsigned long tmp = 0; unsigned long bit; if (!pfq_groups[gid].pid) { __pfq_group_ctor(gid); } if (!__pfq_group_access(gid, id, policy, true)) { pr_devel("[PFQ] gid:%d is not joinable with policy %d\n", gid, policy); return -1; } pfq_bitwise_foreach(class_mask, bit) { int class = pfq_ctz(bit); tmp = atomic_long_read(&pfq_groups[gid].sock_mask[class]); tmp |= 1L << id; atomic_long_set(&pfq_groups[gid].sock_mask[class], tmp); }
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; }