Commit b9bf3d83 authored by David S. Miller's avatar David S. Miller

Merge bk://kernel.bkbits.net/acme/net-2.5

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents ac59d5f3 3c81501f
VERSION = 2 VERSION = 2
PATCHLEVEL = 5 PATCHLEVEL = 5
SUBLEVEL = 71 SUBLEVEL = 72
EXTRAVERSION = EXTRAVERSION =
# *DOCUMENTATION* # *DOCUMENTATION*
......
...@@ -153,9 +153,9 @@ static void atmtcp_v_close(struct atm_vcc *vcc) ...@@ -153,9 +153,9 @@ static void atmtcp_v_close(struct atm_vcc *vcc)
static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
{ {
unsigned long flags;
struct atm_cirange ci; struct atm_cirange ci;
struct atm_vcc *vcc; struct atm_vcc *vcc;
struct sock *s;
if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD; if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD;
if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT; if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT;
...@@ -163,14 +163,18 @@ static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) ...@@ -163,14 +163,18 @@ static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS; if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS;
if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 || if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 ||
ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL; ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL;
spin_lock_irqsave(&dev->lock, flags); read_lock(&vcc_sklist_lock);
for (vcc = dev->vccs; vcc; vcc = vcc->next) for (s = vcc_sklist; s; s = s->sk_next) {
vcc = atm_sk(s);
if (vcc->dev != dev)
continue;
if ((vcc->vpi >> ci.vpi_bits) || if ((vcc->vpi >> ci.vpi_bits) ||
(vcc->vci >> ci.vci_bits)) { (vcc->vci >> ci.vci_bits)) {
spin_unlock_irqrestore(&dev->lock, flags); read_unlock(&vcc_sklist_lock);
return -EBUSY; return -EBUSY;
} }
spin_unlock_irqrestore(&dev->lock, flags); }
read_unlock(&vcc_sklist_lock);
dev->ci_range = ci; dev->ci_range = ci;
return 0; return 0;
} }
...@@ -233,9 +237,9 @@ static int atmtcp_v_proc(struct atm_dev *dev,loff_t *pos,char *page) ...@@ -233,9 +237,9 @@ static int atmtcp_v_proc(struct atm_dev *dev,loff_t *pos,char *page)
static void atmtcp_c_close(struct atm_vcc *vcc) static void atmtcp_c_close(struct atm_vcc *vcc)
{ {
unsigned long flags;
struct atm_dev *atmtcp_dev; struct atm_dev *atmtcp_dev;
struct atmtcp_dev_data *dev_data; struct atmtcp_dev_data *dev_data;
struct sock *s;
struct atm_vcc *walk; struct atm_vcc *walk;
atmtcp_dev = (struct atm_dev *) vcc->dev_data; atmtcp_dev = (struct atm_dev *) vcc->dev_data;
...@@ -246,19 +250,23 @@ static void atmtcp_c_close(struct atm_vcc *vcc) ...@@ -246,19 +250,23 @@ static void atmtcp_c_close(struct atm_vcc *vcc)
kfree(dev_data); kfree(dev_data);
shutdown_atm_dev(atmtcp_dev); shutdown_atm_dev(atmtcp_dev);
vcc->dev_data = NULL; vcc->dev_data = NULL;
spin_lock_irqsave(&atmtcp_dev->lock, flags); read_lock(&vcc_sklist_lock);
for (walk = atmtcp_dev->vccs; walk; walk = walk->next) for (s = vcc_sklist; s; s = s->sk_next) {
walk = atm_sk(s);
if (walk->dev != atmtcp_dev)
continue;
wake_up(&walk->sleep); wake_up(&walk->sleep);
spin_unlock_irqrestore(&atmtcp_dev->lock, flags); }
read_unlock(&vcc_sklist_lock);
} }
static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
{ {
unsigned long flags;
struct atm_dev *dev; struct atm_dev *dev;
struct atmtcp_hdr *hdr; struct atmtcp_hdr *hdr;
struct atm_vcc *out_vcc; struct sock *s;
struct atm_vcc *out_vcc = NULL;
struct sk_buff *new_skb; struct sk_buff *new_skb;
int result = 0; int result = 0;
...@@ -270,13 +278,17 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) ...@@ -270,13 +278,17 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
(struct atmtcp_control *) skb->data); (struct atmtcp_control *) skb->data);
goto done; goto done;
} }
spin_lock_irqsave(&dev->lock, flags); read_lock(&vcc_sklist_lock);
for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next) for (s = vcc_sklist; s; s = s->sk_next) {
out_vcc = atm_sk(s);
if (out_vcc->dev != dev)
continue;
if (out_vcc->vpi == ntohs(hdr->vpi) && if (out_vcc->vpi == ntohs(hdr->vpi) &&
out_vcc->vci == ntohs(hdr->vci) && out_vcc->vci == ntohs(hdr->vci) &&
out_vcc->qos.rxtp.traffic_class != ATM_NONE) out_vcc->qos.rxtp.traffic_class != ATM_NONE)
break; break;
spin_unlock_irqrestore(&dev->lock, flags); }
read_unlock(&vcc_sklist_lock);
if (!out_vcc) { if (!out_vcc) {
atomic_inc(&vcc->stats->tx_err); atomic_inc(&vcc->stats->tx_err);
goto done; goto done;
...@@ -366,7 +378,7 @@ int atmtcp_attach(struct atm_vcc *vcc,int itf) ...@@ -366,7 +378,7 @@ int atmtcp_attach(struct atm_vcc *vcc,int itf)
if (itf != -1) dev = atm_dev_lookup(itf); if (itf != -1) dev = atm_dev_lookup(itf);
if (dev) { if (dev) {
if (dev->ops != &atmtcp_v_dev_ops) { if (dev->ops != &atmtcp_v_dev_ops) {
atm_dev_release(dev); atm_dev_put(dev);
return -EMEDIUMTYPE; return -EMEDIUMTYPE;
} }
if (PRIV(dev)->vcc) return -EBUSY; if (PRIV(dev)->vcc) return -EBUSY;
...@@ -378,7 +390,8 @@ int atmtcp_attach(struct atm_vcc *vcc,int itf) ...@@ -378,7 +390,8 @@ int atmtcp_attach(struct atm_vcc *vcc,int itf)
if (error) return error; if (error) return error;
} }
PRIV(dev)->vcc = vcc; PRIV(dev)->vcc = vcc;
bind_vcc(vcc,&atmtcp_control_dev); vcc->dev = &atmtcp_control_dev;
vcc_insert_socket(vcc->sk);
set_bit(ATM_VF_META,&vcc->flags); set_bit(ATM_VF_META,&vcc->flags);
set_bit(ATM_VF_READY,&vcc->flags); set_bit(ATM_VF_READY,&vcc->flags);
vcc->dev_data = dev; vcc->dev_data = dev;
...@@ -402,7 +415,7 @@ int atmtcp_remove_persistent(int itf) ...@@ -402,7 +415,7 @@ int atmtcp_remove_persistent(int itf)
dev = atm_dev_lookup(itf); dev = atm_dev_lookup(itf);
if (!dev) return -ENODEV; if (!dev) return -ENODEV;
if (dev->ops != &atmtcp_v_dev_ops) { if (dev->ops != &atmtcp_v_dev_ops) {
atm_dev_release(dev); atm_dev_put(dev);
return -EMEDIUMTYPE; return -EMEDIUMTYPE;
} }
dev_data = PRIV(dev); dev_data = PRIV(dev);
...@@ -410,7 +423,7 @@ int atmtcp_remove_persistent(int itf) ...@@ -410,7 +423,7 @@ int atmtcp_remove_persistent(int itf)
dev_data->persist = 0; dev_data->persist = 0;
if (PRIV(dev)->vcc) return 0; if (PRIV(dev)->vcc) return 0;
kfree(dev_data); kfree(dev_data);
atm_dev_release(dev); atm_dev_put(dev);
shutdown_atm_dev(dev); shutdown_atm_dev(dev);
return 0; return 0;
} }
......
...@@ -1887,10 +1887,10 @@ static void eni_close(struct atm_vcc *vcc) ...@@ -1887,10 +1887,10 @@ static void eni_close(struct atm_vcc *vcc)
static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci) static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
{ {
unsigned long flags; struct sock *s;
struct atm_vcc *walk; struct atm_vcc *walk;
spin_lock_irqsave(&vcc->dev->lock, flags); read_lock(&vcc_sklist_lock);
if (*vpi == ATM_VPI_ANY) *vpi = 0; if (*vpi == ATM_VPI_ANY) *vpi = 0;
if (*vci == ATM_VCI_ANY) { if (*vci == ATM_VCI_ANY) {
for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) { for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) {
...@@ -1898,40 +1898,47 @@ static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci) ...@@ -1898,40 +1898,47 @@ static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
ENI_DEV(vcc->dev)->rx_map[*vci]) ENI_DEV(vcc->dev)->rx_map[*vci])
continue; continue;
if (vcc->qos.txtp.traffic_class != ATM_NONE) { if (vcc->qos.txtp.traffic_class != ATM_NONE) {
for (walk = vcc->dev->vccs; walk; for (s = vcc_sklist; s; s = s->sk_next) {
walk = walk->next) walk = atm_sk(s);
if (walk->dev != vcc->dev)
continue;
if (test_bit(ATM_VF_ADDR,&walk->flags) if (test_bit(ATM_VF_ADDR,&walk->flags)
&& walk->vci == *vci && && walk->vci == *vci &&
walk->qos.txtp.traffic_class != walk->qos.txtp.traffic_class !=
ATM_NONE) ATM_NONE)
break; break;
if (walk) continue; }
if (s) continue;
} }
break; break;
} }
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return *vci == NR_VCI ? -EADDRINUSE : 0; return *vci == NR_VCI ? -EADDRINUSE : 0;
} }
if (*vci == ATM_VCI_UNSPEC) { if (*vci == ATM_VCI_UNSPEC) {
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return 0; return 0;
} }
if (vcc->qos.rxtp.traffic_class != ATM_NONE && if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
ENI_DEV(vcc->dev)->rx_map[*vci]) { ENI_DEV(vcc->dev)->rx_map[*vci]) {
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return -EADDRINUSE; return -EADDRINUSE;
} }
if (vcc->qos.txtp.traffic_class == ATM_NONE) { if (vcc->qos.txtp.traffic_class == ATM_NONE) {
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return 0; return 0;
} }
for (walk = vcc->dev->vccs; walk; walk = walk->next) for (s = vcc_sklist; s; s = s->sk_next) {
walk = atm_sk(s);
if (walk->dev != vcc->dev)
continue;
if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci && if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci &&
walk->qos.txtp.traffic_class != ATM_NONE) { walk->qos.txtp.traffic_class != ATM_NONE) {
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return -EADDRINUSE; return -EADDRINUSE;
} }
spin_unlock_irqrestore(&vcc->dev->lock, flags); }
read_unlock(&vcc_sklist_lock);
return 0; return 0;
} }
...@@ -2139,7 +2146,7 @@ static unsigned char eni_phy_get(struct atm_dev *dev,unsigned long addr) ...@@ -2139,7 +2146,7 @@ static unsigned char eni_phy_get(struct atm_dev *dev,unsigned long addr)
static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
{ {
unsigned long flags; struct sock *s;
static const char *signal[] = { "LOST","unknown","okay" }; static const char *signal[] = { "LOST","unknown","okay" };
struct eni_dev *eni_dev = ENI_DEV(dev); struct eni_dev *eni_dev = ENI_DEV(dev);
struct atm_vcc *vcc; struct atm_vcc *vcc;
...@@ -2212,11 +2219,15 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) ...@@ -2212,11 +2219,15 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
return sprintf(page,"%10sbacklog %u packets\n","", return sprintf(page,"%10sbacklog %u packets\n","",
skb_queue_len(&tx->backlog)); skb_queue_len(&tx->backlog));
} }
spin_lock_irqsave(&dev->lock, flags); read_lock(&vcc_sklist_lock);
for (vcc = dev->vccs; vcc; vcc = vcc->next) { for (s = vcc_sklist; s; s = s->sk_next) {
struct eni_vcc *eni_vcc = ENI_VCC(vcc); struct eni_vcc *eni_vcc;
int length; int length;
vcc = atm_sk(s);
if (vcc->dev != dev)
continue;
eni_vcc = ENI_VCC(vcc);
if (--left) continue; if (--left) continue;
length = sprintf(page,"vcc %4d: ",vcc->vci); length = sprintf(page,"vcc %4d: ",vcc->vci);
if (eni_vcc->rx) { if (eni_vcc->rx) {
...@@ -2231,10 +2242,10 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) ...@@ -2231,10 +2242,10 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
length += sprintf(page+length,"tx[%d], txing %d bytes", length += sprintf(page+length,"tx[%d], txing %d bytes",
eni_vcc->tx->index,eni_vcc->txing); eni_vcc->tx->index,eni_vcc->txing);
page[length] = '\n'; page[length] = '\n';
spin_unlock_irqrestore(&dev->lock, flags); read_unlock(&vcc_sklist_lock);
return length+1; return length+1;
} }
spin_unlock_irqrestore(&dev->lock, flags); read_unlock(&vcc_sklist_lock);
for (i = 0; i < eni_dev->free_len; i++) { for (i = 0; i < eni_dev->free_len; i++) {
struct eni_free *fe = eni_dev->free_list+i; struct eni_free *fe = eni_dev->free_list+i;
unsigned long offset; unsigned long offset;
......
...@@ -1069,18 +1069,22 @@ fore200e_supply(struct fore200e* fore200e) ...@@ -1069,18 +1069,22 @@ fore200e_supply(struct fore200e* fore200e)
static struct atm_vcc* static struct atm_vcc*
fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd) fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
{ {
unsigned long flags; struct sock *s;
struct atm_vcc* vcc; struct atm_vcc* vcc;
spin_lock_irqsave(&fore200e->atm_dev->lock, flags); read_lock(&vcc_sklist_lock);
for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { for(s = vcc_sklist; s; s = s->sk_next) {
vcc = atm_sk(s);
if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) if (vcc->dev != fore200e->atm_dev)
break; continue;
if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) {
read_unlock(&vcc_sklist_lock);
return vcc;
}
} }
spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags); read_unlock(&vcc_sklist_lock);
return vcc; return NULL;
} }
...@@ -1350,20 +1354,23 @@ fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* ...@@ -1350,20 +1354,23 @@ fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc*
static int static int
fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci) fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci)
{ {
unsigned long flags;
struct atm_vcc* walk; struct atm_vcc* walk;
struct sock *s;
/* find a free VPI */ /* find a free VPI */
spin_lock_irqsave(&vcc->dev->lock, flags); read_lock(&vcc_sklist_lock);
if (*vpi == ATM_VPI_ANY) { if (*vpi == ATM_VPI_ANY) {
for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) { for (*vpi = 0, s = vcc_sklist; s; s = s->sk_next) {
walk = atm_sk(s);
if (walk->dev != vcc->dev)
continue;
if ((walk->vci == *vci) && (walk->vpi == *vpi)) { if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
(*vpi)++; (*vpi)++;
walk = vcc->dev->vccs; s = vcc_sklist;
} }
} }
} }
...@@ -1371,16 +1378,19 @@ fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci) ...@@ -1371,16 +1378,19 @@ fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci)
/* find a free VCI */ /* find a free VCI */
if (*vci == ATM_VCI_ANY) { if (*vci == ATM_VCI_ANY) {
for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) { for (*vci = ATM_NOT_RSV_VCI, s = vcc_sklist; s; s = s->sk_next) {
walk = atm_sk(s);
if (walk->dev != vcc->dev)
continue;
if ((walk->vpi = *vpi) && (walk->vci == *vci)) { if ((walk->vpi = *vpi) && (walk->vci == *vci)) {
*vci = walk->vci + 1; *vci = walk->vci + 1;
walk = vcc->dev->vccs; s = vcc_sklist;
} }
} }
} }
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return 0; return 0;
} }
...@@ -2642,7 +2652,7 @@ fore200e_module_cleanup(void) ...@@ -2642,7 +2652,7 @@ fore200e_module_cleanup(void)
static int static int
fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
{ {
unsigned long flags; struct sock *s;
struct fore200e* fore200e = FORE200E_DEV(dev); struct fore200e* fore200e = FORE200E_DEV(dev);
int len, left = *pos; int len, left = *pos;
...@@ -2889,8 +2899,12 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) ...@@ -2889,8 +2899,12 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
len = sprintf(page,"\n" len = sprintf(page,"\n"
" VCCs:\n address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n"); " VCCs:\n address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n");
spin_lock_irqsave(&fore200e->atm_dev->lock, flags); read_lock(&vcc_sklist_lock);
for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { for (s = vcc_sklist; s; s = s->sk_next) {
vcc = atm_sk(s);
if (vcc->dev != fore200e->atm_dev)
continue;
fore200e_vcc = FORE200E_VCC(vcc); fore200e_vcc = FORE200E_VCC(vcc);
...@@ -2904,7 +2918,7 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) ...@@ -2904,7 +2918,7 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
fore200e_vcc->rx_max_pdu fore200e_vcc->rx_max_pdu
); );
} }
spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags); read_unlock(&vcc_sklist_lock);
return len; return len;
} }
......
...@@ -79,7 +79,6 @@ ...@@ -79,7 +79,6 @@
#include <linux/sonet.h> #include <linux/sonet.h>
#define USE_TASKLET #define USE_TASKLET
#define USE_HE_FIND_VCC
#undef USE_SCATTERGATHER #undef USE_SCATTERGATHER
#undef USE_CHECKSUM_HW /* still confused about this */ #undef USE_CHECKSUM_HW /* still confused about this */
#define USE_RBPS #define USE_RBPS
...@@ -328,25 +327,24 @@ he_readl_internal(struct he_dev *he_dev, unsigned addr, unsigned flags) ...@@ -328,25 +327,24 @@ he_readl_internal(struct he_dev *he_dev, unsigned addr, unsigned flags)
he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7) he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7)
static __inline__ struct atm_vcc* static __inline__ struct atm_vcc*
he_find_vcc(struct he_dev *he_dev, unsigned cid) __find_vcc(struct he_dev *he_dev, unsigned cid)
{ {
unsigned long flags;
struct atm_vcc *vcc; struct atm_vcc *vcc;
struct sock *s;
short vpi; short vpi;
int vci; int vci;
vpi = cid >> he_dev->vcibits; vpi = cid >> he_dev->vcibits;
vci = cid & ((1 << he_dev->vcibits) - 1); vci = cid & ((1 << he_dev->vcibits) - 1);
spin_lock_irqsave(&he_dev->atm_dev->lock, flags); for (s = vcc_sklist; s; s = s->sk_next) {
for (vcc = he_dev->atm_dev->vccs; vcc; vcc = vcc->next) vcc = atm_sk(s);
if (vcc->vci == vci && vcc->vpi == vpi if (vcc->dev == he_dev->atm_dev &&
&& vcc->qos.rxtp.traffic_class != ATM_NONE) { vcc->vci == vci && vcc->vpi == vpi &&
spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags); vcc->qos.rxtp.traffic_class != ATM_NONE) {
return vcc; return vcc;
} }
}
spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
return NULL; return NULL;
} }
...@@ -1566,17 +1564,6 @@ he_start(struct atm_dev *dev) ...@@ -1566,17 +1564,6 @@ he_start(struct atm_dev *dev)
reg |= RX_ENABLE; reg |= RX_ENABLE;
he_writel(he_dev, reg, RC_CONFIG); he_writel(he_dev, reg, RC_CONFIG);
#ifndef USE_HE_FIND_VCC
he_dev->he_vcc_table = kmalloc(sizeof(struct he_vcc_table) *
(1 << (he_dev->vcibits + he_dev->vpibits)), GFP_KERNEL);
if (he_dev->he_vcc_table == NULL) {
hprintk("failed to alloc he_vcc_table\n");
return -ENOMEM;
}
memset(he_dev->he_vcc_table, 0, sizeof(struct he_vcc_table) *
(1 << (he_dev->vcibits + he_dev->vpibits)));
#endif
for (i = 0; i < HE_NUM_CS_STPER; ++i) { for (i = 0; i < HE_NUM_CS_STPER; ++i) {
he_dev->cs_stper[i].inuse = 0; he_dev->cs_stper[i].inuse = 0;
he_dev->cs_stper[i].pcr = -1; he_dev->cs_stper[i].pcr = -1;
...@@ -1712,11 +1699,6 @@ he_stop(struct he_dev *he_dev) ...@@ -1712,11 +1699,6 @@ he_stop(struct he_dev *he_dev)
he_dev->tpd_base, he_dev->tpd_base_phys); he_dev->tpd_base, he_dev->tpd_base_phys);
#endif #endif
#ifndef USE_HE_FIND_VCC
if (he_dev->he_vcc_table)
kfree(he_dev->he_vcc_table);
#endif
if (he_dev->pci_dev) { if (he_dev->pci_dev) {
pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command); pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command);
command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
...@@ -1798,6 +1780,7 @@ he_service_rbrq(struct he_dev *he_dev, int group) ...@@ -1798,6 +1780,7 @@ he_service_rbrq(struct he_dev *he_dev, int group)
int pdus_assembled = 0; int pdus_assembled = 0;
int updated = 0; int updated = 0;
read_lock(&vcc_sklist_lock);
while (he_dev->rbrq_head != rbrq_tail) { while (he_dev->rbrq_head != rbrq_tail) {
++updated; ++updated;
...@@ -1823,13 +1806,10 @@ he_service_rbrq(struct he_dev *he_dev, int group) ...@@ -1823,13 +1806,10 @@ he_service_rbrq(struct he_dev *he_dev, int group)
buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4; buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
cid = RBRQ_CID(he_dev->rbrq_head); cid = RBRQ_CID(he_dev->rbrq_head);
#ifdef USE_HE_FIND_VCC
if (cid != lastcid) if (cid != lastcid)
vcc = he_find_vcc(he_dev, cid); vcc = __find_vcc(he_dev, cid);
lastcid = cid; lastcid = cid;
#else
vcc = HE_LOOKUP_VCC(he_dev, cid);
#endif
if (vcc == NULL) { if (vcc == NULL) {
hprintk("vcc == NULL (cid 0x%x)\n", cid); hprintk("vcc == NULL (cid 0x%x)\n", cid);
if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
...@@ -1966,6 +1946,7 @@ he_service_rbrq(struct he_dev *he_dev, int group) ...@@ -1966,6 +1946,7 @@ he_service_rbrq(struct he_dev *he_dev, int group)
RBRQ_MASK(++he_dev->rbrq_head)); RBRQ_MASK(++he_dev->rbrq_head));
} }
read_unlock(&vcc_sklist_lock);
if (updated) { if (updated) {
if (updated > he_dev->rbrq_peak) if (updated > he_dev->rbrq_peak)
...@@ -2565,10 +2546,6 @@ he_open(struct atm_vcc *vcc, short vpi, int vci) ...@@ -2565,10 +2546,6 @@ he_open(struct atm_vcc *vcc, short vpi, int vci)
#endif #endif
spin_unlock_irqrestore(&he_dev->global_lock, flags); spin_unlock_irqrestore(&he_dev->global_lock, flags);
#ifndef USE_HE_FIND_VCC
HE_LOOKUP_VCC(he_dev, cid) = vcc;
#endif
} }
open_failed: open_failed:
...@@ -2634,9 +2611,6 @@ he_close(struct atm_vcc *vcc) ...@@ -2634,9 +2611,6 @@ he_close(struct atm_vcc *vcc)
if (timeout == 0) if (timeout == 0)
hprintk("close rx timeout cid 0x%x\n", cid); hprintk("close rx timeout cid 0x%x\n", cid);
#ifndef USE_HE_FIND_VCC
HE_LOOKUP_VCC(he_dev, cid) = NULL;
#endif
HPRINTK("close rx cid 0x%x complete\n", cid); HPRINTK("close rx cid 0x%x complete\n", cid);
} }
......
...@@ -2403,37 +2403,43 @@ idt77252_init_rx(struct idt77252_dev *card, struct vc_map *vc, ...@@ -2403,37 +2403,43 @@ idt77252_init_rx(struct idt77252_dev *card, struct vc_map *vc,
static int static int
idt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci) idt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci)
{ {
unsigned long flags; struct sock *s;
struct atm_vcc *walk; struct atm_vcc *walk;
spin_lock_irqsave(&vcc->dev->lock, flags); read_lock(&vcc_sklist_lock);
if (*vpi == ATM_VPI_ANY) { if (*vpi == ATM_VPI_ANY) {
*vpi = 0; *vpi = 0;
walk = vcc->dev->vccs; s = vcc_sklist;
while (walk) { while (s) {
walk = atm_sk(s);
if (walk->dev != vcc->dev)
continue;
if ((walk->vci == *vci) && (walk->vpi == *vpi)) { if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
(*vpi)++; (*vpi)++;
walk = vcc->dev->vccs; s = vcc_sklist;
continue; continue;
} }
walk = walk->next; s = s->sk_next;
} }
} }
if (*vci == ATM_VCI_ANY) { if (*vci == ATM_VCI_ANY) {
*vci = ATM_NOT_RSV_VCI; *vci = ATM_NOT_RSV_VCI;
walk = vcc->dev->vccs; s = vcc_sklist;
while (walk) { while (s) {
walk = atm_sk(s);
if (walk->dev != vcc->dev)
continue;
if ((walk->vci == *vci) && (walk->vpi == *vpi)) { if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
(*vci)++; (*vci)++;
walk = vcc->dev->vccs; s = vcc_sklist;
continue; continue;
} }
walk = walk->next; s = s->sk_next;
} }
} }
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return 0; return 0;
} }
......
...@@ -297,13 +297,14 @@ int dm_hash_rename(const char *old, const char *new) ...@@ -297,13 +297,14 @@ int dm_hash_rename(const char *old, const char *new)
/* /*
* rename and move the name cell. * rename and move the name cell.
*/ */
unregister_with_devfs(hc);
list_del(&hc->name_list); list_del(&hc->name_list);
old_name = hc->name; old_name = hc->name;
hc->name = new_name; hc->name = new_name;
list_add(&hc->name_list, _name_buckets + hash_str(new_name)); list_add(&hc->name_list, _name_buckets + hash_str(new_name));
/* rename the device node in devfs */ /* rename the device node in devfs */
unregister_with_devfs(hc);
register_with_devfs(hc); register_with_devfs(hc);
up_write(&_hash_lock); up_write(&_hash_lock);
......
...@@ -952,8 +952,6 @@ static int bond_open(struct net_device *dev) ...@@ -952,8 +952,6 @@ static int bond_open(struct net_device *dev)
add_timer(alb_timer); add_timer(alb_timer);
} }
MOD_INC_USE_COUNT;
if (miimon > 0) { /* link check interval, in milliseconds. */ if (miimon > 0) { /* link check interval, in milliseconds. */
init_timer(timer); init_timer(timer);
timer->expires = jiffies + (miimon * HZ / 1000); timer->expires = jiffies + (miimon * HZ / 1000);
...@@ -1027,7 +1025,6 @@ static int bond_close(struct net_device *master) ...@@ -1027,7 +1025,6 @@ static int bond_close(struct net_device *master)
bond_alb_deinitialize(bond); bond_alb_deinitialize(bond);
} }
MOD_DEC_USE_COUNT;
return 0; return 0;
} }
...@@ -3694,6 +3691,8 @@ static int __init bond_init(struct net_device *dev) ...@@ -3694,6 +3691,8 @@ static int __init bond_init(struct net_device *dev)
kfree(bond); kfree(bond);
return -ENOMEM; return -ENOMEM;
} }
bond->bond_proc_dir->owner = THIS_MODULE;
bond->bond_proc_info_file = bond->bond_proc_info_file =
create_proc_info_entry("info", 0, bond->bond_proc_dir, create_proc_info_entry("info", 0, bond->bond_proc_dir,
bond_get_info); bond_get_info);
...@@ -3705,6 +3704,7 @@ static int __init bond_init(struct net_device *dev) ...@@ -3705,6 +3704,7 @@ static int __init bond_init(struct net_device *dev)
kfree(bond); kfree(bond);
return -ENOMEM; return -ENOMEM;
} }
bond->bond_proc_info_file->owner = THIS_MODULE;
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
if (first_pass == 1) { if (first_pass == 1) {
......
...@@ -630,7 +630,7 @@ static void shaper_init_priv(struct net_device *dev) ...@@ -630,7 +630,7 @@ static void shaper_init_priv(struct net_device *dev)
* Add a shaper device to the system * Add a shaper device to the system
*/ */
static int __init shaper_probe(struct net_device *dev) static void __init shaper_setup(struct net_device *dev)
{ {
/* /*
* Set up the shaper. * Set up the shaper.
...@@ -642,6 +642,7 @@ static int __init shaper_probe(struct net_device *dev) ...@@ -642,6 +642,7 @@ static int __init shaper_probe(struct net_device *dev)
dev->open = shaper_open; dev->open = shaper_open;
dev->stop = shaper_close; dev->stop = shaper_close;
dev->destructor = (void (*)(struct net_device *))kfree;
dev->hard_start_xmit = shaper_start_xmit; dev->hard_start_xmit = shaper_start_xmit;
dev->get_stats = shaper_get_stats; dev->get_stats = shaper_get_stats;
dev->set_multicast_list = NULL; dev->set_multicast_list = NULL;
...@@ -669,12 +670,6 @@ static int __init shaper_probe(struct net_device *dev) ...@@ -669,12 +670,6 @@ static int __init shaper_probe(struct net_device *dev)
dev->addr_len = 0; dev->addr_len = 0;
dev->tx_queue_len = 10; dev->tx_queue_len = 10;
dev->flags = 0; dev->flags = 0;
/*
* Shaper is ok
*/
return 0;
} }
static int shapers = 1; static int shapers = 1;
...@@ -695,35 +690,38 @@ __setup("shapers=", set_num_shapers); ...@@ -695,35 +690,38 @@ __setup("shapers=", set_num_shapers);
#endif /* MODULE */ #endif /* MODULE */
static struct net_device *devs; static struct net_device **devs;
static unsigned int shapers_registered = 0; static unsigned int shapers_registered = 0;
static int __init shaper_init(void) static int __init shaper_init(void)
{ {
int i, err; int i;
size_t alloc_size; size_t alloc_size;
struct shaper *sp; struct net_device *dev;
char name[IFNAMSIZ];
if (shapers < 1) if (shapers < 1)
return -ENODEV; return -ENODEV;
alloc_size = (sizeof(*devs) * shapers) + alloc_size = sizeof(*dev) * shapers;
(sizeof(struct shaper) * shapers);
devs = kmalloc(alloc_size, GFP_KERNEL); devs = kmalloc(alloc_size, GFP_KERNEL);
if (!devs) if (!devs)
return -ENOMEM; return -ENOMEM;
memset(devs, 0, alloc_size); memset(devs, 0, alloc_size);
sp = (struct shaper *) &devs[shapers];
for (i = 0; i < shapers; i++) { for (i = 0; i < shapers; i++) {
err = dev_alloc_name(&devs[i], "shaper%d");
if (err < 0) snprintf(name, IFNAMSIZ, "shaper%d", i);
dev = alloc_netdev(sizeof(struct shaper), name,
shaper_setup);
if (!dev)
break; break;
devs[i].init = shaper_probe;
devs[i].priv = &sp[i]; if (register_netdev(dev))
if (register_netdev(&devs[i]))
break; break;
devs[i] = dev;
shapers_registered++; shapers_registered++;
} }
...@@ -740,7 +738,8 @@ static void __exit shaper_exit (void) ...@@ -740,7 +738,8 @@ static void __exit shaper_exit (void)
int i; int i;
for (i = 0; i < shapers_registered; i++) for (i = 0; i < shapers_registered; i++)
unregister_netdev(&devs[i]); if (devs[i])
unregister_netdev(devs[i]);
kfree(devs); kfree(devs);
devs = NULL; devs = NULL;
......
...@@ -985,6 +985,8 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) ...@@ -985,6 +985,8 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
* 7. If we were asked to remove a directory and victim isn't one - ENOTDIR. * 7. If we were asked to remove a directory and victim isn't one - ENOTDIR.
* 8. If we were asked to remove a non-directory and victim isn't one - EISDIR. * 8. If we were asked to remove a non-directory and victim isn't one - EISDIR.
* 9. We can't remove a root or mountpoint. * 9. We can't remove a root or mountpoint.
* 10. We don't allow removal of NFS sillyrenamed files; it's handled by
* nfs_async_unlink().
*/ */
static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir)
{ {
...@@ -1008,6 +1010,8 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) ...@@ -1008,6 +1010,8 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir)
return -EISDIR; return -EISDIR;
if (IS_DEADDIR(dir)) if (IS_DEADDIR(dir))
return -ENOENT; return -ENOENT;
if (victim->d_flags & DCACHE_NFSFS_RENAMED)
return -EBUSY;
return 0; return 0;
} }
......
...@@ -715,7 +715,6 @@ __nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) ...@@ -715,7 +715,6 @@ __nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
if (fattr->valid & NFS_ATTR_FATTR_V4) if (fattr->valid & NFS_ATTR_FATTR_V4)
nfsi->change_attr = fattr->change_attr; nfsi->change_attr = fattr->change_attr;
inode->i_size = nfs_size_to_loff_t(fattr->size); inode->i_size = nfs_size_to_loff_t(fattr->size);
inode->i_mode = fattr->mode;
inode->i_nlink = fattr->nlink; inode->i_nlink = fattr->nlink;
inode->i_uid = fattr->uid; inode->i_uid = fattr->uid;
inode->i_gid = fattr->gid; inode->i_gid = fattr->gid;
......
...@@ -293,7 +293,6 @@ struct atm_vcc { ...@@ -293,7 +293,6 @@ struct atm_vcc {
struct k_atm_aal_stats *stats; /* pointer to AAL stats group */ struct k_atm_aal_stats *stats; /* pointer to AAL stats group */
wait_queue_head_t sleep; /* if socket is busy */ wait_queue_head_t sleep; /* if socket is busy */
struct sock *sk; /* socket backpointer */ struct sock *sk; /* socket backpointer */
struct atm_vcc *prev,*next;
/* SVC part --- may move later ------------------------------------- */ /* SVC part --- may move later ------------------------------------- */
short itf; /* interface number */ short itf; /* interface number */
struct sockaddr_atmsvc local; struct sockaddr_atmsvc local;
...@@ -320,8 +319,6 @@ struct atm_dev { ...@@ -320,8 +319,6 @@ struct atm_dev {
/* (NULL) */ /* (NULL) */
const char *type; /* device type name */ const char *type; /* device type name */
int number; /* device index */ int number; /* device index */
struct atm_vcc *vccs; /* VCC table (or NULL) */
struct atm_vcc *last; /* last VCC (or undefined) */
void *dev_data; /* per-device data */ void *dev_data; /* per-device data */
void *phy_data; /* private PHY date */ void *phy_data; /* private PHY date */
unsigned long flags; /* device flags (ATM_DF_*) */ unsigned long flags; /* device flags (ATM_DF_*) */
...@@ -390,6 +387,9 @@ struct atm_skb_data { ...@@ -390,6 +387,9 @@ struct atm_skb_data {
unsigned long atm_options; /* ATM layer options */ unsigned long atm_options; /* ATM layer options */
}; };
extern struct sock *vcc_sklist;
extern rwlock_t vcc_sklist_lock;
#define ATM_SKB(skb) (((struct atm_skb_data *) (skb)->cb)) #define ATM_SKB(skb) (((struct atm_skb_data *) (skb)->cb))
struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
...@@ -397,7 +397,8 @@ struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops, ...@@ -397,7 +397,8 @@ struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
struct atm_dev *atm_dev_lookup(int number); struct atm_dev *atm_dev_lookup(int number);
void atm_dev_deregister(struct atm_dev *dev); void atm_dev_deregister(struct atm_dev *dev);
void shutdown_atm_dev(struct atm_dev *dev); void shutdown_atm_dev(struct atm_dev *dev);
void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev); void vcc_insert_socket(struct sock *sk);
void vcc_remove_socket(struct sock *sk);
/* /*
...@@ -436,7 +437,7 @@ static inline void atm_dev_hold(struct atm_dev *dev) ...@@ -436,7 +437,7 @@ static inline void atm_dev_hold(struct atm_dev *dev)
} }
static inline void atm_dev_release(struct atm_dev *dev) static inline void atm_dev_put(struct atm_dev *dev)
{ {
atomic_dec(&dev->refcnt); atomic_dec(&dev->refcnt);
...@@ -452,7 +453,7 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, ...@@ -452,7 +453,7 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci); int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci);
int atm_pcr_goal(struct atm_trafprm *tp); int atm_pcr_goal(struct atm_trafprm *tp);
void atm_async_release_vcc(struct atm_vcc *vcc,int reply); void vcc_release_async(struct atm_vcc *vcc, int reply);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -47,15 +47,20 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, ...@@ -47,15 +47,20 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
static int check_ci(struct atm_vcc *vcc,short vpi,int vci) static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
{ {
struct sock *s;
struct atm_vcc *walk; struct atm_vcc *walk;
for (walk = vcc->dev->vccs; walk; walk = walk->next) for (s = vcc_sklist; s; s = s->sk_next) {
walk = atm_sk(s);
if (walk->dev != vcc->dev)
continue;
if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi && if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi &&
walk->vci == vci && ((walk->qos.txtp.traffic_class != walk->vci == vci && ((walk->qos.txtp.traffic_class !=
ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) || ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
(walk->qos.rxtp.traffic_class != ATM_NONE && (walk->qos.rxtp.traffic_class != ATM_NONE &&
vcc->qos.rxtp.traffic_class != ATM_NONE))) vcc->qos.rxtp.traffic_class != ATM_NONE)))
return -EADDRINUSE; return -EADDRINUSE;
}
/* allow VCCs with same VPI/VCI iff they don't collide on /* allow VCCs with same VPI/VCI iff they don't collide on
TX/RX (but we may refuse such sharing for other reasons, TX/RX (but we may refuse such sharing for other reasons,
e.g. if protocol requires to have both channels) */ e.g. if protocol requires to have both channels) */
...@@ -65,17 +70,16 @@ static int check_ci(struct atm_vcc *vcc,short vpi,int vci) ...@@ -65,17 +70,16 @@ static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci) int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
{ {
unsigned long flags;
static short p = 0; /* poor man's per-device cache */ static short p = 0; /* poor man's per-device cache */
static int c = 0; static int c = 0;
short old_p; short old_p;
int old_c; int old_c;
int err; int err;
spin_lock_irqsave(&vcc->dev->lock, flags); read_lock(&vcc_sklist_lock);
if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) { if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
err = check_ci(vcc,*vpi,*vci); err = check_ci(vcc,*vpi,*vci);
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return err; return err;
} }
/* last scan may have left values out of bounds for current device */ /* last scan may have left values out of bounds for current device */
...@@ -90,7 +94,7 @@ int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci) ...@@ -90,7 +94,7 @@ int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
if (!check_ci(vcc,p,c)) { if (!check_ci(vcc,p,c)) {
*vpi = p; *vpi = p;
*vci = c; *vci = c;
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return 0; return 0;
} }
if (*vci == ATM_VCI_ANY) { if (*vci == ATM_VCI_ANY) {
...@@ -105,7 +109,7 @@ int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci) ...@@ -105,7 +109,7 @@ int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
} }
} }
while (old_p != p || old_c != c); while (old_p != p || old_c != c);
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return -EADDRINUSE; return -EADDRINUSE;
} }
......
...@@ -140,7 +140,7 @@ static void idle_timer_check(unsigned long dummy) ...@@ -140,7 +140,7 @@ static void idle_timer_check(unsigned long dummy)
DPRINTK("releasing vcc %p->%p of " DPRINTK("releasing vcc %p->%p of "
"entry %p\n",clip_vcc,clip_vcc->vcc, "entry %p\n",clip_vcc,clip_vcc->vcc,
entry); entry);
atm_async_release_vcc(clip_vcc->vcc, vcc_release_async(clip_vcc->vcc,
-ETIMEDOUT); -ETIMEDOUT);
} }
if (entry->vccs || if (entry->vccs ||
...@@ -737,7 +737,8 @@ static int atm_init_atmarp(struct atm_vcc *vcc) ...@@ -737,7 +737,8 @@ static int atm_init_atmarp(struct atm_vcc *vcc)
set_bit(ATM_VF_META,&vcc->flags); set_bit(ATM_VF_META,&vcc->flags);
set_bit(ATM_VF_READY,&vcc->flags); set_bit(ATM_VF_READY,&vcc->flags);
/* allow replies and avoid getting closed if signaling dies */ /* allow replies and avoid getting closed if signaling dies */
bind_vcc(vcc,&atmarpd_dev); vcc->dev = &atmarpd_dev;
vcc_insert_socket(vcc->sk);
vcc->push = NULL; vcc->push = NULL;
vcc->pop = NULL; /* crash */ vcc->pop = NULL; /* crash */
vcc->push_oam = NULL; /* crash */ vcc->push_oam = NULL; /* crash */
......
...@@ -157,6 +157,38 @@ EXPORT_SYMBOL(br2684_ioctl_hook); ...@@ -157,6 +157,38 @@ EXPORT_SYMBOL(br2684_ioctl_hook);
#endif #endif
struct sock *vcc_sklist;
rwlock_t vcc_sklist_lock = RW_LOCK_UNLOCKED;
void __vcc_insert_socket(struct sock *sk)
{
sk->sk_next = vcc_sklist;
if (sk->sk_next)
vcc_sklist->sk_pprev = &sk->sk_next;
vcc_sklist = sk;
sk->sk_pprev = &vcc_sklist;
}
void vcc_insert_socket(struct sock *sk)
{
write_lock_irq(&vcc_sklist_lock);
__vcc_insert_socket(sk);
write_unlock_irq(&vcc_sklist_lock);
}
void vcc_remove_socket(struct sock *sk)
{
write_lock_irq(&vcc_sklist_lock);
if (sk->sk_pprev) {
if (sk->sk_next)
sk->sk_next->sk_pprev = sk->sk_pprev;
*sk->sk_pprev = sk->sk_next;
sk->sk_pprev = NULL;
}
write_unlock_irq(&vcc_sklist_lock);
}
static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -175,16 +207,45 @@ static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) ...@@ -175,16 +207,45 @@ static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
} }
int atm_create(struct socket *sock,int protocol,int family) EXPORT_SYMBOL(vcc_sklist);
EXPORT_SYMBOL(vcc_sklist_lock);
EXPORT_SYMBOL(vcc_insert_socket);
EXPORT_SYMBOL(vcc_remove_socket);
static void vcc_sock_destruct(struct sock *sk)
{
struct atm_vcc *vcc = atm_sk(sk);
if (atomic_read(&vcc->sk->sk_rmem_alloc))
printk(KERN_DEBUG "vcc_sock_destruct: rmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_rmem_alloc));
if (atomic_read(&vcc->sk->sk_wmem_alloc))
printk(KERN_DEBUG "vcc_sock_destruct: wmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_wmem_alloc));
kfree(sk->sk_protinfo);
}
int vcc_create(struct socket *sock, int protocol, int family)
{ {
struct sock *sk; struct sock *sk;
struct atm_vcc *vcc; struct atm_vcc *vcc;
sock->sk = NULL; sock->sk = NULL;
if (sock->type == SOCK_STREAM) return -EINVAL; if (sock->type == SOCK_STREAM)
if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM; return -EINVAL;
vcc = atm_sk(sk); sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
memset(&vcc->flags,0,sizeof(vcc->flags)); if (!sk)
return -ENOMEM;
sock_init_data(NULL, sk);
vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
if (!vcc) {
sk_free(sk);
return -ENOMEM;
}
memset(vcc, 0, sizeof(*vcc));
vcc->sk = sk;
vcc->dev = NULL; vcc->dev = NULL;
vcc->callback = NULL; vcc->callback = NULL;
memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc)); memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
...@@ -199,55 +260,63 @@ int atm_create(struct socket *sock,int protocol,int family) ...@@ -199,55 +260,63 @@ int atm_create(struct socket *sock,int protocol,int family)
vcc->atm_options = vcc->aal_options = 0; vcc->atm_options = vcc->aal_options = 0;
init_waitqueue_head(&vcc->sleep); init_waitqueue_head(&vcc->sleep);
sk->sk_sleep = &vcc->sleep; sk->sk_sleep = &vcc->sleep;
sk->sk_destruct = vcc_sock_destruct;
sock->sk = sk; sock->sk = sk;
return 0; return 0;
} }
void atm_release_vcc_sk(struct sock *sk,int free_sk) static void vcc_destroy_socket(struct sock *sk)
{ {
struct atm_vcc *vcc = atm_sk(sk); struct atm_vcc *vcc = atm_sk(sk);
struct sk_buff *skb; struct sk_buff *skb;
clear_bit(ATM_VF_READY,&vcc->flags); clear_bit(ATM_VF_READY, &vcc->flags);
if (vcc->dev) { if (vcc->dev) {
if (vcc->dev->ops->close) vcc->dev->ops->close(vcc); if (vcc->dev->ops->close)
if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */ vcc->dev->ops->close(vcc);
if (vcc->push)
vcc->push(vcc, NULL); /* atmarpd has no push */
vcc_remove_socket(sk); /* no more receive */
while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) { while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) {
atm_return(vcc,skb->truesize); atm_return(vcc,skb->truesize);
kfree_skb(skb); kfree_skb(skb);
} }
module_put(vcc->dev->ops->owner); module_put(vcc->dev->ops->owner);
atm_dev_release(vcc->dev); atm_dev_put(vcc->dev);
if (atomic_read(&vcc->sk->sk_rmem_alloc))
printk(KERN_WARNING "atm_release_vcc: strange ... "
"rmem_alloc == %d after closing\n",
atomic_read(&vcc->sk->sk_rmem_alloc));
bind_vcc(vcc,NULL);
} }
if (free_sk) free_atm_vcc_sk(sk);
} }
int atm_release(struct socket *sock) int vcc_release(struct socket *sock)
{ {
if (sock->sk) struct sock *sk = sock->sk;
atm_release_vcc_sk(sock->sk,1);
if (sk) {
sock_orphan(sk);
lock_sock(sk);
vcc_destroy_socket(sock->sk);
release_sock(sk);
sock_put(sk);
}
return 0; return 0;
} }
void atm_async_release_vcc(struct atm_vcc *vcc,int reply) void vcc_release_async(struct atm_vcc *vcc, int reply)
{ {
set_bit(ATM_VF_CLOSE,&vcc->flags); set_bit(ATM_VF_CLOSE, &vcc->flags);
vcc->reply = reply; vcc->reply = reply;
vcc->sk->sk_err = -reply;
wake_up(&vcc->sleep); wake_up(&vcc->sleep);
} }
EXPORT_SYMBOL(atm_async_release_vcc); EXPORT_SYMBOL(vcc_release_async);
static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) static int adjust_tp(struct atm_trafprm *tp,unsigned char aal)
...@@ -276,7 +345,7 @@ static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) ...@@ -276,7 +345,7 @@ static int adjust_tp(struct atm_trafprm *tp,unsigned char aal)
} }
static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, int vpi,
int vci) int vci)
{ {
int error; int error;
...@@ -288,7 +357,8 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, ...@@ -288,7 +357,8 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi,
if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
return -EPERM; return -EPERM;
error = 0; error = 0;
bind_vcc(vcc,dev); vcc->dev = dev;
vcc_insert_socket(vcc->sk);
switch (vcc->qos.aal) { switch (vcc->qos.aal) {
case ATM_AAL0: case ATM_AAL0:
error = atm_init_aal0(vcc); error = atm_init_aal0(vcc);
...@@ -312,7 +382,7 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, ...@@ -312,7 +382,7 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi,
if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal); if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal); if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
if (error) { if (error) {
bind_vcc(vcc,NULL); vcc_remove_socket(vcc->sk);
return error; return error;
} }
DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal); DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
...@@ -326,7 +396,7 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, ...@@ -326,7 +396,7 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi,
error = dev->ops->open(vcc,vpi,vci); error = dev->ops->open(vcc,vpi,vci);
if (error) { if (error) {
module_put(dev->ops->owner); module_put(dev->ops->owner);
bind_vcc(vcc,NULL); vcc_remove_socket(vcc->sk);
return error; return error;
} }
} }
...@@ -334,29 +404,26 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, ...@@ -334,29 +404,26 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi,
} }
static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci) int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
{ {
struct atm_dev *dev; struct atm_dev *dev;
int return_val; struct atm_vcc *vcc = ATM_SD(sock);
int error;
dev = atm_dev_lookup(itf);
if (!dev)
return_val = -ENODEV;
else {
return_val = atm_do_connect_dev(vcc,dev,vpi,vci);
if (return_val) atm_dev_release(dev);
}
return return_val;
}
DPRINTK("vcc_connect (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;
int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci)
{
if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC) if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC)
clear_bit(ATM_VF_PARTIAL,&vcc->flags); clear_bit(ATM_VF_PARTIAL,&vcc->flags);
else if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) return -EINVAL; else
DPRINTK("atm_connect (TX: cl %d,bw %d-%d,sdu %d; " if (test_bit(ATM_VF_PARTIAL,&vcc->flags))
return -EINVAL;
DPRINTK("vcc_connect (TX: cl %d,bw %d-%d,sdu %d; "
"RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n", "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.traffic_class,vcc->qos.txtp.min_pcr,
vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu, vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu,
...@@ -364,141 +431,135 @@ int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci) ...@@ -364,141 +431,135 @@ int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci)
vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu, vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu,
vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" : vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" :
" ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal); " ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; if (!test_bit(ATM_VF_HASQOS, &vcc->flags))
return -EBADFD;
if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
return -EINVAL; return -EINVAL;
if (itf != ATM_ITF_ANY) { if (itf != ATM_ITF_ANY) {
int error; dev = atm_dev_lookup(itf);
error = __vcc_connect(vcc, dev, vpi, vci);
error = atm_do_connect(vcc,itf,vpi,vci); if (error) {
if (error) return error; atm_dev_put(dev);
return error;
} }
else { } else {
struct atm_dev *dev = NULL;
struct list_head *p, *next; struct list_head *p, *next;
dev = NULL;
spin_lock(&atm_dev_lock); spin_lock(&atm_dev_lock);
list_for_each_safe(p, next, &atm_devs) { list_for_each_safe(p, next, &atm_devs) {
dev = list_entry(p, struct atm_dev, dev_list); dev = list_entry(p, struct atm_dev, dev_list);
atm_dev_hold(dev); atm_dev_hold(dev);
spin_unlock(&atm_dev_lock); spin_unlock(&atm_dev_lock);
if (!atm_do_connect_dev(vcc,dev,vpi,vci)) if (!__vcc_connect(vcc, dev, vpi, vci))
break; break;
atm_dev_release(dev); atm_dev_put(dev);
dev = NULL; dev = NULL;
spin_lock(&atm_dev_lock); spin_lock(&atm_dev_lock);
} }
spin_unlock(&atm_dev_lock); spin_unlock(&atm_dev_lock);
if (!dev) return -ENODEV; if (!dev)
return -ENODEV;
} }
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
set_bit(ATM_VF_PARTIAL,&vcc->flags); set_bit(ATM_VF_PARTIAL,&vcc->flags);
return 0;
}
int atm_connect(struct socket *sock,int itf,short vpi,int vci)
{
int error;
DPRINTK("atm_connect (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;
error = atm_connect_vcc(ATM_SD(sock),itf,vpi,vci);
if (error) return error;
if (test_bit(ATM_VF_READY,&ATM_SD(sock)->flags)) if (test_bit(ATM_VF_READY,&ATM_SD(sock)->flags))
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
return 0; return 0;
} }
int atm_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
int total_len, int flags) int size, int flags)
{ {
DECLARE_WAITQUEUE(wait,current); struct sock *sk = sock->sk;
struct atm_vcc *vcc; struct atm_vcc *vcc;
struct sk_buff *skb; struct sk_buff *skb;
int eff_len,error; int copied, error = -EINVAL;
void *buff;
int size;
if (sock->state != SS_CONNECTED) return -ENOTCONN; if (sock->state != SS_CONNECTED)
if (flags & ~MSG_DONTWAIT) return -EOPNOTSUPP; return -ENOTCONN;
if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ if (flags & ~MSG_DONTWAIT) /* only handle MSG_DONTWAIT */
buff = m->msg_iov->iov_base; return -EOPNOTSUPP;
size = m->msg_iov->iov_len;
vcc = ATM_SD(sock); vcc = ATM_SD(sock);
add_wait_queue(&vcc->sleep,&wait);
set_current_state(TASK_INTERRUPTIBLE);
error = 1; /* <= 0 is error */
while (!(skb = skb_dequeue(&vcc->sk->sk_receive_queue))) {
if (test_bit(ATM_VF_RELEASED,&vcc->flags) || if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
test_bit(ATM_VF_CLOSE,&vcc->flags)) { test_bit(ATM_VF_CLOSE,&vcc->flags))
error = vcc->reply; return vcc->reply;
break; if (!test_bit(ATM_VF_READY, &vcc->flags))
} return 0;
if (!test_bit(ATM_VF_READY,&vcc->flags)) {
error = 0; skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &error);
break; if (!skb)
} return error;
if (flags & MSG_DONTWAIT) {
error = -EAGAIN; copied = skb->len;
break; if (copied > size) {
} copied = size;
schedule(); msg->msg_flags |= MSG_TRUNC;
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
error = -ERESTARTSYS;
break;
}
} }
set_current_state(TASK_RUNNING);
remove_wait_queue(&vcc->sleep,&wait); error = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (error <= 0) return error; if (error)
sock_recv_timestamp(m, vcc->sk, skb); return error;
eff_len = skb->len > size ? size : skb->len; sock_recv_timestamp(msg, sk, skb);
if (skb->len > size) /* Not fit ? Report it... */
m->msg_flags |= MSG_TRUNC;
if (vcc->dev->ops->feedback) if (vcc->dev->ops->feedback)
vcc->dev->ops->feedback(vcc,skb,(unsigned long) skb->data, vcc->dev->ops->feedback(vcc, skb, (unsigned long) skb->data,
(unsigned long) buff,eff_len); (unsigned long) msg->msg_iov->iov_base, copied);
DPRINTK("RcvM %d -= %d\n", atomic_read(&vcc->sk->sk_rmem_alloc), DPRINTK("RcvM %d -= %d\n", atomic_read(&vcc->sk->rmem_alloc), skb->truesize);
skb->truesize); atm_return(vcc, skb->truesize);
atm_return(vcc,skb->truesize); skb_free_datagram(sk, skb);
error = copy_to_user(buff,skb->data,eff_len) ? -EFAULT : 0; return copied;
kfree_skb(skb);
return error ? error : eff_len;
} }
int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
int total_len) int total_len)
{ {
DECLARE_WAITQUEUE(wait,current); struct sock *sk = sock->sk;
DEFINE_WAIT(wait);
struct atm_vcc *vcc; struct atm_vcc *vcc;
struct sk_buff *skb; struct sk_buff *skb;
int eff,error; int eff,error;
const void *buff; const void *buff;
int size; int size;
if (sock->state != SS_CONNECTED) return -ENOTCONN; lock_sock(sk);
if (m->msg_name) return -EISCONN; if (sock->state != SS_CONNECTED) {
if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ error = -ENOTCONN;
goto out;
}
if (m->msg_name) {
error = -EISCONN;
goto out;
}
if (m->msg_iovlen != 1) {
error = -ENOSYS; /* fix this later @@@ */
goto out;
}
buff = m->msg_iov->iov_base; buff = m->msg_iov->iov_base;
size = m->msg_iov->iov_len; size = m->msg_iov->iov_len;
vcc = ATM_SD(sock); vcc = ATM_SD(sock);
if (test_bit(ATM_VF_RELEASED,&vcc->flags) || if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
test_bit(ATM_VF_CLOSE,&vcc->flags)) test_bit(ATM_VF_CLOSE, &vcc->flags)) {
return vcc->reply; error = vcc->reply;
if (!test_bit(ATM_VF_READY,&vcc->flags)) return -EPIPE; goto out;
if (!size) return 0; }
if (size < 0 || size > vcc->qos.txtp.max_sdu) return -EMSGSIZE; if (!test_bit(ATM_VF_READY, &vcc->flags)) {
error = -EPIPE;
goto out;
}
if (!size) {
error = 0;
goto out;
}
if (size < 0 || size > vcc->qos.txtp.max_sdu) {
error = -EMSGSIZE;
goto out;
}
/* verify_area is done by net/socket.c */ /* verify_area is done by net/socket.c */
eff = (size+3) & ~3; /* align to word boundary */ eff = (size+3) & ~3; /* align to word boundary */
add_wait_queue(&vcc->sleep,&wait); prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE);
set_current_state(TASK_INTERRUPTIBLE);
error = 0; error = 0;
while (!(skb = alloc_tx(vcc,eff))) { while (!(skb = alloc_tx(vcc,eff))) {
if (m->msg_flags & MSG_DONTWAIT) { if (m->msg_flags & MSG_DONTWAIT) {
...@@ -506,7 +567,6 @@ int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, ...@@ -506,7 +567,6 @@ int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
break; break;
} }
schedule(); schedule();
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) { if (signal_pending(current)) {
error = -ERESTARTSYS; error = -ERESTARTSYS;
break; break;
...@@ -520,19 +580,24 @@ int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, ...@@ -520,19 +580,24 @@ int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
error = -EPIPE; error = -EPIPE;
break; break;
} }
prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE);
} }
set_current_state(TASK_RUNNING); finish_wait(&vcc->sleep, &wait);
remove_wait_queue(&vcc->sleep,&wait); if (error)
if (error) return error; goto out;
skb->dev = NULL; /* for paths shared with net_device interfaces */ skb->dev = NULL; /* for paths shared with net_device interfaces */
ATM_SKB(skb)->atm_options = vcc->atm_options; ATM_SKB(skb)->atm_options = vcc->atm_options;
if (copy_from_user(skb_put(skb,size),buff,size)) { if (copy_from_user(skb_put(skb,size),buff,size)) {
kfree_skb(skb); kfree_skb(skb);
return -EFAULT; error = -EFAULT;
goto out;
} }
if (eff != size) memset(skb->data+size,0,eff-size); if (eff != size) memset(skb->data+size,0,eff-size);
error = vcc->dev->ops->send(vcc,skb); error = vcc->dev->ops->send(vcc,skb);
return error ? error : size; error = error ? error : size;
out:
release_sock(sk);
return error;
} }
...@@ -563,61 +628,20 @@ unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait) ...@@ -563,61 +628,20 @@ unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait)
} }
static void copy_aal_stats(struct k_atm_aal_stats *from, int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
struct atm_aal_stats *to)
{ {
#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
__AAL_STAT_ITEMS
#undef __HANDLE_ITEM
}
static void subtract_aal_stats(struct k_atm_aal_stats *from,
struct atm_aal_stats *to)
{
#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i)
__AAL_STAT_ITEMS
#undef __HANDLE_ITEM
}
static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero)
{
struct atm_dev_stats tmp;
int error = 0;
copy_aal_stats(&dev->stats.aal0,&tmp.aal0);
copy_aal_stats(&dev->stats.aal34,&tmp.aal34);
copy_aal_stats(&dev->stats.aal5,&tmp.aal5);
if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
if (zero && !error) {
subtract_aal_stats(&dev->stats.aal0,&tmp.aal0);
subtract_aal_stats(&dev->stats.aal34,&tmp.aal34);
subtract_aal_stats(&dev->stats.aal5,&tmp.aal5);
}
return error ? -EFAULT : 0;
}
int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
{
struct atm_dev *dev;
struct list_head *p;
struct atm_vcc *vcc; struct atm_vcc *vcc;
int *tmp_buf, *tmp_p; int error;
void *buf;
int error,len,size,number, ret_val;
ret_val = 0;
vcc = ATM_SD(sock); vcc = ATM_SD(sock);
switch (cmd) { switch (cmd) {
case SIOCOUTQ: case SIOCOUTQ:
if (sock->state != SS_CONNECTED || if (sock->state != SS_CONNECTED ||
!test_bit(ATM_VF_READY,&vcc->flags)) { !test_bit(ATM_VF_READY, &vcc->flags)) {
ret_val = -EINVAL; error = -EINVAL;
goto done; goto done;
} }
ret_val = put_user(vcc->sk->sk_sndbuf - error = put_user(vcc->sk->sk_sndbuf -
atomic_read(&vcc->sk->sk_wmem_alloc), atomic_read(&vcc->sk->sk_wmem_alloc),
(int *) arg) ? -EFAULT : 0; (int *) arg) ? -EFAULT : 0;
goto done; goto done;
...@@ -626,66 +650,29 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) ...@@ -626,66 +650,29 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
struct sk_buff *skb; struct sk_buff *skb;
if (sock->state != SS_CONNECTED) { if (sock->state != SS_CONNECTED) {
ret_val = -EINVAL; error = -EINVAL;
goto done; goto done;
} }
skb = skb_peek(&vcc->sk->sk_receive_queue); skb = skb_peek(&vcc->sk->sk_receive_queue);
ret_val = put_user(skb ? skb->len : 0,(int *) arg) error = put_user(skb ? skb->len : 0,
? -EFAULT : 0; (int *) arg) ? -EFAULT : 0;
goto done;
}
case ATM_GETNAMES:
if (get_user(buf,
&((struct atm_iobuf *) arg)->buffer)) {
ret_val = -EFAULT;
goto done;
}
if (get_user(len,
&((struct atm_iobuf *) arg)->length)) {
ret_val = -EFAULT;
goto done;
}
size = 0;
spin_lock(&atm_dev_lock);
list_for_each(p, &atm_devs)
size += sizeof(int);
if (size > len) {
spin_unlock(&atm_dev_lock);
ret_val = -E2BIG;
goto done;
}
tmp_buf = kmalloc(size, GFP_ATOMIC);
if (!tmp_buf) {
spin_unlock(&atm_dev_lock);
ret_val = -ENOMEM;
goto done; goto done;
} }
tmp_p = tmp_buf;
list_for_each(p, &atm_devs) {
dev = list_entry(p, struct atm_dev, dev_list);
*tmp_p++ = dev->number;
}
spin_unlock(&atm_dev_lock);
ret_val = ((copy_to_user(buf, tmp_buf, size)) ||
put_user(size, &((struct atm_iobuf *) arg)->length)
) ? -EFAULT : 0;
kfree(tmp_buf);
goto done;
case SIOCGSTAMP: /* borrowed from IP */ case SIOCGSTAMP: /* borrowed from IP */
if (!vcc->sk->sk_stamp.tv_sec) { if (!vcc->sk->sk_stamp.tv_sec) {
ret_val = -ENOENT; error = -ENOENT;
goto done; goto done;
} }
ret_val = copy_to_user((void *)arg, &vcc->sk->sk_stamp, error = copy_to_user((void *)arg, &vcc->sk->sk_stamp,
sizeof(struct timeval)) ? -EFAULT : 0; sizeof(struct timeval)) ? -EFAULT : 0;
goto done; goto done;
case ATM_SETSC: case ATM_SETSC:
printk(KERN_WARNING "ATM_SETSC is obsolete\n"); printk(KERN_WARNING "ATM_SETSC is obsolete\n");
ret_val = 0; error = 0;
goto done; goto done;
case ATMSIGD_CTRL: case ATMSIGD_CTRL:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
/* /*
...@@ -696,28 +683,28 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) ...@@ -696,28 +683,28 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
* have the same privledges that /proc/kcore needs * have the same privledges that /proc/kcore needs
*/ */
if (!capable(CAP_SYS_RAWIO)) { if (!capable(CAP_SYS_RAWIO)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
error = sigd_attach(vcc); error = sigd_attach(vcc);
if (!error) sock->state = SS_CONNECTED; if (!error)
ret_val = error; sock->state = SS_CONNECTED;
goto done; goto done;
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
case SIOCMKCLIP: case SIOCMKCLIP:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
if (try_atm_clip_ops()) { if (try_atm_clip_ops()) {
ret_val = atm_clip_ops->clip_create(arg); error = atm_clip_ops->clip_create(arg);
module_put(atm_clip_ops->owner); module_put(atm_clip_ops->owner);
} else } else
ret_val = -ENOSYS; error = -ENOSYS;
goto done; goto done;
case ATMARPD_CTRL: case ATMARPD_CTRL:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
#if defined(CONFIG_ATM_CLIP_MODULE) #if defined(CONFIG_ATM_CLIP_MODULE)
...@@ -728,48 +715,47 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) ...@@ -728,48 +715,47 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
error = atm_clip_ops->atm_init_atmarp(vcc); error = atm_clip_ops->atm_init_atmarp(vcc);
if (!error) if (!error)
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
ret_val = error;
} else } else
ret_val = -ENOSYS; error = -ENOSYS;
goto done; goto done;
case ATMARP_MKIP: case ATMARP_MKIP:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
if (try_atm_clip_ops()) { if (try_atm_clip_ops()) {
ret_val = atm_clip_ops->clip_mkip(vcc, arg); error = atm_clip_ops->clip_mkip(vcc, arg);
module_put(atm_clip_ops->owner); module_put(atm_clip_ops->owner);
} else } else
ret_val = -ENOSYS; error = -ENOSYS;
goto done; goto done;
case ATMARP_SETENTRY: case ATMARP_SETENTRY:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
if (try_atm_clip_ops()) { if (try_atm_clip_ops()) {
ret_val = atm_clip_ops->clip_setentry(vcc, arg); error = atm_clip_ops->clip_setentry(vcc, arg);
module_put(atm_clip_ops->owner); module_put(atm_clip_ops->owner);
} else } else
ret_val = -ENOSYS; error = -ENOSYS;
goto done; goto done;
case ATMARP_ENCAP: case ATMARP_ENCAP:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
if (try_atm_clip_ops()) { if (try_atm_clip_ops()) {
ret_val = atm_clip_ops->clip_encap(vcc, arg); error = atm_clip_ops->clip_encap(vcc, arg);
module_put(atm_clip_ops->owner); module_put(atm_clip_ops->owner);
} else } else
ret_val = -ENOSYS; error = -ENOSYS;
goto done; goto done;
#endif #endif
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
case ATMLEC_CTRL: case ATMLEC_CTRL:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
#if defined(CONFIG_ATM_LANE_MODULE) #if defined(CONFIG_ATM_LANE_MODULE)
...@@ -781,37 +767,36 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) ...@@ -781,37 +767,36 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
module_put(atm_lane_ops->owner); module_put(atm_lane_ops->owner);
if (error >= 0) if (error >= 0)
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
ret_val = error;
} else } else
ret_val = -ENOSYS; error = -ENOSYS;
goto done; goto done;
case ATMLEC_MCAST: case ATMLEC_MCAST:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
if (try_atm_lane_ops()) { if (try_atm_lane_ops()) {
ret_val = atm_lane_ops->mcast_attach(vcc, (int) arg); error = atm_lane_ops->mcast_attach(vcc, (int) arg);
module_put(atm_lane_ops->owner); module_put(atm_lane_ops->owner);
} else } else
ret_val = -ENOSYS; error = -ENOSYS;
goto done; goto done;
case ATMLEC_DATA: case ATMLEC_DATA:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
if (try_atm_lane_ops()) { if (try_atm_lane_ops()) {
ret_val = atm_lane_ops->vcc_attach(vcc, (void *) arg); error = atm_lane_ops->vcc_attach(vcc, (void *) arg);
module_put(atm_lane_ops->owner); module_put(atm_lane_ops->owner);
} else } else
ret_val = -ENOSYS; error = -ENOSYS;
goto done; goto done;
#endif #endif
#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
case ATMMPC_CTRL: case ATMMPC_CTRL:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
#if defined(CONFIG_ATM_MPOA_MODULE) #if defined(CONFIG_ATM_MPOA_MODULE)
...@@ -823,63 +808,62 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) ...@@ -823,63 +808,62 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
module_put(atm_mpoa_ops->owner); module_put(atm_mpoa_ops->owner);
if (error >= 0) if (error >= 0)
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
ret_val = error;
} else } else
ret_val = -ENOSYS; error = -ENOSYS;
goto done; goto done;
case ATMMPC_DATA: case ATMMPC_DATA:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
if (try_atm_mpoa_ops()) { if (try_atm_mpoa_ops()) {
ret_val = atm_mpoa_ops->vcc_attach(vcc, arg); error = atm_mpoa_ops->vcc_attach(vcc, arg);
module_put(atm_mpoa_ops->owner); module_put(atm_mpoa_ops->owner);
} else } else
ret_val = -ENOSYS; error = -ENOSYS;
goto done; goto done;
#endif #endif
#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
case SIOCSIFATMTCP: case SIOCSIFATMTCP:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
if (!atm_tcp_ops.attach) { if (!atm_tcp_ops.attach) {
ret_val = -ENOPKG; error = -ENOPKG;
goto done; goto done;
} }
fops_get (&atm_tcp_ops); fops_get(&atm_tcp_ops);
error = atm_tcp_ops.attach(vcc,(int) arg); error = atm_tcp_ops.attach(vcc, (int) arg);
if (error >= 0) sock->state = SS_CONNECTED; if (error >= 0)
else fops_put (&atm_tcp_ops); sock->state = SS_CONNECTED;
ret_val = error; else
fops_put (&atm_tcp_ops);
goto done; goto done;
case ATMTCP_CREATE: case ATMTCP_CREATE:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
if (!atm_tcp_ops.create_persistent) { if (!atm_tcp_ops.create_persistent) {
ret_val = -ENOPKG; error = -ENOPKG;
goto done; goto done;
} }
error = atm_tcp_ops.create_persistent((int) arg); error = atm_tcp_ops.create_persistent((int) arg);
if (error < 0) fops_put (&atm_tcp_ops); if (error < 0)
ret_val = error; fops_put (&atm_tcp_ops);
goto done; goto done;
case ATMTCP_REMOVE: case ATMTCP_REMOVE:
if (!capable(CAP_NET_ADMIN)) { if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM; error = -EPERM;
goto done; goto done;
} }
if (!atm_tcp_ops.remove_persistent) { if (!atm_tcp_ops.remove_persistent) {
ret_val = -ENOPKG; error = -ENOPKG;
goto done; goto done;
} }
error = atm_tcp_ops.remove_persistent((int) arg); error = atm_tcp_ops.remove_persistent((int) arg);
fops_put (&atm_tcp_ops); fops_put(&atm_tcp_ops);
ret_val = error;
goto done; goto done;
#endif #endif
default: default:
...@@ -887,182 +871,23 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) ...@@ -887,182 +871,23 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg)
} }
#if defined(CONFIG_PPPOATM) || defined(CONFIG_PPPOATM_MODULE) #if defined(CONFIG_PPPOATM) || defined(CONFIG_PPPOATM_MODULE)
if (pppoatm_ioctl_hook) { if (pppoatm_ioctl_hook) {
ret_val = pppoatm_ioctl_hook(vcc, cmd, arg); error = pppoatm_ioctl_hook(vcc, cmd, arg);
if (ret_val != -ENOIOCTLCMD) if (error != -ENOIOCTLCMD)
goto done; goto done;
} }
#endif #endif
#if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE) #if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE)
if (br2684_ioctl_hook) { if (br2684_ioctl_hook) {
ret_val = br2684_ioctl_hook(vcc, cmd, arg); error = br2684_ioctl_hook(vcc, cmd, arg);
if (ret_val != -ENOIOCTLCMD) if (error != -ENOIOCTLCMD)
goto done; goto done;
} }
#endif #endif
if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) {
ret_val = -EFAULT;
goto done;
}
if (get_user(len,&((struct atmif_sioc *) arg)->length)) {
ret_val = -EFAULT;
goto done;
}
if (get_user(number,&((struct atmif_sioc *) arg)->number)) {
ret_val = -EFAULT;
goto done;
}
if (!(dev = atm_dev_lookup(number))) {
ret_val = -ENODEV;
goto done;
}
size = 0; error = atm_dev_ioctl(cmd, arg);
switch (cmd) {
case ATM_GETTYPE:
size = strlen(dev->type)+1;
if (copy_to_user(buf,dev->type,size)) {
ret_val = -EFAULT;
goto done_release;
}
break;
case ATM_GETESI:
size = ESI_LEN;
if (copy_to_user(buf,dev->esi,size)) {
ret_val = -EFAULT;
goto done_release;
}
break;
case ATM_SETESI:
{
int i;
for (i = 0; i < ESI_LEN; i++)
if (dev->esi[i]) {
ret_val = -EEXIST;
goto done_release;
}
}
/* fall through */
case ATM_SETESIF:
{
unsigned char esi[ESI_LEN];
if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM;
goto done_release;
}
if (copy_from_user(esi,buf,ESI_LEN)) {
ret_val = -EFAULT;
goto done_release;
}
memcpy(dev->esi,esi,ESI_LEN);
ret_val = ESI_LEN;
goto done_release;
}
case ATM_GETSTATZ:
if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM;
goto done_release;
}
/* fall through */
case ATM_GETSTAT:
size = sizeof(struct atm_dev_stats);
error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ);
if (error) {
ret_val = error;
goto done_release;
}
break;
case ATM_GETCIRANGE:
size = sizeof(struct atm_cirange);
if (copy_to_user(buf,&dev->ci_range,size)) {
ret_val = -EFAULT;
goto done_release;
}
break;
case ATM_GETLINKRATE:
size = sizeof(int);
if (copy_to_user(buf,&dev->link_rate,size)) {
ret_val = -EFAULT;
goto done_release;
}
break;
case ATM_RSTADDR:
if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM;
goto done_release;
}
atm_reset_addr(dev);
break;
case ATM_ADDADDR:
case ATM_DELADDR:
if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM;
goto done_release;
}
{
struct sockaddr_atmsvc addr;
if (copy_from_user(&addr,buf,sizeof(addr))) {
ret_val = -EFAULT;
goto done_release;
}
if (cmd == ATM_ADDADDR)
ret_val = atm_add_addr(dev,&addr);
else
ret_val = atm_del_addr(dev,&addr);
goto done_release;
}
case ATM_GETADDR:
size = atm_get_addr(dev,buf,len);
if (size < 0)
ret_val = size;
else
/* may return 0, but later on size == 0 means "don't
write the length" */
ret_val = put_user(size,
&((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
goto done_release;
case ATM_SETLOOP:
if (__ATM_LM_XTRMT((int) (long) buf) &&
__ATM_LM_XTLOC((int) (long) buf) >
__ATM_LM_XTRMT((int) (long) buf)) {
ret_val = -EINVAL;
goto done_release;
}
/* fall through */
case ATM_SETCIRANGE:
case SONET_GETSTATZ:
case SONET_SETDIAG:
case SONET_CLRDIAG:
case SONET_SETFRAMING:
if (!capable(CAP_NET_ADMIN)) {
ret_val = -EPERM;
goto done_release;
}
/* fall through */
default:
if (!dev->ops->ioctl) {
ret_val = -EINVAL;
goto done_release;
}
size = dev->ops->ioctl(dev,cmd,buf);
if (size < 0) {
ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size);
goto done_release;
}
}
if (size)
ret_val = put_user(size,&((struct atmif_sioc *) arg)->length) ?
-EFAULT : 0;
else
ret_val = 0;
done_release:
atm_dev_release(dev);
done: done:
return ret_val; return error;
} }
...@@ -1120,14 +945,16 @@ static int check_qos(struct atm_qos *qos) ...@@ -1120,14 +945,16 @@ static int check_qos(struct atm_qos *qos)
return check_tp(&qos->rxtp); return check_tp(&qos->rxtp);
} }
int vcc_setsockopt(struct socket *sock, int level, int optname,
static int atm_do_setsockopt(struct socket *sock,int level,int optname, char *optval, int optlen)
void *optval,int optlen)
{ {
struct atm_vcc *vcc; struct atm_vcc *vcc;
unsigned long value; unsigned long value;
int error; int error;
if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
return -EINVAL;
vcc = ATM_SD(sock); vcc = ATM_SD(sock);
switch (optname) { switch (optname) {
case SO_ATMQOS: case SO_ATMQOS:
...@@ -1161,10 +988,16 @@ static int atm_do_setsockopt(struct socket *sock,int level,int optname, ...@@ -1161,10 +988,16 @@ static int atm_do_setsockopt(struct socket *sock,int level,int optname,
} }
static int atm_do_getsockopt(struct socket *sock,int level,int optname, int vcc_getsockopt(struct socket *sock, int level, int optname,
void *optval,int optlen) char *optval, int *optlen)
{ {
struct atm_vcc *vcc; 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); vcc = ATM_SD(sock);
switch (optname) { switch (optname) {
...@@ -1195,28 +1028,7 @@ static int atm_do_getsockopt(struct socket *sock,int level,int optname, ...@@ -1195,28 +1028,7 @@ static int atm_do_getsockopt(struct socket *sock,int level,int optname,
break; break;
} }
if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL; if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL;
return vcc->dev->ops->getsockopt(vcc,level,optname,optval,optlen); return vcc->dev->ops->getsockopt(vcc, level, optname, optval, len);
}
int atm_setsockopt(struct socket *sock,int level,int optname,char *optval,
int optlen)
{
if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
return -EINVAL;
return atm_do_setsockopt(sock,level,optname,optval,optlen);
}
int atm_getsockopt(struct socket *sock,int level,int optname,
char *optval,int *optlen)
{
int len;
if (get_user(len,optlen)) return -EFAULT;
if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname))
return -EINVAL;
return atm_do_getsockopt(sock,level,optname,optval,len);
} }
......
...@@ -10,22 +10,20 @@ ...@@ -10,22 +10,20 @@
#include <linux/poll.h> /* for poll_table */ #include <linux/poll.h> /* for poll_table */
int atm_create(struct socket *sock,int protocol,int family); int vcc_create(struct socket *sock, int protocol, int family);
int atm_release(struct socket *sock); int vcc_release(struct socket *sock);
int atm_connect(struct socket *sock,int itf,short vpi,int vci); int vcc_connect(struct socket *sock, int itf, short vpi, int vci);
int atm_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
int total_len, int flags); int size, int flags);
int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
int total_len); int total_len);
unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait); unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait);
int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg); int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, int vcc_setsockopt(struct socket *sock, int level, int optname, char *optval,
int optlen); int optlen);
int atm_getsockopt(struct socket *sock,int level,int optname,char *optval, int vcc_getsockopt(struct socket *sock, int level, int optname, char *optval,
int *optlen); int *optlen);
int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci);
void atm_release_vcc_sk(struct sock *sk,int free_sk);
void atm_shutdown_dev(struct atm_dev *dev); void atm_shutdown_dev(struct atm_dev *dev);
int atmpvc_init(void); int atmpvc_init(void);
......
...@@ -48,7 +48,7 @@ extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent); ...@@ -48,7 +48,7 @@ extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
#include "lec.h" #include "lec.h"
#include "lec_arpc.h" #include "lec_arpc.h"
#include "resources.h" /* for bind_vcc() */ #include "resources.h"
#if 0 #if 0
#define DPRINTK printk #define DPRINTK printk
...@@ -810,7 +810,8 @@ lecd_attach(struct atm_vcc *vcc, int arg) ...@@ -810,7 +810,8 @@ lecd_attach(struct atm_vcc *vcc, int arg)
lec_arp_init(priv); lec_arp_init(priv);
priv->itfnum = i; /* LANE2 addition */ priv->itfnum = i; /* LANE2 addition */
priv->lecd = vcc; priv->lecd = vcc;
bind_vcc(vcc, &lecatm_dev); vcc->dev = &lecatm_dev;
vcc_insert_socket(vcc->sk);
vcc->proto_data = dev_lec[i]; vcc->proto_data = dev_lec[i];
set_bit(ATM_VF_META,&vcc->flags); set_bit(ATM_VF_META,&vcc->flags);
...@@ -1079,7 +1080,7 @@ lec_arp_clear_vccs(struct lec_arp_table *entry) ...@@ -1079,7 +1080,7 @@ lec_arp_clear_vccs(struct lec_arp_table *entry)
clear_bit(ATM_VF_READY,&entry->vcc->flags); clear_bit(ATM_VF_READY,&entry->vcc->flags);
entry->vcc->push(entry->vcc, NULL); entry->vcc->push(entry->vcc, NULL);
#endif #endif
atm_async_release_vcc(entry->vcc, -EPIPE); vcc_release_async(entry->vcc, -EPIPE);
entry->vcc = NULL; entry->vcc = NULL;
} }
if (entry->recv_vcc) { if (entry->recv_vcc) {
...@@ -1089,7 +1090,7 @@ lec_arp_clear_vccs(struct lec_arp_table *entry) ...@@ -1089,7 +1090,7 @@ lec_arp_clear_vccs(struct lec_arp_table *entry)
clear_bit(ATM_VF_READY,&entry->recv_vcc->flags); clear_bit(ATM_VF_READY,&entry->recv_vcc->flags);
entry->recv_vcc->push(entry->recv_vcc, NULL); entry->recv_vcc->push(entry->recv_vcc, NULL);
#endif #endif
atm_async_release_vcc(entry->recv_vcc, -EPIPE); vcc_release_async(entry->recv_vcc, -EPIPE);
entry->recv_vcc = NULL; entry->recv_vcc = NULL;
} }
} }
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "lec.h" #include "lec.h"
#include "mpc.h" #include "mpc.h"
#include "resources.h" /* for bind_vcc() */ #include "resources.h"
/* /*
* mpc.c: Implementation of MPOA client kernel part * mpc.c: Implementation of MPOA client kernel part
...@@ -789,7 +789,8 @@ int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) ...@@ -789,7 +789,8 @@ int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg)
} }
mpc->mpoad_vcc = vcc; mpc->mpoad_vcc = vcc;
bind_vcc(vcc, &mpc_dev); vcc->dev = &mpc_dev;
vcc_insert_socket(vcc->sk);
set_bit(ATM_VF_META,&vcc->flags); set_bit(ATM_VF_META,&vcc->flags);
set_bit(ATM_VF_READY,&vcc->flags); set_bit(ATM_VF_READY,&vcc->flags);
......
...@@ -212,7 +212,7 @@ static void in_cache_remove_entry(in_cache_entry *entry, ...@@ -212,7 +212,7 @@ static void in_cache_remove_entry(in_cache_entry *entry,
client->eg_ops->put(eg_entry); client->eg_ops->put(eg_entry);
return; return;
} }
atm_async_release_vcc(vcc, -EPIPE); vcc_release_async(vcc, -EPIPE);
} }
return; return;
...@@ -447,7 +447,7 @@ static void eg_cache_remove_entry(eg_cache_entry *entry, ...@@ -447,7 +447,7 @@ static void eg_cache_remove_entry(eg_cache_entry *entry,
client->in_ops->put(in_entry); client->in_ops->put(in_entry);
return; return;
} }
atm_async_release_vcc(vcc, -EPIPE); vcc_release_async(vcc, -EPIPE);
} }
return; return;
......
...@@ -334,9 +334,7 @@ static int atm_devices_info(loff_t pos,char *buf) ...@@ -334,9 +334,7 @@ static int atm_devices_info(loff_t pos,char *buf)
static int atm_pvc_info(loff_t pos,char *buf) static int atm_pvc_info(loff_t pos,char *buf)
{ {
unsigned long flags; struct sock *s;
struct atm_dev *dev;
struct list_head *p;
struct atm_vcc *vcc; struct atm_vcc *vcc;
int left, clip_info = 0; int left, clip_info = 0;
...@@ -349,25 +347,20 @@ static int atm_pvc_info(loff_t pos,char *buf) ...@@ -349,25 +347,20 @@ static int atm_pvc_info(loff_t pos,char *buf)
if (try_atm_clip_ops()) if (try_atm_clip_ops())
clip_info = 1; clip_info = 1;
#endif #endif
spin_lock(&atm_dev_lock); read_lock(&vcc_sklist_lock);
list_for_each(p, &atm_devs) { for(s = vcc_sklist; s; s = s->sk_next) {
dev = list_entry(p, struct atm_dev, dev_list); vcc = atm_sk(s);
spin_lock_irqsave(&dev->lock, flags); if (vcc->sk->sk_family == PF_ATMPVC && vcc->dev && !left--) {
for (vcc = dev->vccs; vcc; vcc = vcc->next)
if (vcc->sk->sk_family == PF_ATMPVC &&
vcc->dev && !left--) {
pvc_info(vcc,buf,clip_info); pvc_info(vcc,buf,clip_info);
spin_unlock_irqrestore(&dev->lock, flags); read_unlock(&vcc_sklist_lock);
spin_unlock(&atm_dev_lock);
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
if (clip_info) if (clip_info)
module_put(atm_clip_ops->owner); module_put(atm_clip_ops->owner);
#endif #endif
return strlen(buf); return strlen(buf);
} }
spin_unlock_irqrestore(&dev->lock, flags);
} }
spin_unlock(&atm_dev_lock); read_unlock(&vcc_sklist_lock);
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
if (clip_info) if (clip_info)
module_put(atm_clip_ops->owner); module_put(atm_clip_ops->owner);
...@@ -378,10 +371,8 @@ static int atm_pvc_info(loff_t pos,char *buf) ...@@ -378,10 +371,8 @@ static int atm_pvc_info(loff_t pos,char *buf)
static int atm_vc_info(loff_t pos,char *buf) static int atm_vc_info(loff_t pos,char *buf)
{ {
unsigned long flags;
struct atm_dev *dev;
struct list_head *p;
struct atm_vcc *vcc; struct atm_vcc *vcc;
struct sock *s;
int left; int left;
if (!pos) if (!pos)
...@@ -389,20 +380,16 @@ static int atm_vc_info(loff_t pos,char *buf) ...@@ -389,20 +380,16 @@ static int atm_vc_info(loff_t pos,char *buf)
"Address"," Itf VPI VCI Fam Flags Reply Send buffer" "Address"," Itf VPI VCI Fam Flags Reply Send buffer"
" Recv buffer\n"); " Recv buffer\n");
left = pos-1; left = pos-1;
spin_lock(&atm_dev_lock); read_lock(&vcc_sklist_lock);
list_for_each(p, &atm_devs) { for(s = vcc_sklist; s; s = s->sk_next) {
dev = list_entry(p, struct atm_dev, dev_list); vcc = atm_sk(s);
spin_lock_irqsave(&dev->lock, flags);
for (vcc = dev->vccs; vcc; vcc = vcc->next)
if (!left--) { if (!left--) {
vc_info(vcc,buf); vc_info(vcc,buf);
spin_unlock_irqrestore(&dev->lock, flags); read_unlock(&vcc_sklist_lock);
spin_unlock(&atm_dev_lock);
return strlen(buf); return strlen(buf);
} }
spin_unlock_irqrestore(&dev->lock, flags);
} }
spin_unlock(&atm_dev_lock); read_unlock(&vcc_sklist_lock);
return 0; return 0;
} }
...@@ -410,29 +397,23 @@ static int atm_vc_info(loff_t pos,char *buf) ...@@ -410,29 +397,23 @@ static int atm_vc_info(loff_t pos,char *buf)
static int atm_svc_info(loff_t pos,char *buf) static int atm_svc_info(loff_t pos,char *buf)
{ {
unsigned long flags; struct sock *s;
struct atm_dev *dev;
struct list_head *p;
struct atm_vcc *vcc; struct atm_vcc *vcc;
int left; int left;
if (!pos) if (!pos)
return sprintf(buf,"Itf VPI VCI State Remote\n"); return sprintf(buf,"Itf VPI VCI State Remote\n");
left = pos-1; left = pos-1;
spin_lock(&atm_dev_lock); read_lock(&vcc_sklist_lock);
list_for_each(p, &atm_devs) { for(s = vcc_sklist; s; s = s->sk_next) {
dev = list_entry(p, struct atm_dev, dev_list); vcc = atm_sk(s);
spin_lock_irqsave(&dev->lock, flags);
for (vcc = dev->vccs; vcc; vcc = vcc->next)
if (vcc->sk->sk_family == PF_ATMSVC && !left--) { if (vcc->sk->sk_family == PF_ATMSVC && !left--) {
svc_info(vcc,buf); svc_info(vcc,buf);
spin_unlock_irqrestore(&dev->lock, flags); read_unlock(&vcc_sklist_lock);
spin_unlock(&atm_dev_lock);
return strlen(buf); return strlen(buf);
} }
spin_unlock_irqrestore(&dev->lock, flags);
} }
spin_unlock(&atm_dev_lock); read_unlock(&vcc_sklist_lock);
return 0; return 0;
} }
......
...@@ -17,10 +17,6 @@ ...@@ -17,10 +17,6 @@
#include "resources.h" /* devs and vccs */ #include "resources.h" /* devs and vccs */
#include "common.h" /* common for PVCs and SVCs */ #include "common.h" /* common for PVCs and SVCs */
#ifndef NULL
#define NULL 0
#endif
static int pvc_shutdown(struct socket *sock,int how) static int pvc_shutdown(struct socket *sock,int how)
{ {
...@@ -31,20 +27,29 @@ static int pvc_shutdown(struct socket *sock,int how) ...@@ -31,20 +27,29 @@ static int pvc_shutdown(struct socket *sock,int how)
static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr, static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr,
int sockaddr_len) int sockaddr_len)
{ {
struct sock *sk = sock->sk;
struct sockaddr_atmpvc *addr; struct sockaddr_atmpvc *addr;
struct atm_vcc *vcc; struct atm_vcc *vcc;
int error;
if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL; if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL;
addr = (struct sockaddr_atmpvc *) sockaddr; addr = (struct sockaddr_atmpvc *) sockaddr;
if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT; if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT;
lock_sock(sk);
vcc = ATM_SD(sock); vcc = ATM_SD(sock);
if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
error = -EBADFD;
goto out;
}
if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) { if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi; if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi;
if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci; if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci;
} }
return atm_connect(sock,addr->sap_addr.itf,addr->sap_addr.vpi, error = vcc_connect(sock, addr->sap_addr.itf, addr->sap_addr.vpi,
addr->sap_addr.vci); addr->sap_addr.vci);
out:
release_sock(sk);
return error;
} }
...@@ -54,6 +59,31 @@ static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr, ...@@ -54,6 +59,31 @@ static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr,
return pvc_bind(sock,sockaddr,sockaddr_len); return pvc_bind(sock,sockaddr,sockaddr_len);
} }
static int pvc_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen)
{
struct sock *sk = sock->sk;
int error;
lock_sock(sk);
error = vcc_setsockopt(sock, level, optname, optval, optlen);
release_sock(sk);
return error;
}
static int pvc_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
{
struct sock *sk = sock->sk;
int error;
lock_sock(sk);
error = vcc_getsockopt(sock, level, optname, optval, optlen);
release_sock(sk);
return error;
}
static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr,
int *sockaddr_len,int peer) int *sockaddr_len,int peer)
...@@ -72,36 +102,32 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, ...@@ -72,36 +102,32 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr,
} }
static struct proto_ops SOCKOPS_WRAPPED(pvc_proto_ops) = { static struct proto_ops pvc_proto_ops = {
.family = PF_ATMPVC, .family = PF_ATMPVC,
.release = atm_release, .release = vcc_release,
.bind = pvc_bind, .bind = pvc_bind,
.connect = pvc_connect, .connect = pvc_connect,
.socketpair = sock_no_socketpair, .socketpair = sock_no_socketpair,
.accept = sock_no_accept, .accept = sock_no_accept,
.getname = pvc_getname, .getname = pvc_getname,
.poll = atm_poll, .poll = atm_poll,
.ioctl = atm_ioctl, .ioctl = vcc_ioctl,
.listen = sock_no_listen, .listen = sock_no_listen,
.shutdown = pvc_shutdown, .shutdown = pvc_shutdown,
.setsockopt = atm_setsockopt, .setsockopt = pvc_setsockopt,
.getsockopt = atm_getsockopt, .getsockopt = pvc_getsockopt,
.sendmsg = atm_sendmsg, .sendmsg = vcc_sendmsg,
.recvmsg = atm_recvmsg, .recvmsg = vcc_recvmsg,
.mmap = sock_no_mmap, .mmap = sock_no_mmap,
.sendpage = sock_no_sendpage, .sendpage = sock_no_sendpage,
}; };
#include <linux/smp_lock.h>
SOCKOPS_WRAP(pvc_proto, PF_ATMPVC);
static int pvc_create(struct socket *sock,int protocol) static int pvc_create(struct socket *sock,int protocol)
{ {
sock->ops = &pvc_proto_ops; sock->ops = &pvc_proto_ops;
return atm_create(sock,protocol,PF_ATMPVC); return vcc_create(sock, protocol, PF_ATMPVC);
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/atmdev.h> #include <linux/atmdev.h>
#include <linux/sonet.h>
#include <linux/kernel.h> /* for barrier */ #include <linux/kernel.h> /* for barrier */
#include <linux/module.h> #include <linux/module.h>
#include <linux/bitops.h> #include <linux/bitops.h>
...@@ -19,11 +20,7 @@ ...@@ -19,11 +20,7 @@
#include "common.h" #include "common.h"
#include "resources.h" #include "resources.h"
#include "addr.h"
#ifndef NULL
#define NULL 0
#endif
LIST_HEAD(atm_devs); LIST_HEAD(atm_devs);
...@@ -89,7 +86,7 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, ...@@ -89,7 +86,7 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
spin_lock(&atm_dev_lock); spin_lock(&atm_dev_lock);
if (number != -1) { if (number != -1) {
if ((inuse = __atm_dev_lookup(number))) { if ((inuse = __atm_dev_lookup(number))) {
atm_dev_release(inuse); atm_dev_put(inuse);
spin_unlock(&atm_dev_lock); spin_unlock(&atm_dev_lock);
__free_atm_dev(dev); __free_atm_dev(dev);
return NULL; return NULL;
...@@ -98,7 +95,7 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, ...@@ -98,7 +95,7 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
} else { } else {
dev->number = 0; dev->number = 0;
while ((inuse = __atm_dev_lookup(dev->number))) { while ((inuse = __atm_dev_lookup(dev->number))) {
atm_dev_release(inuse); atm_dev_put(inuse);
dev->number++; dev->number++;
} }
} }
...@@ -171,73 +168,241 @@ void shutdown_atm_dev(struct atm_dev *dev) ...@@ -171,73 +168,241 @@ void shutdown_atm_dev(struct atm_dev *dev)
atm_dev_deregister(dev); atm_dev_deregister(dev);
} }
struct sock *alloc_atm_vcc_sk(int family)
static void copy_aal_stats(struct k_atm_aal_stats *from,
struct atm_aal_stats *to)
{ {
struct sock *sk; #define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
struct atm_vcc *vcc; __AAL_STAT_ITEMS
#undef __HANDLE_ITEM
}
sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
if (!sk)
return NULL;
vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
if (!vcc) {
sk_free(sk);
return NULL;
}
sock_init_data(NULL, sk);
memset(vcc, 0, sizeof(*vcc));
vcc->sk = sk;
return sk; static void subtract_aal_stats(struct k_atm_aal_stats *from,
struct atm_aal_stats *to)
{
#define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i)
__AAL_STAT_ITEMS
#undef __HANDLE_ITEM
} }
static void unlink_vcc(struct atm_vcc *vcc) static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats *arg, int zero)
{ {
unsigned long flags; struct atm_dev_stats tmp;
if (vcc->dev) { int error = 0;
spin_lock_irqsave(&vcc->dev->lock, flags);
if (vcc->prev) copy_aal_stats(&dev->stats.aal0, &tmp.aal0);
vcc->prev->next = vcc->next; copy_aal_stats(&dev->stats.aal34, &tmp.aal34);
else copy_aal_stats(&dev->stats.aal5, &tmp.aal5);
vcc->dev->vccs = vcc->next; if (arg)
error = copy_to_user(arg, &tmp, sizeof(tmp));
if (vcc->next) if (zero && !error) {
vcc->next->prev = vcc->prev; subtract_aal_stats(&dev->stats.aal0, &tmp.aal0);
else subtract_aal_stats(&dev->stats.aal34, &tmp.aal34);
vcc->dev->last = vcc->prev; subtract_aal_stats(&dev->stats.aal5, &tmp.aal5);
spin_unlock_irqrestore(&vcc->dev->lock, flags);
} }
return error ? -EFAULT : 0;
} }
void free_atm_vcc_sk(struct sock *sk) int atm_dev_ioctl(unsigned int cmd, unsigned long arg)
{ {
unlink_vcc(atm_sk(sk)); void *buf;
sk_free(sk); int error, len, number, size = 0;
} struct atm_dev *dev;
struct list_head *p;
int *tmp_buf, *tmp_p;
switch (cmd) {
case ATM_GETNAMES:
if (get_user(buf, &((struct atm_iobuf *) arg)->buffer))
return -EFAULT;
if (get_user(len, &((struct atm_iobuf *) arg)->length))
return -EFAULT;
spin_lock(&atm_dev_lock);
list_for_each(p, &atm_devs)
size += sizeof(int);
if (size > len) {
spin_unlock(&atm_dev_lock);
return -E2BIG;
}
tmp_buf = kmalloc(size, GFP_ATOMIC);
if (!tmp_buf) {
spin_unlock(&atm_dev_lock);
return -ENOMEM;
}
tmp_p = tmp_buf;
list_for_each(p, &atm_devs) {
dev = list_entry(p, struct atm_dev, dev_list);
*tmp_p++ = dev->number;
}
spin_unlock(&atm_dev_lock);
error = ((copy_to_user(buf, tmp_buf, size)) ||
put_user(size, &((struct atm_iobuf *) arg)->length))
? -EFAULT : 0;
kfree(tmp_buf);
return error;
default:
break;
}
void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev) if (get_user(buf, &((struct atmif_sioc *) arg)->arg))
{ return -EFAULT;
unsigned long flags; if (get_user(len, &((struct atmif_sioc *) arg)->length))
return -EFAULT;
unlink_vcc(vcc); if (get_user(number, &((struct atmif_sioc *) arg)->number))
vcc->dev = dev; return -EFAULT;
if (dev) {
spin_lock_irqsave(&dev->lock, flags); if (!(dev = atm_dev_lookup(number)))
vcc->next = NULL; return -ENODEV;
vcc->prev = dev->last;
if (dev->vccs) switch (cmd) {
dev->last->next = vcc; case ATM_GETTYPE:
size = strlen(dev->type) + 1;
if (copy_to_user(buf, dev->type, size)) {
error = -EFAULT;
goto done;
}
break;
case ATM_GETESI:
size = ESI_LEN;
if (copy_to_user(buf, dev->esi, size)) {
error = -EFAULT;
goto done;
}
break;
case ATM_SETESI:
{
int i;
for (i = 0; i < ESI_LEN; i++)
if (dev->esi[i]) {
error = -EEXIST;
goto done;
}
}
/* fall through */
case ATM_SETESIF:
{
unsigned char esi[ESI_LEN];
if (!capable(CAP_NET_ADMIN)) {
error = -EPERM;
goto done;
}
if (copy_from_user(esi, buf, ESI_LEN)) {
error = -EFAULT;
goto done;
}
memcpy(dev->esi, esi, ESI_LEN);
error = ESI_LEN;
goto done;
}
case ATM_GETSTATZ:
if (!capable(CAP_NET_ADMIN)) {
error = -EPERM;
goto done;
}
/* fall through */
case ATM_GETSTAT:
size = sizeof(struct atm_dev_stats);
error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ);
if (error)
goto done;
break;
case ATM_GETCIRANGE:
size = sizeof(struct atm_cirange);
if (copy_to_user(buf, &dev->ci_range, size)) {
error = -EFAULT;
goto done;
}
break;
case ATM_GETLINKRATE:
size = sizeof(int);
if (copy_to_user(buf, &dev->link_rate, size)) {
error = -EFAULT;
goto done;
}
break;
case ATM_RSTADDR:
if (!capable(CAP_NET_ADMIN)) {
error = -EPERM;
goto done;
}
atm_reset_addr(dev);
break;
case ATM_ADDADDR:
case ATM_DELADDR:
if (!capable(CAP_NET_ADMIN)) {
error = -EPERM;
goto done;
}
{
struct sockaddr_atmsvc addr;
if (copy_from_user(&addr, buf, sizeof(addr))) {
error = -EFAULT;
goto done;
}
if (cmd == ATM_ADDADDR)
error = atm_add_addr(dev, &addr);
else else
dev->vccs = vcc; error = atm_del_addr(dev, &addr);
dev->last = vcc; goto done;
spin_unlock_irqrestore(&dev->lock, flags); }
case ATM_GETADDR:
error = atm_get_addr(dev, buf, len);
if (error < 0)
goto done;
size = error;
/* may return 0, but later on size == 0 means "don't
write the length" */
error = put_user(size, &((struct atmif_sioc *) arg)->length)
? -EFAULT : 0;
goto done;
case ATM_SETLOOP:
if (__ATM_LM_XTRMT((int) (long) buf) &&
__ATM_LM_XTLOC((int) (long) buf) >
__ATM_LM_XTRMT((int) (long) buf)) {
error = -EINVAL;
goto done;
}
/* fall through */
case ATM_SETCIRANGE:
case SONET_GETSTATZ:
case SONET_SETDIAG:
case SONET_CLRDIAG:
case SONET_SETFRAMING:
if (!capable(CAP_NET_ADMIN)) {
error = -EPERM;
goto done;
} }
/* fall through */
default:
if (!dev->ops->ioctl) {
error = -EINVAL;
goto done;
}
size = dev->ops->ioctl(dev, cmd, buf);
if (size < 0) {
error = (size == -ENOIOCTLCMD ? -EINVAL : size);
goto done;
}
}
if (size)
error = put_user(size, &((struct atmif_sioc *) arg)->length)
? -EFAULT : 0;
else
error = 0;
done:
atm_dev_put(dev);
return error;
} }
EXPORT_SYMBOL(atm_dev_register); EXPORT_SYMBOL(atm_dev_register);
EXPORT_SYMBOL(atm_dev_deregister); EXPORT_SYMBOL(atm_dev_deregister);
EXPORT_SYMBOL(atm_dev_lookup); EXPORT_SYMBOL(atm_dev_lookup);
EXPORT_SYMBOL(shutdown_atm_dev); EXPORT_SYMBOL(shutdown_atm_dev);
EXPORT_SYMBOL(bind_vcc);
...@@ -14,8 +14,7 @@ extern struct list_head atm_devs; ...@@ -14,8 +14,7 @@ extern struct list_head atm_devs;
extern spinlock_t atm_dev_lock; extern spinlock_t atm_dev_lock;
struct sock *alloc_atm_vcc_sk(int family); int atm_dev_ioctl(unsigned int cmd, unsigned long arg);
void free_atm_vcc_sk(struct sock *sk);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
...@@ -124,14 +124,16 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) ...@@ -124,14 +124,16 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb)
clear_bit(ATM_VF_REGIS,&vcc->flags); clear_bit(ATM_VF_REGIS,&vcc->flags);
clear_bit(ATM_VF_READY,&vcc->flags); clear_bit(ATM_VF_READY,&vcc->flags);
vcc->reply = msg->reply; vcc->reply = msg->reply;
vcc->sk->sk_err = -msg->reply;
break; break;
case as_indicate: case as_indicate:
vcc = *(struct atm_vcc **) &msg->listen_vcc; vcc = *(struct atm_vcc **) &msg->listen_vcc;
DPRINTK("as_indicate!!!\n"); DPRINTK("as_indicate!!!\n");
lock_sock(vcc->sk);
if (vcc->sk->sk_ack_backlog == if (vcc->sk->sk_ack_backlog ==
vcc->sk->sk_max_ack_backlog) { vcc->sk->sk_max_ack_backlog) {
sigd_enq(0,as_reject,vcc,NULL,NULL); sigd_enq(0,as_reject,vcc,NULL,NULL);
return 0; goto as_indicate_complete;
} }
vcc->sk->sk_ack_backlog++; vcc->sk->sk_ack_backlog++;
skb_queue_tail(&vcc->sk->sk_receive_queue, skb); skb_queue_tail(&vcc->sk->sk_receive_queue, skb);
...@@ -140,11 +142,14 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) ...@@ -140,11 +142,14 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb)
&vcc->sleep); &vcc->sleep);
vcc->callback(vcc); vcc->callback(vcc);
} }
as_indicate_complete:
release_sock(vcc->sk);
return 0; return 0;
case as_close: case as_close:
set_bit(ATM_VF_RELEASED,&vcc->flags); set_bit(ATM_VF_RELEASED,&vcc->flags);
clear_bit(ATM_VF_READY,&vcc->flags); clear_bit(ATM_VF_READY,&vcc->flags);
vcc->reply = msg->reply; vcc->reply = msg->reply;
vcc->sk->sk_err = -msg->reply;
break; break;
case as_modify: case as_modify:
modify_qos(vcc,msg); modify_qos(vcc,msg);
...@@ -195,25 +200,21 @@ void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, ...@@ -195,25 +200,21 @@ void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
} }
static void purge_vccs(struct atm_vcc *vcc) static void purge_vcc(struct atm_vcc *vcc)
{ {
while (vcc) {
if (vcc->sk->sk_family == PF_ATMSVC && if (vcc->sk->sk_family == PF_ATMSVC &&
!test_bit(ATM_VF_META,&vcc->flags)) { !test_bit(ATM_VF_META,&vcc->flags)) {
set_bit(ATM_VF_RELEASED,&vcc->flags); set_bit(ATM_VF_RELEASED,&vcc->flags);
vcc->reply = -EUNATCH; vcc->reply = -EUNATCH;
vcc->sk->sk_err = EUNATCH;
wake_up(&vcc->sleep); wake_up(&vcc->sleep);
} }
vcc = vcc->next;
}
} }
static void sigd_close(struct atm_vcc *vcc) static void sigd_close(struct atm_vcc *vcc)
{ {
unsigned long flags; struct sock *s;
struct atm_dev *dev;
struct list_head *p;
DPRINTK("sigd_close\n"); DPRINTK("sigd_close\n");
sigd = NULL; sigd = NULL;
...@@ -221,14 +222,14 @@ static void sigd_close(struct atm_vcc *vcc) ...@@ -221,14 +222,14 @@ static void sigd_close(struct atm_vcc *vcc)
printk(KERN_ERR "sigd_close: closing with requests pending\n"); printk(KERN_ERR "sigd_close: closing with requests pending\n");
skb_queue_purge(&vcc->sk->sk_receive_queue); skb_queue_purge(&vcc->sk->sk_receive_queue);
spin_lock(&atm_dev_lock); read_lock(&vcc_sklist_lock);
list_for_each(p, &atm_devs) { for(s = vcc_sklist; s; s = s->sk_next) {
dev = list_entry(p, struct atm_dev, dev_list); struct atm_vcc *vcc = atm_sk(s);
spin_lock_irqsave(&dev->lock, flags);
purge_vccs(dev->vccs); if (vcc->dev)
spin_unlock_irqrestore(&dev->lock, flags); purge_vcc(vcc);
} }
spin_unlock(&atm_dev_lock); read_unlock(&vcc_sklist_lock);
} }
...@@ -251,7 +252,8 @@ int sigd_attach(struct atm_vcc *vcc) ...@@ -251,7 +252,8 @@ int sigd_attach(struct atm_vcc *vcc)
if (sigd) return -EADDRINUSE; if (sigd) return -EADDRINUSE;
DPRINTK("sigd_attach\n"); DPRINTK("sigd_attach\n");
sigd = vcc; sigd = vcc;
bind_vcc(vcc,&sigd_dev); vcc->dev = &sigd_dev;
vcc_insert_socket(vcc->sk);
set_bit(ATM_VF_META,&vcc->flags); set_bit(ATM_VF_META,&vcc->flags);
set_bit(ATM_VF_READY,&vcc->flags); set_bit(ATM_VF_READY,&vcc->flags);
wake_up(&sigd_sleep); wake_up(&sigd_sleep);
......
...@@ -59,18 +59,18 @@ static int svc_shutdown(struct socket *sock,int how) ...@@ -59,18 +59,18 @@ static int svc_shutdown(struct socket *sock,int how)
static void svc_disconnect(struct atm_vcc *vcc) static void svc_disconnect(struct atm_vcc *vcc)
{ {
DECLARE_WAITQUEUE(wait,current); DEFINE_WAIT(wait);
struct sk_buff *skb; struct sk_buff *skb;
DPRINTK("svc_disconnect %p\n",vcc); DPRINTK("svc_disconnect %p\n",vcc);
if (test_bit(ATM_VF_REGIS,&vcc->flags)) { if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
add_wait_queue(&vcc->sleep,&wait); prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE);
sigd_enq(vcc,as_close,NULL,NULL,NULL); sigd_enq(vcc,as_close,NULL,NULL,NULL);
while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule(); schedule();
prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE);
} }
remove_wait_queue(&vcc->sleep,&wait); finish_wait(&vcc->sleep, &wait);
} }
/* beware - socket is still in use by atmsigd until the last /* beware - socket is still in use by atmsigd until the last
as_indicate has been answered */ as_indicate has been answered */
...@@ -88,18 +88,21 @@ static void svc_disconnect(struct atm_vcc *vcc) ...@@ -88,18 +88,21 @@ static void svc_disconnect(struct atm_vcc *vcc)
static int svc_release(struct socket *sock) static int svc_release(struct socket *sock)
{ {
struct sock *sk = sock->sk;
struct atm_vcc *vcc; struct atm_vcc *vcc;
if (!sock->sk) return 0; if (sk) {
vcc = ATM_SD(sock); vcc = ATM_SD(sock);
DPRINTK("svc_release %p\n",vcc); DPRINTK("svc_release %p\n", vcc);
clear_bit(ATM_VF_READY,&vcc->flags); clear_bit(ATM_VF_READY, &vcc->flags);
atm_release_vcc_sk(sock->sk,0);
svc_disconnect(vcc);
/* VCC pointer is used as a reference, so we must not free it /* VCC pointer is used as a reference, so we must not free it
(thereby subjecting it to re-use) before all pending connections (thereby subjecting it to re-use) before all pending connections
are closed */ are closed */
free_atm_vcc_sk(sock->sk); sock_hold(sk);
vcc_release(sock);
svc_disconnect(vcc);
sock_put(sk);
}
return 0; return 0;
} }
...@@ -107,80 +110,138 @@ static int svc_release(struct socket *sock) ...@@ -107,80 +110,138 @@ static int svc_release(struct socket *sock)
static int svc_bind(struct socket *sock,struct sockaddr *sockaddr, static int svc_bind(struct socket *sock,struct sockaddr *sockaddr,
int sockaddr_len) int sockaddr_len)
{ {
DECLARE_WAITQUEUE(wait,current); DEFINE_WAIT(wait);
struct sock *sk = sock->sk;
struct sockaddr_atmsvc *addr; struct sockaddr_atmsvc *addr;
struct atm_vcc *vcc; struct atm_vcc *vcc;
int error;
if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; if (sockaddr_len != sizeof(struct sockaddr_atmsvc))
if (sock->state == SS_CONNECTED) return -EISCONN; return -EINVAL;
if (sock->state != SS_UNCONNECTED) return -EINVAL; lock_sock(sk);
if (sock->state == SS_CONNECTED) {
error = -EISCONN;
goto out;
}
if (sock->state != SS_UNCONNECTED) {
error = -EINVAL;
goto out;
}
vcc = ATM_SD(sock); vcc = ATM_SD(sock);
if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; if (test_bit(ATM_VF_SESSION, &vcc->flags)) {
error = -EINVAL;
goto out;
}
addr = (struct sockaddr_atmsvc *) sockaddr; addr = (struct sockaddr_atmsvc *) sockaddr;
if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; if (addr->sas_family != AF_ATMSVC) {
error = -EAFNOSUPPORT;
goto out;
}
clear_bit(ATM_VF_BOUND,&vcc->flags); clear_bit(ATM_VF_BOUND,&vcc->flags);
/* failing rebind will kill old binding */ /* failing rebind will kill old binding */
/* @@@ check memory (de)allocation on rebind */ /* @@@ check memory (de)allocation on rebind */
if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) {
error = -EBADFD;
goto out;
}
vcc->local = *addr; vcc->local = *addr;
vcc->reply = WAITING; vcc->reply = WAITING;
add_wait_queue(&vcc->sleep,&wait); prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE);
sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local); sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
while (vcc->reply == WAITING && sigd) { while (vcc->reply == WAITING && sigd) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule(); schedule();
prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE);
} }
remove_wait_queue(&vcc->sleep,&wait); finish_wait(&vcc->sleep, &wait);
clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */ clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */
if (!sigd) return -EUNATCH; if (!sigd) {
if (!vcc->reply) set_bit(ATM_VF_BOUND,&vcc->flags); error = -EUNATCH;
return vcc->reply; goto out;
}
if (!vcc->reply)
set_bit(ATM_VF_BOUND,&vcc->flags);
error = vcc->reply;
out:
release_sock(sk);
return error;
} }
static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
int sockaddr_len,int flags) int sockaddr_len,int flags)
{ {
DECLARE_WAITQUEUE(wait,current); DEFINE_WAIT(wait);
struct sock *sk = sock->sk;
struct sockaddr_atmsvc *addr; struct sockaddr_atmsvc *addr;
struct atm_vcc *vcc = ATM_SD(sock); struct atm_vcc *vcc = ATM_SD(sock);
int error; int error;
DPRINTK("svc_connect %p\n",vcc); DPRINTK("svc_connect %p\n",vcc);
if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; lock_sock(sk);
if (sock->state == SS_CONNECTED) return -EISCONN; if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) {
if (sock->state == SS_CONNECTING) { error = -EINVAL;
if (vcc->reply == WAITING) return -EALREADY; goto out;
sock->state = SS_UNCONNECTED;
if (vcc->reply) return vcc->reply;
} }
else {
int error;
if (sock->state != SS_UNCONNECTED) return -EINVAL; switch (sock->state) {
if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; default:
error = -EINVAL;
goto out;
case SS_CONNECTED:
error = -EISCONN;
goto out;
case SS_CONNECTING:
if (vcc->reply == WAITING) {
error = -EALREADY;
goto out;
}
sock->state = SS_UNCONNECTED;
if (vcc->reply) {
error = vcc->reply;
goto out;
}
break;
case SS_UNCONNECTED:
if (test_bit(ATM_VF_SESSION, &vcc->flags)) {
error = -EINVAL;
goto out;
}
addr = (struct sockaddr_atmsvc *) sockaddr; addr = (struct sockaddr_atmsvc *) sockaddr;
if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; if (addr->sas_family != AF_ATMSVC) {
if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; error = -EAFNOSUPPORT;
goto out;
}
if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
error = -EBADFD;
goto out;
}
if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) {
return -EINVAL; error = -EINVAL;
goto out;
}
if (!vcc->qos.txtp.traffic_class && if (!vcc->qos.txtp.traffic_class &&
!vcc->qos.rxtp.traffic_class) return -EINVAL; !vcc->qos.rxtp.traffic_class) {
error = -EINVAL;
goto out;
}
vcc->remote = *addr; vcc->remote = *addr;
vcc->reply = WAITING; vcc->reply = WAITING;
add_wait_queue(&vcc->sleep,&wait); prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE);
sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote); sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote);
if (flags & O_NONBLOCK) { if (flags & O_NONBLOCK) {
remove_wait_queue(&vcc->sleep,&wait); finish_wait(&vcc->sleep, &wait);
sock->state = SS_CONNECTING; sock->state = SS_CONNECTING;
return -EINPROGRESS; error = -EINPROGRESS;
goto out;
} }
error = 0; error = 0;
while (vcc->reply == WAITING && sigd) { while (vcc->reply == WAITING && sigd) {
set_current_state(TASK_INTERRUPTIBLE);
schedule(); schedule();
if (!signal_pending(current)) continue; if (!signal_pending(current)) {
prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE);
continue;
}
DPRINTK("*ABORT*\n"); DPRINTK("*ABORT*\n");
/* /*
* This is tricky: * This is tricky:
...@@ -196,13 +257,13 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, ...@@ -196,13 +257,13 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
*/ */
sigd_enq(vcc,as_close,NULL,NULL,NULL); sigd_enq(vcc,as_close,NULL,NULL,NULL);
while (vcc->reply == WAITING && sigd) { while (vcc->reply == WAITING && sigd) {
set_current_state(TASK_UNINTERRUPTIBLE); prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE);
schedule(); schedule();
} }
if (!vcc->reply) if (!vcc->reply)
while (!test_bit(ATM_VF_RELEASED,&vcc->flags) while (!test_bit(ATM_VF_RELEASED,&vcc->flags)
&& sigd) { && sigd) {
set_current_state(TASK_UNINTERRUPTIBLE); prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE);
schedule(); schedule();
} }
clear_bit(ATM_VF_REGIS,&vcc->flags); clear_bit(ATM_VF_REGIS,&vcc->flags);
...@@ -212,10 +273,17 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, ...@@ -212,10 +273,17 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
error = -EINTR; error = -EINTR;
break; break;
} }
remove_wait_queue(&vcc->sleep,&wait); finish_wait(&vcc->sleep, &wait);
if (error) return error; if (error)
if (!sigd) return -EUNATCH; goto out;
if (vcc->reply) return vcc->reply; if (!sigd) {
error = -EUNATCH;
goto out;
}
if (vcc->reply) {
error = vcc->reply;
goto out;
}
} }
/* /*
* Not supported yet * Not supported yet
...@@ -228,56 +296,73 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, ...@@ -228,56 +296,73 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
/* /*
* #endif * #endif
*/ */
if (!(error = atm_connect(sock,vcc->itf,vcc->vpi,vcc->vci))) if (!(error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci)))
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
else (void) svc_disconnect(vcc); else (void) svc_disconnect(vcc);
out:
release_sock(sk);
return error; return error;
} }
static int svc_listen(struct socket *sock,int backlog) static int svc_listen(struct socket *sock,int backlog)
{ {
DECLARE_WAITQUEUE(wait,current); DEFINE_WAIT(wait);
struct sock *sk = sock->sk;
struct atm_vcc *vcc = ATM_SD(sock); struct atm_vcc *vcc = ATM_SD(sock);
int error;
DPRINTK("svc_listen %p\n",vcc); DPRINTK("svc_listen %p\n",vcc);
lock_sock(sk);
/* let server handle listen on unbound sockets */ /* let server handle listen on unbound sockets */
if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; if (test_bit(ATM_VF_SESSION,&vcc->flags)) {
error = -EINVAL;
goto out;
}
vcc->reply = WAITING; vcc->reply = WAITING;
add_wait_queue(&vcc->sleep,&wait); prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE);
sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);
while (vcc->reply == WAITING && sigd) { while (vcc->reply == WAITING && sigd) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule(); schedule();
prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE);
}
finish_wait(&vcc->sleep, &wait);
if (!sigd) {
error = -EUNATCH;
goto out;
} }
remove_wait_queue(&vcc->sleep,&wait);
if (!sigd) return -EUNATCH;
set_bit(ATM_VF_LISTEN,&vcc->flags); set_bit(ATM_VF_LISTEN,&vcc->flags);
vcc->sk->sk_max_ack_backlog = backlog > 0 ? backlog : vcc->sk->sk_max_ack_backlog = backlog > 0 ? backlog :
ATM_BACKLOG_DEFAULT; ATM_BACKLOG_DEFAULT;
return vcc->reply; error = vcc->reply;
out:
release_sock(sk);
return error;
} }
static int svc_accept(struct socket *sock,struct socket *newsock,int flags) static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
{ {
struct sock *sk = sock->sk;
struct sk_buff *skb; struct sk_buff *skb;
struct atmsvc_msg *msg; struct atmsvc_msg *msg;
struct atm_vcc *old_vcc = ATM_SD(sock); struct atm_vcc *old_vcc = ATM_SD(sock);
struct atm_vcc *new_vcc; struct atm_vcc *new_vcc;
int error; int error;
lock_sock(sk);
error = svc_create(newsock,0); error = svc_create(newsock,0);
if (error) if (error)
return error; goto out;
new_vcc = ATM_SD(newsock); new_vcc = ATM_SD(newsock);
DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc); DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc);
while (1) { while (1) {
DECLARE_WAITQUEUE(wait,current); DEFINE_WAIT(wait);
add_wait_queue(&old_vcc->sleep,&wait); prepare_to_wait(&old_vcc->sleep, &wait, TASK_INTERRUPTIBLE);
while (!(skb = skb_dequeue(&old_vcc->sk->sk_receive_queue)) && while (!(skb = skb_dequeue(&old_vcc->sk->sk_receive_queue)) &&
sigd) { sigd) {
if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break; if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break;
...@@ -289,46 +374,63 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) ...@@ -289,46 +374,63 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
error = -EAGAIN; error = -EAGAIN;
break; break;
} }
set_current_state(TASK_INTERRUPTIBLE); release_sock(sk);
schedule(); schedule();
lock_sock(sk);
if (signal_pending(current)) { if (signal_pending(current)) {
error = -ERESTARTSYS; error = -ERESTARTSYS;
break; break;
} }
prepare_to_wait(&old_vcc->sleep, &wait, TASK_INTERRUPTIBLE);
}
finish_wait(&old_vcc->sleep, &wait);
if (error)
goto out;
if (!skb) {
error = -EUNATCH;
goto out;
} }
remove_wait_queue(&old_vcc->sleep,&wait);
if (error) return error;
if (!skb) return -EUNATCH;
msg = (struct atmsvc_msg *) skb->data; msg = (struct atmsvc_msg *) skb->data;
new_vcc->qos = msg->qos; new_vcc->qos = msg->qos;
set_bit(ATM_VF_HASQOS,&new_vcc->flags); set_bit(ATM_VF_HASQOS,&new_vcc->flags);
new_vcc->remote = msg->svc; new_vcc->remote = msg->svc;
new_vcc->local = msg->local; new_vcc->local = msg->local;
new_vcc->sap = msg->sap; new_vcc->sap = msg->sap;
error = atm_connect(newsock,msg->pvc.sap_addr.itf, error = vcc_connect(newsock, msg->pvc.sap_addr.itf,
msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci); msg->pvc.sap_addr.vpi, msg->pvc.sap_addr.vci);
dev_kfree_skb(skb); dev_kfree_skb(skb);
old_vcc->sk->sk_ack_backlog--; old_vcc->sk->sk_ack_backlog--;
if (error) { if (error) {
sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL, sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL,
&old_vcc->qos,error); &old_vcc->qos,error);
return error == -EAGAIN ? -EBUSY : error; error = error == -EAGAIN ? -EBUSY : error;
goto out;
} }
/* wait should be short, so we ignore the non-blocking flag */ /* wait should be short, so we ignore the non-blocking flag */
new_vcc->reply = WAITING; new_vcc->reply = WAITING;
add_wait_queue(&new_vcc->sleep,&wait); prepare_to_wait(&new_vcc->sleep, &wait, TASK_UNINTERRUPTIBLE);
sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
while (new_vcc->reply == WAITING && sigd) { while (new_vcc->reply == WAITING && sigd) {
set_current_state(TASK_UNINTERRUPTIBLE); release_sock(sk);
schedule(); schedule();
lock_sock(sk);
prepare_to_wait(&new_vcc->sleep, &wait, TASK_UNINTERRUPTIBLE);
}
finish_wait(&new_vcc->sleep, &wait);
if (!sigd) {
error = -EUNATCH;
goto out;
} }
remove_wait_queue(&new_vcc->sleep,&wait);
if (!sigd) return -EUNATCH;
if (!new_vcc->reply) break; if (!new_vcc->reply) break;
if (new_vcc->reply != -ERESTARTSYS) return new_vcc->reply; if (new_vcc->reply != -ERESTARTSYS) {
error = new_vcc->reply;
goto out;
}
} }
newsock->state = SS_CONNECTED; newsock->state = SS_CONNECTED;
return 0; out:
release_sock(sk);
return error;
} }
...@@ -347,17 +449,17 @@ static int svc_getname(struct socket *sock,struct sockaddr *sockaddr, ...@@ -347,17 +449,17 @@ static int svc_getname(struct socket *sock,struct sockaddr *sockaddr,
int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
{ {
DECLARE_WAITQUEUE(wait,current); DEFINE_WAIT(wait);
vcc->reply = WAITING; vcc->reply = WAITING;
add_wait_queue(&vcc->sleep,&wait); prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE);
sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0); sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags) while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags)
&& sigd) { && sigd) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule(); schedule();
prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE);
} }
remove_wait_queue(&vcc->sleep,&wait); finish_wait(&vcc->sleep, &wait);
if (!sigd) return -EUNATCH; if (!sigd) return -EUNATCH;
return vcc->reply; return vcc->reply;
} }
...@@ -366,33 +468,57 @@ int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) ...@@ -366,33 +468,57 @@ int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
static int svc_setsockopt(struct socket *sock,int level,int optname, static int svc_setsockopt(struct socket *sock,int level,int optname,
char *optval,int optlen) char *optval,int optlen)
{ {
struct sock *sk = sock->sk;
struct atm_vcc *vcc; struct atm_vcc *vcc;
int error = 0;
if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP || if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP ||
optlen != sizeof(struct atm_sap)) optlen != sizeof(struct atm_sap)) {
return atm_setsockopt(sock,level,optname,optval,optlen); error = vcc_setsockopt(sock, level, optname, optval, optlen);
goto out;
}
vcc = ATM_SD(sock); vcc = ATM_SD(sock);
if (copy_from_user(&vcc->sap,optval,optlen)) return -EFAULT; if (copy_from_user(&vcc->sap, optval, optlen)) {
set_bit(ATM_VF_HASSAP,&vcc->flags); error = -EFAULT;
return 0; goto out;
}
set_bit(ATM_VF_HASSAP, &vcc->flags);
out:
release_sock(sk);
return error;
} }
static int svc_getsockopt(struct socket *sock,int level,int optname, static int svc_getsockopt(struct socket *sock,int level,int optname,
char *optval,int *optlen) char *optval,int *optlen)
{ {
int len; struct sock *sk = sock->sk;
int error = 0, len;
if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP)
return atm_getsockopt(sock,level,optname,optval,optlen); lock_sock(sk);
if (get_user(len,optlen)) return -EFAULT; if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) {
if (len != sizeof(struct atm_sap)) return -EINVAL; error = vcc_getsockopt(sock, level, optname, optval, optlen);
return copy_to_user(optval,&ATM_SD(sock)->sap,sizeof(struct atm_sap)) ? goto out;
-EFAULT : 0; }
if (get_user(len, optlen)) {
error = -EFAULT;
goto out;
}
if (len != sizeof(struct atm_sap)) {
error = -EINVAL;
goto out;
}
if (copy_to_user(optval, &ATM_SD(sock)->sap, sizeof(struct atm_sap))) {
error = -EFAULT;
goto out;
}
out:
release_sock(sk);
return error;
} }
static struct proto_ops SOCKOPS_WRAPPED(svc_proto_ops) = { static struct proto_ops svc_proto_ops = {
.family = PF_ATMSVC, .family = PF_ATMSVC,
.release = svc_release, .release = svc_release,
...@@ -402,27 +528,24 @@ static struct proto_ops SOCKOPS_WRAPPED(svc_proto_ops) = { ...@@ -402,27 +528,24 @@ static struct proto_ops SOCKOPS_WRAPPED(svc_proto_ops) = {
.accept = svc_accept, .accept = svc_accept,
.getname = svc_getname, .getname = svc_getname,
.poll = atm_poll, .poll = atm_poll,
.ioctl = atm_ioctl, .ioctl = vcc_ioctl,
.listen = svc_listen, .listen = svc_listen,
.shutdown = svc_shutdown, .shutdown = svc_shutdown,
.setsockopt = svc_setsockopt, .setsockopt = svc_setsockopt,
.getsockopt = svc_getsockopt, .getsockopt = svc_getsockopt,
.sendmsg = atm_sendmsg, .sendmsg = vcc_sendmsg,
.recvmsg = atm_recvmsg, .recvmsg = vcc_recvmsg,
.mmap = sock_no_mmap, .mmap = sock_no_mmap,
.sendpage = sock_no_sendpage, .sendpage = sock_no_sendpage,
}; };
#include <linux/smp_lock.h>
SOCKOPS_WRAP(svc_proto, PF_ATMSVC);
static int svc_create(struct socket *sock,int protocol) static int svc_create(struct socket *sock,int protocol)
{ {
int error; int error;
sock->ops = &svc_proto_ops; sock->ops = &svc_proto_ops;
error = atm_create(sock,protocol,AF_ATMSVC); error = vcc_create(sock, protocol, AF_ATMSVC);
if (error) return error; if (error) return error;
ATM_SD(sock)->callback = svc_callback; ATM_SD(sock)->callback = svc_callback;
ATM_SD(sock)->local.sas_family = AF_ATMSVC; ATM_SD(sock)->local.sas_family = AF_ATMSVC;
......
...@@ -387,8 +387,17 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, ...@@ -387,8 +387,17 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
if (type == IGMPV3_ALLOW_NEW_SOURCES || if (type == IGMPV3_ALLOW_NEW_SOURCES ||
type == IGMPV3_BLOCK_OLD_SOURCES) type == IGMPV3_BLOCK_OLD_SOURCES)
return skb; return skb;
if (pmc->crcount || isquery) if (pmc->crcount || isquery) {
/* make sure we have room for group header and at
* least one source.
*/
if (skb && AVAILABLE(skb) < sizeof(struct igmpv3_grec)+
sizeof(__u32)) {
igmpv3_sendpack(skb);
skb = 0; /* add_grhead will get a new one */
}
skb = add_grhead(skb, pmc, type, &pgr); skb = add_grhead(skb, pmc, type, &pgr);
}
return skb; return skb;
} }
pih = skb ? (struct igmpv3_report *)skb->h.igmph : 0; pih = skb ? (struct igmpv3_report *)skb->h.igmph : 0;
......
...@@ -1321,8 +1321,17 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, ...@@ -1321,8 +1321,17 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
if (type == MLD2_ALLOW_NEW_SOURCES || if (type == MLD2_ALLOW_NEW_SOURCES ||
type == MLD2_BLOCK_OLD_SOURCES) type == MLD2_BLOCK_OLD_SOURCES)
return skb; return skb;
if (pmc->mca_crcount || isquery) if (pmc->mca_crcount || isquery) {
/* make sure we have room for group header and at
* least one source.
*/
if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)+
sizeof(struct in6_addr)) {
mld_sendpack(skb);
skb = 0; /* add_grhead will get a new one */
}
skb = add_grhead(skb, pmc, type, &pgr); skb = add_grhead(skb, pmc, type, &pgr);
}
return skb; return skb;
} }
pmr = skb ? (struct mld2_report *)skb->h.raw : 0; pmr = skb ? (struct mld2_report *)skb->h.raw : 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment