Release 4.11 net/atm/common.c
/* net/atm/common.c - ATM sockets (common part for PVC and SVC) */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/net.h> /* struct socket, struct proto_ops */
#include <linux/atm.h> /* ATM stuff */
#include <linux/atmdev.h>
#include <linux/socket.h> /* SOL_SOCKET */
#include <linux/errno.h> /* error codes */
#include <linux/capability.h>
#include <linux/mm.h>
#include <linux/sched/signal.h>
#include <linux/time.h> /* struct timeval */
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <net/sock.h> /* struct sock */
#include <linux/uaccess.h>
#include <linux/poll.h>
#include <linux/atomic.h>
#include "resources.h" /* atm_find_dev */
#include "common.h" /* prototypes */
#include "protocols.h" /* atm_init_<transport> */
#include "addr.h" /* address registry */
#include "signaling.h" /* for WAITING and sigd_attach */
struct hlist_head vcc_hash[VCC_HTABLE_SIZE];
EXPORT_SYMBOL(vcc_hash);
DEFINE_RWLOCK(vcc_sklist_lock);
EXPORT_SYMBOL(vcc_sklist_lock);
static ATOMIC_NOTIFIER_HEAD(atm_dev_notify_chain);
static void __vcc_insert_socket(struct sock *sk)
{
struct atm_vcc *vcc = atm_sk(sk);
struct hlist_head *head = &vcc_hash[vcc->vci & (VCC_HTABLE_SIZE - 1)];
sk->sk_hash = vcc->vci & (VCC_HTABLE_SIZE - 1);
sk_add_node(sk, head);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 60 | 98.36% | 4 | 80.00% |
Eric Dumazet | 1 | 1.64% | 1 | 20.00% |
Total | 61 | 100.00% | 5 | 100.00% |
void vcc_insert_socket(struct sock *sk)
{
write_lock_irq(&vcc_sklist_lock);
__vcc_insert_socket(sk);
write_unlock_irq(&vcc_sklist_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 27 | 100.00% | 2 | 100.00% |
Total | 27 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(vcc_insert_socket);
static void vcc_remove_socket(struct sock *sk)
{
write_lock_irq(&vcc_sklist_lock);
sk_del_node_init(sk);
write_unlock_irq(&vcc_sklist_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 27 | 96.43% | 2 | 66.67% |
Christoph Hellwig | 1 | 3.57% | 1 | 33.33% |
Total | 28 | 100.00% | 3 | 100.00% |
static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size)
{
struct sk_buff *skb;
struct sock *sk = sk_atm(vcc);
if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
sk_wmem_alloc_get(sk), size, sk->sk_sndbuf);
return NULL;
}
while (!(skb = alloc_skb(size, GFP_KERNEL)))
schedule();
pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
atomic_add(skb->truesize, &sk->sk_wmem_alloc);
return skb;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 98 | 85.96% | 2 | 33.33% |
Arnaldo Carvalho de Melo | 10 | 8.77% | 1 | 16.67% |
Eric Dumazet | 3 | 2.63% | 1 | 16.67% |
Stephen Hemminger | 2 | 1.75% | 1 | 16.67% |
Joe Perches | 1 | 0.88% | 1 | 16.67% |
Total | 114 | 100.00% | 6 | 100.00% |
static void vcc_sock_destruct(struct sock *sk)
{
if (atomic_read(&sk->sk_rmem_alloc))
printk(KERN_DEBUG "%s: rmem leakage (%d bytes) detected.\n",
__func__, atomic_read(&sk->sk_rmem_alloc));
if (atomic_read(&sk->sk_wmem_alloc))
printk(KERN_DEBUG "%s: wmem leakage (%d bytes) detected.\n",
__func__, atomic_read(&sk->sk_wmem_alloc));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 57 | 90.48% | 2 | 66.67% |
Joe Perches | 6 | 9.52% | 1 | 33.33% |
Total | 63 | 100.00% | 3 | 100.00% |
static void vcc_def_wakeup(struct sock *sk)
{
struct socket_wq *wq;
rcu_read_lock();
wq = rcu_dereference(sk->sk_wq);
if (skwq_has_sleeper(wq))
wake_up(&wq->wait);
rcu_read_unlock();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 27 | 58.70% | 2 | 50.00% |
Eric Dumazet | 18 | 39.13% | 1 | 25.00% |
Herbert Xu | 1 | 2.17% | 1 | 25.00% |
Total | 46 | 100.00% | 4 | 100.00% |
static inline int vcc_writable(struct sock *sk)
{
struct atm_vcc *vcc = atm_sk(sk);
return (vcc->qos.txtp.max_sdu +
atomic_read(&sk->sk_wmem_alloc)) <= sk->sk_sndbuf;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 40 | 88.89% | 2 | 66.67% |
Linus Torvalds | 5 | 11.11% | 1 | 33.33% |
Total | 45 | 100.00% | 3 | 100.00% |
static void vcc_write_space(struct sock *sk)
{
struct socket_wq *wq;
rcu_read_lock();
if (vcc_writable(sk)) {
wq = rcu_dereference(sk->sk_wq);
if (skwq_has_sleeper(wq))
wake_up_interruptible(&wq->wait);
sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
}
rcu_read_unlock();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 37 | 57.81% | 4 | 50.00% |
Eric Dumazet | 23 | 35.94% | 1 | 12.50% |
Linus Torvalds | 2 | 3.12% | 1 | 12.50% |
Pavel Emelyanov | 1 | 1.56% | 1 | 12.50% |
Herbert Xu | 1 | 1.56% | 1 | 12.50% |
Total | 64 | 100.00% | 8 | 100.00% |
static void vcc_release_cb(struct sock *sk)
{
struct atm_vcc *vcc = atm_sk(sk);
if (vcc->release_cb)
vcc->release_cb(vcc);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David Woodhouse | 34 | 100.00% | 1 | 100.00% |
Total | 34 | 100.00% | 1 | 100.00% |
static struct proto vcc_proto = {
.name = "VCC",
.owner = THIS_MODULE,
.obj_size = sizeof(struct atm_vcc),
.release_cb = vcc_release_cb,
};
int vcc_create(struct net *net, struct socket *sock, int protocol, int family, int kern)
{
struct sock *sk;
struct atm_vcc *vcc;
sock->sk = NULL;
if (sock->type == SOCK_STREAM)
return -EINVAL;
sk = sk_alloc(net, family, GFP_KERNEL, &vcc_proto, kern);
if (!sk)
return -ENOMEM;
sock_init_data(sock, sk);
sk->sk_state_change = vcc_def_wakeup;
sk->sk_write_space = vcc_write_space;
vcc = atm_sk(sk);
vcc->dev = NULL;
memset(&vcc->local, 0, sizeof(struct sockaddr_atmsvc));
memset(&vcc->remote, 0, sizeof(struct sockaddr_atmsvc));
vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
atomic_set(&sk->sk_wmem_alloc, 1);
atomic_set(&sk->sk_rmem_alloc, 0);
vcc->push = NULL;
vcc->pop = NULL;
vcc->owner = NULL;
vcc->push_oam = NULL;
vcc->release_cb = NULL;
vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */
vcc->atm_options = vcc->aal_options = 0;
sk->sk_destruct = vcc_sock_destruct;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 183 | 78.21% | 6 | 40.00% |
Linus Torvalds (pre-git) | 23 | 9.83% | 2 | 13.33% |
Eric W. Biedermann | 12 | 5.13% | 2 | 13.33% |
David Woodhouse | 6 | 2.56% | 1 | 6.67% |
Krzysztof Mazur | 6 | 2.56% | 1 | 6.67% |
Arnaldo Carvalho de Melo | 3 | 1.28% | 2 | 13.33% |
Eric Dumazet | 1 | 0.43% | 1 | 6.67% |
Total | 234 | 100.00% | 15 | 100.00% |
static void vcc_destroy_socket(struct sock *sk)
{
struct atm_vcc *vcc = atm_sk(sk);
struct sk_buff *skb;
set_bit(ATM_VF_CLOSE, &vcc->flags);
clear_bit(ATM_VF_READY, &vcc->flags);
if (vcc->dev) {
if (vcc->dev->ops->close)
vcc->dev->ops->close(vcc);
if (vcc->push)
vcc->push(vcc, NULL); /* atmarpd has no push */
module_put(vcc->owner);
while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
atm_return(vcc, skb->truesize);
kfree_skb(skb);
}
module_put(vcc->dev->ops->owner);
atm_dev_put(vcc->dev);
}
vcc_remove_socket(sk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 92 | 60.13% | 6 | 66.67% |
Linus Torvalds (pre-git) | 54 | 35.29% | 2 | 22.22% |
Krzysztof Mazur | 7 | 4.58% | 1 | 11.11% |
Total | 153 | 100.00% | 9 | 100.00% |
int vcc_release(struct socket *sock)
{
struct sock *sk = sock->sk;
if (sk) {
lock_sock(sk);
vcc_destroy_socket(sock->sk);
release_sock(sk);
sock_put(sk);
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 42 | 84.00% | 2 | 66.67% |
Linus Torvalds (pre-git) | 8 | 16.00% | 1 | 33.33% |
Total | 50 | 100.00% | 3 | 100.00% |
void vcc_release_async(struct atm_vcc *vcc, int reply)
{
struct sock *sk = sk_atm(vcc);
set_bit(ATM_VF_CLOSE, &vcc->flags);
sk->sk_shutdown |= RCV_SHUTDOWN;
sk->sk_err = -reply;
clear_bit(ATM_VF_WAITING, &vcc->flags);
sk->sk_state_change(sk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 53 | 84.13% | 2 | 66.67% |
Arnaldo Carvalho de Melo | 10 | 15.87% | 1 | 33.33% |
Total | 63 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(vcc_release_async);
void vcc_process_recv_queue(struct atm_vcc *vcc)
{
struct sk_buff_head queue, *rq;
struct sk_buff *skb, *tmp;
unsigned long flags;
__skb_queue_head_init(&queue);
rq = &sk_atm(vcc)->sk_receive_queue;
spin_lock_irqsave(&rq->lock, flags);
skb_queue_splice_init(rq, &queue);
spin_unlock_irqrestore(&rq->lock, flags);
skb_queue_walk_safe(&queue, skb, tmp) {
__skb_unlink(skb, &queue);
vcc->push(vcc, skb);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jorge Boncompte | 100 | 100.00% | 1 | 100.00% |
Total | 100 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(vcc_process_recv_queue);
void atm_dev_signal_change(struct atm_dev *dev, char signal)
{
pr_debug("%s signal=%d dev=%p number=%d dev->signal=%d\n",
__func__, signal, dev, dev->number, dev->signal);
/* atm driver sending invalid signal */
WARN_ON(signal < ATM_PHY_SIG_LOST || signal > ATM_PHY_SIG_FOUND);
if (dev->signal == signal)
return; /* no change */
dev->signal = signal;
atomic_notifier_call_chain(&atm_dev_notify_chain, signal, dev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Karl Hiramoto | 70 | 100.00% | 1 | 100.00% |
Total | 70 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(atm_dev_signal_change);
void atm_dev_release_vccs(struct atm_dev *dev)
{
int i;
write_lock_irq(&vcc_sklist_lock);
for (i = 0; i < VCC_HTABLE_SIZE; i++) {
struct hlist_head *head = &vcc_hash[i];
struct hlist_node *tmp;
struct sock *s;
struct atm_vcc *vcc;
sk_for_each_safe(s, tmp, head) {
vcc = atm_sk(s);
if (vcc->dev == dev) {
vcc_release_async(vcc, -EPIPE);
sk_del_node_init(s);
}
}
}
write_unlock_irq(&vcc_sklist_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Stanislaw W. Gruszka | 106 | 100.00% | 1 | 100.00% |
Total | 106 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(atm_dev_release_vccs);
static int adjust_tp(struct atm_trafprm *tp, unsigned char aal)
{
int max_sdu;
if (!tp->traffic_class)
return 0;
switch (aal) {
case ATM_AAL0:
max_sdu = ATM_CELL_SIZE-1;
break;
case ATM_AAL34:
max_sdu = ATM_MAX_AAL34_PDU;
break;
default:
pr_warn("AAL problems ... (%d)\n", aal);
/* fall through */
case ATM_AAL5:
max_sdu = ATM_MAX_AAL5_PDU;
}
if (!tp->max_sdu)
tp->max_sdu = max_sdu;
else if (tp->max_sdu > max_sdu)
return -EINVAL;
if (!tp->max_cdv)
tp->max_cdv = ATM_MAX_CDV;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 86 | 78.18% | 2 | 40.00% |
Linus Torvalds (pre-git) | 22 | 20.00% | 1 | 20.00% |
Joe Perches | 2 | 1.82% | 2 | 40.00% |
Total | 110 | 100.00% | 5 | 100.00% |
static int check_ci(const struct atm_vcc *vcc, short vpi, int vci)
{
struct hlist_head *head = &vcc_hash[vci & (VCC_HTABLE_SIZE - 1)];
struct sock *s;
struct atm_vcc *walk;
sk_for_each(s, head) {
walk = atm_sk(s);
if (walk->dev != vcc->dev)
continue;
if (test_bit(ATM_VF_ADDR, &walk->flags) && walk->vpi == vpi &&
walk->vci == vci && ((walk->qos.txtp.traffic_class !=
ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
(walk->qos.rxtp.traffic_class != ATM_NONE &&
vcc->qos.rxtp.traffic_class != ATM_NONE)))
return -EADDRINUSE;
}
/* allow VCCs with same VPI/VCI iff they don't collide on
TX/RX (but we may refuse such sharing for other reasons,
e.g. if protocol requires to have both channels) */
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 148 | 99.33% | 2 | 66.67% |
Mitchell Blank Jr. | 1 | 0.67% | 1 | 33.33% |
Total | 149 | 100.00% | 3 | 100.00% |
static int find_ci(const struct atm_vcc *vcc, short *vpi, int *vci)
{
static short p; /* poor man's per-device cache */
static int c;
short old_p;
int old_c;
int err;
if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
err = check_ci(vcc, *vpi, *vci);
return err;
}
/* last scan may have left values out of bounds for current device */
if (*vpi != ATM_VPI_ANY)
p = *vpi;
else if (p >= 1 << vcc->dev->ci_range.vpi_bits)
p = 0;
if (*vci != ATM_VCI_ANY)
c = *vci;
else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits)
c = ATM_NOT_RSV_VCI;
old_p = p;
old_c = c;
do {
if (!check_ci(vcc, p, c)) {
*vpi = p;
*vci = c;
return 0;
}
if (*vci == ATM_VCI_ANY) {
c++;
if (c >= 1 << vcc->dev->ci_range.vci_bits)
c = ATM_NOT_RSV_VCI;
}
if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) &&
*vpi == ATM_VPI_ANY) {
p++;
if (p >= 1 << vcc->dev->ci_range.vpi_bits)
p = 0;
}
} while (old_p != p || old_c != c);
return -EADDRINUSE;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 258 | 99.61% | 1 | 50.00% |
Mitchell Blank Jr. | 1 | 0.39% | 1 | 50.00% |
Total | 259 | 100.00% | 2 | 100.00% |
static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
int vci)
{
struct sock *sk = sk_atm(vcc);
int error;
if ((vpi != ATM_VPI_UNSPEC && vpi != ATM_VPI_ANY &&
vpi >> dev->ci_range.vpi_bits) || (vci != ATM_VCI_UNSPEC &&
vci != ATM_VCI_ANY && vci >> dev->ci_range.vci_bits))
return -EINVAL;
if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
return -EPERM;
error = -ENODEV;
if (!try_module_get(dev->ops->owner))
return error;
vcc->dev = dev;
write_lock_irq(&vcc_sklist_lock);
if (test_bit(ATM_DF_REMOVED, &dev->flags) ||
(error = find_ci(vcc, &vpi, &vci))) {
write_unlock_irq(&vcc_sklist_lock);
goto fail_module_put;
}
vcc->vpi = vpi;
vcc->vci = vci;
__vcc_insert_socket(sk);
write_unlock_irq(&vcc_sklist_lock);
switch (vcc->qos.aal) {
case ATM_AAL0:
error = atm_init_aal0(vcc);
vcc->stats = &dev->stats.aal0;
break;
case ATM_AAL34:
error = atm_init_aal34(vcc);
vcc->stats = &dev->stats.aal34;
break;
case ATM_NO_AAL:
/* ATM_AAL5 is also used in the "0 for default" case */
vcc->qos.aal = ATM_AAL5;
/* fall through */
case ATM_AAL5:
error = atm_init_aal5(vcc);
vcc->stats = &dev->stats.aal5;
break;
default:
error = -EPROTOTYPE;
}
if (!error)
error = adjust_tp(&vcc->qos.txtp, vcc->qos.aal);
if (!error)
error = adjust_tp(&vcc->qos.rxtp, vcc->qos.aal);
if (error)
goto fail;
pr_debug("VCC %d.%d, AAL %d\n", vpi, vci, vcc->qos.aal);
pr_debug(" TX: %d, PCR %d..%d, SDU %d\n",
vcc->qos.txtp.traffic_class,
vcc->qos.txtp.min_pcr,
vcc->qos.txtp.max_pcr,
vcc->qos.txtp.max_sdu);
pr_debug(" RX: %d, PCR %d..%d, SDU %d\n",
vcc->qos.rxtp.traffic_class,
vcc->qos.rxtp.min_pcr,
vcc->qos.rxtp.max_pcr,
vcc->qos.rxtp.max_sdu);
if (dev->ops->open) {
error = dev->ops->open(vcc);
if (error)
goto fail;
}
return 0;
fail:
vcc_remove_socket(sk);
fail_module_put:
module_put(dev->ops->owner);
/* ensure we get dev module ref count correct */
vcc->dev = NULL;
return error;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 366 | 75.31% | 6 | 42.86% |
Linus Torvalds (pre-git) | 90 | 18.52% | 4 | 28.57% |
Stanislaw W. Gruszka | 13 | 2.67% | 1 | 7.14% |
Arnaldo Carvalho de Melo | 10 | 2.06% | 1 | 7.14% |
Joe Perches | 4 | 0.82% | 1 | 7.14% |
Stephen Hemminger | 3 | 0.62% | 1 | 7.14% |
Total | 486 | 100.00% | 14 | 100.00% |
int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
{
struct atm_dev *dev;
struct atm_vcc *vcc = ATM_SD(sock);
int error;
pr_debug("(vpi %d, vci %d)\n", vpi, vci);
if (sock->state == SS_CONNECTED)
return -EISCONN;
if (sock->state != SS_UNCONNECTED)
return -EINVAL;
if (!(vpi || vci))
return -EINVAL;
if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC)
clear_bit(ATM_VF_PARTIAL, &vcc->flags);
else
if (test_bit(ATM_VF_PARTIAL, &vcc->flags))
return -EINVAL;
pr_debug("(TX: cl %d,bw %d-%d,sdu %d; "
"RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
vcc->qos.txtp.traffic_class, vcc->qos.txtp.min_pcr,
vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_sdu,
vcc->qos.rxtp.traffic_class, vcc->qos.rxtp.min_pcr,
vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_sdu,
vcc->qos.aal == ATM_AAL5 ? "" :
vcc->qos.aal == ATM_AAL0 ? "" : " ??? code ",
vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
if (!test_bit(ATM_VF_HASQOS, &vcc->flags))
return -EBADFD;
if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
return -EINVAL;
if (likely(itf != ATM_ITF_ANY)) {
dev = try_then_request_module(atm_dev_lookup(itf),
"atm-device-%d", itf);
} else {
dev = NULL;
mutex_lock(&atm_dev_mutex);
if (!list_empty(&atm_devs)) {
dev = list_entry(atm_devs.next,
struct atm_dev, dev_list);
atm_dev_hold(dev);
}
mutex_unlock(&atm_dev_mutex);
}
if (!dev)
return -ENODEV;
error = __vcc_connect(vcc, dev, vpi, vci);
if (error) {
atm_dev_put(dev);
return error;
}
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
set_bit(ATM_VF_PARTIAL, &vcc->flags);
if (test_bit(ATM_VF_READY, &ATM_SD(sock)->flags))
sock->state = SS_CONNECTED;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 298 | 70.12% | 4 | 28.57% |
Linus Torvalds (pre-git) | 83 | 19.53% | 4 | 28.57% |
Mitchell Blank Jr. | 36 | 8.47% | 2 | 14.29% |
Ingo Molnar | 2 | 0.47% | 1 | 7.14% |
Joe Perches | 2 | 0.47% | 1 | 7.14% |
Stanislaw W. Gruszka | 2 | 0.47% | 1 | 7.14% |
Stephen Hemminger | 2 | 0.47% | 1 | 7.14% |
Total | 425 | 100.00% | 14 | 100.00% |
int vcc_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
int flags)
{
struct sock *sk = sock->sk;
struct atm_vcc *vcc;
struct sk_buff *skb;
int copied, error = -EINVAL;
if (sock->state != SS_CONNECTED)
return -ENOTCONN;
/* only handle MSG_DONTWAIT and MSG_PEEK */
if (flags & ~(MSG_DONTWAIT | MSG_PEEK))
return -EOPNOTSUPP;
vcc = ATM_SD(sock);
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
test_bit(ATM_VF_CLOSE, &vcc->flags) ||
!test_bit(ATM_VF_READY, &vcc->flags))
return 0;
skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &error);
if (!skb)
return error;
copied = skb->len;
if (copied > size) {
copied = size;
msg->msg_flags |= MSG_TRUNC;
}
error = skb_copy_datagram_msg(skb, 0, msg, copied);
if (error)
return error;
sock_recv_ts_and_drops(msg, sk, skb);
if (!(flags & MSG_PEEK)) {
pr_debug("%d -= %d\n", atomic_read(&sk->sk_rmem_alloc),
skb->truesize);
atm_return(vcc, skb->truesize);
}
skb_free_datagram(sk, skb);
return copied;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 191 | 78.60% | 5 | 38.46% |
Linus Torvalds (pre-git) | 30 | 12.35% | 2 | 15.38% |
Jorge Boncompte | 16 | 6.58% | 1 | 7.69% |
Stephen Hemminger | 3 | 1.23% | 2 | 15.38% |
Neil Horman | 1 | 0.41% | 1 | 7.69% |
Joe Perches | 1 | 0.41% | 1 | 7.69% |
David S. Miller | 1 | 0.41% | 1 | 7.69% |
Total | 243 | 100.00% | 13 | 100.00% |
int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
{
struct sock *sk = sock->sk;
DEFINE_WAIT(wait);
struct atm_vcc *vcc;
struct sk_buff *skb;
int eff, error;
lock_sock(sk);
if (sock->state != SS_CONNECTED) {
error = -ENOTCONN;
goto out;
}
if (m->msg_name) {
error = -EISCONN;
goto out;
}
vcc = ATM_SD(sock);
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
test_bit(ATM_VF_CLOSE, &vcc->flags) ||
!test_bit(ATM_VF_READY, &vcc->flags)) {
error = -EPIPE;
send_sig(SIGPIPE, current, 0);
goto out;
}
if (!size) {
error = 0;
goto out;
}
if (size > vcc->qos.txtp.max_sdu) {
error = -EMSGSIZE;
goto out;
}
eff = (size+3) & ~3; /* align to word boundary */
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
error = 0;
while (!(skb = alloc_tx(vcc, eff))) {
if (m->msg_flags & MSG_DONTWAIT) {
error = -EAGAIN;
break;
}
schedule();
if (signal_pending(current)) {
error = -ERESTARTSYS;
break;
}
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
test_bit(ATM_VF_CLOSE, &vcc->flags) ||
!test_bit(ATM_VF_READY, &vcc->flags)) {
error = -EPIPE;
send_sig(SIGPIPE, current, 0);
break;
}
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
}
finish_wait(sk_sleep(sk), &wait);
if (error)
goto out;
skb->dev = NULL; /* for paths shared with net_device interfaces */
ATM_SKB(skb)->atm_options = vcc->atm_options;
if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) {
kfree_skb(skb);
error = -EFAULT;
goto out;
}
if (eff != size)
memset(skb->data + size, 0, eff-size);
error = vcc->dev->ops->send(vcc, skb);
error = error ? error : size;
out:
release_sock(sk);
return error;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 331 | 73.88% | 5 | 41.67% |
Linus Torvalds (pre-git) | 99 | 22.10% | 2 | 16.67% |
Eric Dumazet | 9 | 2.01% | 1 | 8.33% |
Al Viro | 8 | 1.79% | 3 | 25.00% |
Stephen Hemminger | 1 | 0.22% | 1 | 8.33% |
Total | 448 | 100.00% | 12 | 100.00% |
unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
{
struct sock *sk = sock->sk;
struct atm_vcc *vcc;
unsigned int mask;
sock_poll_wait(file, sk_sleep(sk), wait);
mask = 0;
vcc = ATM_SD(sock);
/* exceptional events */
if (sk->sk_err)
mask = POLLERR;
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
test_bit(ATM_VF_CLOSE, &vcc->flags))
mask |= POLLHUP;
/* readable? */
if (!skb_queue_empty(&sk->sk_receive_queue))
mask |= POLLIN | POLLRDNORM;
/* writable? */
if (sock->state == SS_CONNECTING &&
test_bit(ATM_VF_WAITING, &vcc->flags))
return mask;
if (vcc->qos.txtp.traffic_class != ATM_NONE &&
vcc_writable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
return mask;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 148 | 89.16% | 4 | 44.44% |
Linus Torvalds | 8 | 4.82% | 1 | 11.11% |
Linus Torvalds (pre-git) | 6 | 3.61% | 2 | 22.22% |
Eric Dumazet | 3 | 1.81% | 1 | 11.11% |
Jiri Olsa | 1 | 0.60% | 1 | 11.11% |
Total | 166 | 100.00% | 9 | 100.00% |
static int atm_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
{
int error;
/*
* Don't let the QoS change the already connected AAL type nor the
* traffic class.
*/
if (qos->aal != vcc->qos.aal ||
qos->rxtp.traffic_class != vcc->qos.rxtp.traffic_class ||
qos->txtp.traffic_class != vcc->qos.txtp.traffic_class)
return -EINVAL;
error = adjust_tp(&qos->txtp, qos->aal);
if (!error)
error = adjust_tp(&qos->rxtp, qos->aal);
if (error)
return error;
if (!vcc->dev->ops->change_qos)
return -EOPNOTSUPP;
if (sk_atm(vcc)->sk_family == AF_ATMPVC)
return vcc->dev->ops->change_qos(vcc, qos, ATM_MF_SET);
return svc_change_qos(vcc, qos);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 149 | 96.75% | 3 | 50.00% |
Arnaldo Carvalho de Melo | 4 | 2.60% | 2 | 33.33% |
Chas Williams | 1 | 0.65% | 1 | 16.67% |
Total | 154 | 100.00% | 6 | 100.00% |
static int check_tp(const struct atm_trafprm *tp)
{
/* @@@ Should be merged with adjust_tp */
if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS)
return 0;
if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->pcr &&
!tp->max_pcr)
return -EINVAL;
if (tp->min_pcr == ATM_MAX_PCR)
return -EINVAL;
if (tp->min_pcr && tp->max_pcr && tp->max_pcr != ATM_MAX_PCR &&
tp->min_pcr > tp->max_pcr)
return -EINVAL;
/*
* We allow pcr to be outside [min_pcr,max_pcr], because later
* adjustment may still push it in the valid range.
*/
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 99 | 99.00% | 1 | 50.00% |
Mitchell Blank Jr. | 1 | 1.00% | 1 | 50.00% |
Total | 100 | 100.00% | 2 | 100.00% |
static int check_qos(const struct atm_qos *qos)
{
int error;
if (!qos->txtp.traffic_class && !qos->rxtp.traffic_class)
return -EINVAL;
if (qos->txtp.traffic_class != qos->rxtp.traffic_class &&
qos->txtp.traffic_class && qos->rxtp.traffic_class &&
qos->txtp.traffic_class != ATM_ANYCLASS &&
qos->rxtp.traffic_class != ATM_ANYCLASS)
return -EINVAL;
error = check_tp(&qos->txtp);
if (error)
return error;
return check_tp(&qos->rxtp);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 106 | 99.07% | 1 | 50.00% |
Mitchell Blank Jr. | 1 | 0.93% | 1 | 50.00% |
Total | 107 | 100.00% | 2 | 100.00% |
int vcc_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen)
{
struct atm_vcc *vcc;
unsigned long value;
int error;
if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
return -EINVAL;
vcc = ATM_SD(sock);
switch (optname) {
case SO_ATMQOS:
{
struct atm_qos qos;
if (copy_from_user(&qos, optval, sizeof(qos)))
return -EFAULT;
error = check_qos(&qos);
if (error)
return error;
if (sock->state == SS_CONNECTED)
return atm_change_qos(vcc, &qos);
if (sock->state != SS_UNCONNECTED)
return -EBADFD;
vcc->qos = qos;
set_bit(ATM_VF_HASQOS, &vcc->flags);
return 0;
}
case SO_SETCLP:
if (get_user(value, (unsigned long __user *)optval))
return -EFAULT;
if (value)
vcc->atm_options |= ATM_ATMOPT_CLP;
else
vcc->atm_options &= ~ATM_ATMOPT_CLP;
return 0;
default:
if (level == SOL_SOCKET)
return -EINVAL;
break;
}
if (!vcc->dev || !vcc->dev->ops->setsockopt)
return -EINVAL;
return vcc->dev->ops->setsockopt(vcc, level, optname, optval, optlen);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 231 | 90.23% | 2 | 40.00% |
Chas Williams | 22 | 8.59% | 1 | 20.00% |
Al Viro | 2 | 0.78% | 1 | 20.00% |
David S. Miller | 1 | 0.39% | 1 | 20.00% |
Total | 256 | 100.00% | 5 | 100.00% |
int vcc_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
struct atm_vcc *vcc;
int len;
if (get_user(len, optlen))
return -EFAULT;
if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname))
return -EINVAL;
vcc = ATM_SD(sock);
switch (optname) {
case SO_ATMQOS:
if (!test_bit(ATM_VF_HASQOS, &vcc->flags))
return -EINVAL;
return copy_to_user(optval, &vcc->qos, sizeof(vcc->qos))
? -EFAULT : 0;
case SO_SETCLP:
return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 : 0,
(unsigned long __user *)optval) ? -EFAULT : 0;
case SO_ATMPVC:
{
struct sockaddr_atmpvc pvc;
if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags))
return -ENOTCONN;
memset(&pvc, 0, sizeof(pvc));
pvc.sap_family = AF_ATMPVC;
pvc.sap_addr.itf = vcc->dev->number;
pvc.sap_addr.vpi = vcc->vpi;
pvc.sap_addr.vci = vcc->vci;
return copy_to_user(optval, &pvc, sizeof(pvc)) ? -EFAULT : 0;
}
default:
if (level == SOL_SOCKET)
return -EINVAL;
break;
}
if (!vcc->dev || !vcc->dev->ops->getsockopt)
return -EINVAL;
return vcc->dev->ops->getsockopt(vcc, level, optname, optval, len);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 251 | 82.03% | 3 | 50.00% |
Chas Williams | 39 | 12.75% | 1 | 16.67% |
Mathias Krause | 13 | 4.25% | 1 | 16.67% |
Al Viro | 3 | 0.98% | 1 | 16.67% |
Total | 306 | 100.00% | 6 | 100.00% |
int register_atmdevice_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&atm_dev_notify_chain, nb);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Karl Hiramoto | 19 | 100.00% | 1 | 100.00% |
Total | 19 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(register_atmdevice_notifier);
void unregister_atmdevice_notifier(struct notifier_block *nb)
{
atomic_notifier_chain_unregister(&atm_dev_notify_chain, nb);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Karl Hiramoto | 18 | 100.00% | 1 | 100.00% |
Total | 18 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(unregister_atmdevice_notifier);
static int __init atm_init(void)
{
int error;
error = proto_register(&vcc_proto, 0);
if (error < 0)
goto out;
error = atmpvc_init();
if (error < 0) {
pr_err("atmpvc_init() failed with %d\n", error);
goto out_unregister_vcc_proto;
}
error = atmsvc_init();
if (error < 0) {
pr_err("atmsvc_init() failed with %d\n", error);
goto out_atmpvc_exit;
}
error = atm_proc_init();
if (error < 0) {
pr_err("atm_proc_init() failed with %d\n", error);
goto out_atmsvc_exit;
}
error = atm_sysfs_init();
if (error < 0) {
pr_err("atm_sysfs_init() failed with %d\n", error);
goto out_atmproc_exit;
}
out:
return error;
out_atmproc_exit:
atm_proc_exit();
out_atmsvc_exit:
atmsvc_exit();
out_atmpvc_exit:
atmsvc_exit();
out_unregister_vcc_proto:
proto_unregister(&vcc_proto);
goto out;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 71 | 46.10% | 1 | 20.00% |
Arnaldo Carvalho de Melo | 36 | 23.38% | 1 | 20.00% |
Joe Perches | 24 | 15.58% | 2 | 40.00% |
Roman Kagan | 23 | 14.94% | 1 | 20.00% |
Total | 154 | 100.00% | 5 | 100.00% |
static void __exit atm_exit(void)
{
atm_proc_exit();
atm_sysfs_exit();
atmsvc_exit();
atmpvc_exit();
proto_unregister(&vcc_proto);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 18 | 66.67% | 1 | 33.33% |
Arnaldo Carvalho de Melo | 6 | 22.22% | 1 | 33.33% |
Roman Kagan | 3 | 11.11% | 1 | 33.33% |
Total | 27 | 100.00% | 3 | 100.00% |
subsys_initcall(atm_init);
module_exit(atm_exit);
MODULE_LICENSE("GPL");
MODULE_ALIAS_NETPROTO(PF_ATMPVC);
MODULE_ALIAS_NETPROTO(PF_ATMSVC);
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chas Williams | 2756 | 56.29% | 20 | 26.32% |
Linus Torvalds (pre-git) | 1314 | 26.84% | 7 | 9.21% |
Karl Hiramoto | 128 | 2.61% | 1 | 1.32% |
Jorge Boncompte | 121 | 2.47% | 2 | 2.63% |
Stanislaw W. Gruszka | 121 | 2.47% | 2 | 2.63% |
Arnaldo Carvalho de Melo | 106 | 2.17% | 4 | 5.26% |
Joe Perches | 64 | 1.31% | 3 | 3.95% |
Eric Dumazet | 58 | 1.18% | 4 | 5.26% |
David Woodhouse | 45 | 0.92% | 1 | 1.32% |
Mitchell Blank Jr. | 40 | 0.82% | 3 | 3.95% |
Roman Kagan | 26 | 0.53% | 1 | 1.32% |
Linus Torvalds | 17 | 0.35% | 2 | 2.63% |
Al Viro | 13 | 0.27% | 4 | 5.26% |
Mathias Krause | 13 | 0.27% | 1 | 1.32% |
Krzysztof Mazur | 13 | 0.27% | 1 | 1.32% |
Eric W. Biedermann | 12 | 0.25% | 2 | 2.63% |
Stephen Hemminger | 11 | 0.22% | 2 | 2.63% |
Rusty Russell | 10 | 0.20% | 1 | 1.32% |
David S. Miller | 5 | 0.10% | 3 | 3.95% |
Philip A. Prindeville | 5 | 0.10% | 1 | 1.32% |
Thomas Gleixner | 4 | 0.08% | 1 | 1.32% |
Ingo Molnar | 3 | 0.06% | 2 | 2.63% |
Tejun Heo | 3 | 0.06% | 1 | 1.32% |
Herbert Xu | 2 | 0.04% | 1 | 1.32% |
Pavel Emelyanov | 1 | 0.02% | 1 | 1.32% |
Arun Sharma | 1 | 0.02% | 1 | 1.32% |
Christoph Hellwig | 1 | 0.02% | 1 | 1.32% |
Jiri Olsa | 1 | 0.02% | 1 | 1.32% |
Neil Horman | 1 | 0.02% | 1 | 1.32% |
Daniel Walker | 1 | 0.02% | 1 | 1.32% |
Total | 4896 | 100.00% | 76 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.