Commit cb84e0b3 authored by Linus Torvalds's avatar Linus Torvalds

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

into home.transmeta.com:/home/torvalds/v2.5/linux
parents cfa89a3e b798ab6d
...@@ -153,9 +153,10 @@ static void atmtcp_v_close(struct atm_vcc *vcc) ...@@ -153,9 +153,10 @@ 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 hlist_node *node;
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 +164,18 @@ static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) ...@@ -163,14 +164,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) sk_for_each(s, node, &vcc_sklist) {
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 +238,10 @@ static int atmtcp_v_proc(struct atm_dev *dev,loff_t *pos,char *page) ...@@ -233,9 +238,10 @@ 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 hlist_node *node;
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 +252,24 @@ static void atmtcp_c_close(struct atm_vcc *vcc) ...@@ -246,19 +252,24 @@ 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) sk_for_each(s, node, &vcc_sklist) {
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 hlist_node *node;
struct atm_vcc *out_vcc = NULL;
struct sk_buff *new_skb; struct sk_buff *new_skb;
int result = 0; int result = 0;
...@@ -270,13 +281,17 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) ...@@ -270,13 +281,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) sk_for_each(s, node, &vcc_sklist) {
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 +381,7 @@ int atmtcp_attach(struct atm_vcc *vcc,int itf) ...@@ -366,7 +381,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 +393,8 @@ int atmtcp_attach(struct atm_vcc *vcc,int itf) ...@@ -378,7 +393,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 +418,7 @@ int atmtcp_remove_persistent(int itf) ...@@ -402,7 +418,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 +426,7 @@ int atmtcp_remove_persistent(int itf) ...@@ -410,7 +426,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,11 @@ static void eni_close(struct atm_vcc *vcc) ...@@ -1887,10 +1887,11 @@ 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 hlist_node *node;
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 +1899,48 @@ static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci) ...@@ -1898,40 +1899,48 @@ 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; sk_for_each(s, node, &vcc_sklist) {
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 (node)
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) sk_for_each(s, node, &vcc_sklist) {
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 +2148,8 @@ static unsigned char eni_phy_get(struct atm_dev *dev,unsigned long addr) ...@@ -2139,7 +2148,8 @@ 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 hlist_node *node;
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 +2222,15 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) ...@@ -2212,11 +2222,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) { sk_for_each(s, node, &vcc_sklist) {
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 +2245,10 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) ...@@ -2231,10 +2245,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,23 @@ fore200e_supply(struct fore200e* fore200e) ...@@ -1069,18 +1069,23 @@ 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;
struct hlist_node *node;
spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { read_lock(&vcc_sklist_lock);
sk_for_each(s, node, &vcc_sklist) {
if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) vcc = atm_sk(s);
break; if (vcc->dev != fore200e->atm_dev)
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 +1355,26 @@ fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* ...@@ -1350,20 +1355,26 @@ 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;
struct hlist_node *node;
/* 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) { *vpi = 0;
restart_vpi_search:
sk_for_each(s, node, &vcc_sklist) {
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; goto restart_vpi_search;
} }
} }
} }
...@@ -1371,16 +1382,21 @@ fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci) ...@@ -1371,16 +1382,21 @@ 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) { *vci = ATM_NOT_RSV_VCI;
restart_vci_search:
sk_for_each(s, node, &vcc_sklist) {
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; goto restart_vci_search;
} }
} }
} }
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return 0; return 0;
} }
...@@ -2642,7 +2658,8 @@ fore200e_module_cleanup(void) ...@@ -2642,7 +2658,8 @@ 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 hlist_node *node;
struct fore200e* fore200e = FORE200E_DEV(dev); struct fore200e* fore200e = FORE200E_DEV(dev);
int len, left = *pos; int len, left = *pos;
...@@ -2889,8 +2906,12 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) ...@@ -2889,8 +2906,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) { sk_for_each(s, node, &vcc_sklist) {
vcc = atm_sk(s);
if (vcc->dev != fore200e->atm_dev)
continue;
fore200e_vcc = FORE200E_VCC(vcc); fore200e_vcc = FORE200E_VCC(vcc);
...@@ -2904,7 +2925,7 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) ...@@ -2904,7 +2925,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,25 @@ he_readl_internal(struct he_dev *he_dev, unsigned addr, unsigned flags) ...@@ -328,25 +327,25 @@ 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 hlist_node *node;
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); sk_for_each(s, node, &vcc_sklist) {
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 +1565,6 @@ he_start(struct atm_dev *dev) ...@@ -1566,17 +1565,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 +1700,6 @@ he_stop(struct he_dev *he_dev) ...@@ -1712,11 +1700,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 +1781,7 @@ he_service_rbrq(struct he_dev *he_dev, int group) ...@@ -1798,6 +1781,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 +1807,10 @@ he_service_rbrq(struct he_dev *he_dev, int group) ...@@ -1823,13 +1807,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 +1947,7 @@ he_service_rbrq(struct he_dev *he_dev, int group) ...@@ -1966,6 +1947,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 +2547,6 @@ he_open(struct atm_vcc *vcc, short vpi, int vci) ...@@ -2565,10 +2547,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 +2612,6 @@ he_close(struct atm_vcc *vcc) ...@@ -2634,9 +2612,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 = sk_head(&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 = sk_head(&vcc_sklist);
continue; continue;
} }
walk = walk->next; s = sk_next(s);
} }
} }
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 = sk_head(&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 = sk_head(&vcc_sklist);
continue; continue;
} }
walk = walk->next; s = sk_next(s);
} }
} }
spin_unlock_irqrestore(&vcc->dev->lock, flags); read_unlock(&vcc_sklist_lock);
return 0; return 0;
} }
......
...@@ -1348,11 +1348,18 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb) ...@@ -1348,11 +1348,18 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
struct channel *pch = chan->ppp; struct channel *pch = chan->ppp;
int proto; int proto;
if (pch == 0 || skb->len == 0) { if (pch == 0)
kfree_skb(skb); goto drop;
return;
}
/* need to have PPP header */
if (!pskb_may_pull(skb, 2)) {
if (pch->ppp) {
++pch->ppp->stats.rx_length_errors;
ppp_receive_error(pch->ppp);
}
goto drop;
}
proto = PPP_PROTO(skb); proto = PPP_PROTO(skb);
read_lock_bh(&pch->upl); read_lock_bh(&pch->upl);
if (pch->ppp == 0 || proto >= 0xc000 || proto == PPP_CCPFRAG) { if (pch->ppp == 0 || proto >= 0xc000 || proto == PPP_CCPFRAG) {
...@@ -1367,6 +1374,10 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb) ...@@ -1367,6 +1374,10 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
ppp_do_recv(pch->ppp, skb, pch); ppp_do_recv(pch->ppp, skb, pch);
} }
read_unlock_bh(&pch->upl); read_unlock_bh(&pch->upl);
return;
drop:
kfree_skb(skb);
return;
} }
/* Put a 0-length skb in the receive queue as an error indication */ /* Put a 0-length skb in the receive queue as an error indication */
...@@ -1398,23 +1409,13 @@ ppp_input_error(struct ppp_channel *chan, int code) ...@@ -1398,23 +1409,13 @@ ppp_input_error(struct ppp_channel *chan, int code)
static void static void
ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
{ {
if (skb->len >= 2) {
#ifdef CONFIG_PPP_MULTILINK #ifdef CONFIG_PPP_MULTILINK
/* XXX do channel-level decompression here */ /* XXX do channel-level decompression here */
if (PPP_PROTO(skb) == PPP_MP) if (PPP_PROTO(skb) == PPP_MP)
ppp_receive_mp_frame(ppp, skb, pch); ppp_receive_mp_frame(ppp, skb, pch);
else else
#endif /* CONFIG_PPP_MULTILINK */ #endif /* CONFIG_PPP_MULTILINK */
ppp_receive_nonmp_frame(ppp, skb); ppp_receive_nonmp_frame(ppp, skb);
return;
}
if (skb->len > 0)
/* note: a 0-length skb is used as an error indication */
++ppp->stats.rx_length_errors;
kfree_skb(skb);
ppp_receive_error(ppp);
} }
static void static void
...@@ -1446,7 +1447,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1446,7 +1447,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
/* decompress VJ compressed packets */ /* decompress VJ compressed packets */
if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
goto err; goto err;
if (skb_tailroom(skb) < 124) {
if (skb_tailroom(skb) < 124 || skb_is_nonlinear(skb) ) {
/* copy to a new sk_buff with more tailroom */ /* copy to a new sk_buff with more tailroom */
ns = dev_alloc_skb(skb->len + 128); ns = dev_alloc_skb(skb->len + 128);
if (ns == 0) { if (ns == 0) {
...@@ -1474,6 +1476,13 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1474,6 +1476,13 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
case PPP_VJC_UNCOMP: case PPP_VJC_UNCOMP:
if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
goto err; goto err;
/* Until we fix the decompressor need to make sure
* data portion is linear.
*/
if (!pskb_may_pull(skb, skb->len))
goto err;
if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) { if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) {
printk(KERN_ERR "PPP: VJ uncompressed error\n"); printk(KERN_ERR "PPP: VJ uncompressed error\n");
goto err; goto err;
...@@ -1551,6 +1560,12 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb) ...@@ -1551,6 +1560,12 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb)
struct sk_buff *ns; struct sk_buff *ns;
int len; int len;
/* Until we fix all the decompressor's need to make sure
* data portion is linear.
*/
if (!pskb_may_pull(skb, skb->len))
goto err;
if (proto == PPP_COMP) { if (proto == PPP_COMP) {
ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN); ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN);
if (ns == 0) { if (ns == 0) {
...@@ -1603,7 +1618,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) ...@@ -1603,7 +1618,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
struct list_head *l; struct list_head *l;
int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
if (skb->len < mphdrlen + 1 || ppp->mrru == 0) if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0)
goto err; /* no good, throw it away */ goto err; /* no good, throw it away */
/* Decode sequence number and begin/end bits */ /* Decode sequence number and begin/end bits */
...@@ -2021,7 +2036,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) ...@@ -2021,7 +2036,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
unsigned char *dp = skb->data + 2; unsigned char *dp = skb->data + 2;
int len; int len;
if (skb->len < CCP_HDRLEN + 2 if (!pskb_may_pull(skb, CCP_HDRLEN + 2)
|| skb->len < (len = CCP_LENGTH(dp)) + 2) || skb->len < (len = CCP_LENGTH(dp)) + 2)
return; /* too short */ return; /* too short */
...@@ -2056,6 +2071,10 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) ...@@ -2056,6 +2071,10 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
case CCP_CONFACK: case CCP_CONFACK:
if ((ppp->flags & (SC_CCP_OPEN | SC_CCP_UP)) != SC_CCP_OPEN) if ((ppp->flags & (SC_CCP_OPEN | SC_CCP_UP)) != SC_CCP_OPEN)
break; break;
if (!pskb_may_pull(skb, len))
break;
dp += CCP_HDRLEN; dp += CCP_HDRLEN;
len -= CCP_HDRLEN; len -= CCP_HDRLEN;
if (len < CCP_OPT_MINLEN || len < CCP_OPT_LENGTH(dp)) if (len < CCP_OPT_MINLEN || len < CCP_OPT_LENGTH(dp))
......
...@@ -77,27 +77,14 @@ ...@@ -77,27 +77,14 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
static int __attribute__((unused)) pppoe_debug = 7;
#define PPPOE_HASH_BITS 4 #define PPPOE_HASH_BITS 4
#define PPPOE_HASH_SIZE (1<<PPPOE_HASH_BITS) #define PPPOE_HASH_SIZE (1<<PPPOE_HASH_BITS)
int pppoe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); static int pppoe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb); static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb);
int __pppoe_xmit(struct sock *sk, struct sk_buff *skb); static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb);
struct proto_ops pppoe_ops;
#if 0
#define CHECKPTR(x,y) do { if (!(x) && pppoe_debug &7 ){ printk(KERN_CRIT "PPPoE Invalid pointer : %s , %p\n",#x,(x)); error=-EINVAL; goto y; }} while (0)
#define DEBUG(s,args...) do { if( pppoe_debug & (s) ) printk(KERN_CRIT args ); } while (0)
#else
#define CHECKPTR(x,y) do { } while (0)
#define DEBUG(s,args...) do { } while (0)
#endif
static struct proto_ops pppoe_ops;
static rwlock_t pppoe_hash_lock = RW_LOCK_UNLOCKED; static rwlock_t pppoe_hash_lock = RW_LOCK_UNLOCKED;
...@@ -255,8 +242,7 @@ static void pppoe_flush_dev(struct net_device *dev) ...@@ -255,8 +242,7 @@ static void pppoe_flush_dev(struct net_device *dev)
{ {
int hash; int hash;
if (dev == NULL) BUG_ON(dev == NULL);
BUG();
read_lock_bh(&pppoe_hash_lock); read_lock_bh(&pppoe_hash_lock);
for (hash = 0; hash < PPPOE_HASH_SIZE; hash++) { for (hash = 0; hash < PPPOE_HASH_SIZE; hash++) {
...@@ -336,20 +322,22 @@ static struct notifier_block pppoe_notifier = { ...@@ -336,20 +322,22 @@ static struct notifier_block pppoe_notifier = {
}; };
/************************************************************************ /************************************************************************
* *
* Do the real work of receiving a PPPoE Session frame. * Do the real work of receiving a PPPoE Session frame.
* *
***********************************************************************/ ***********************************************************************/
int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
{ {
struct pppox_opt *po = pppox_sk(sk); struct pppox_opt *po = pppox_sk(sk);
struct pppox_opt *relay_po = NULL; struct pppox_opt *relay_po = NULL;
if (sk->sk_state & PPPOX_BOUND) { if (sk->sk_state & PPPOX_BOUND) {
struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw;
int len = ntohs(ph->length);
skb_pull(skb, sizeof(struct pppoe_hdr)); skb_pull(skb, sizeof(struct pppoe_hdr));
skb_trim(skb, len);
ppp_input(&po->chan, skb); ppp_input(&po->chan, skb);
} else if (sk->sk_state & PPPOX_RELAY) { } else if (sk->sk_state & PPPOX_RELAY) {
relay_po = get_item_by_addr(&po->pppoe_relay); relay_po = get_item_by_addr(&po->pppoe_relay);
...@@ -361,7 +349,7 @@ int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) ...@@ -361,7 +349,7 @@ int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
goto abort_put; goto abort_put;
skb_pull(skb, sizeof(struct pppoe_hdr)); skb_pull(skb, sizeof(struct pppoe_hdr));
if (!__pppoe_xmit( relay_po->sk , skb)) if (!__pppoe_xmit( relay_po->sk, skb))
goto abort_put; goto abort_put;
} else { } else {
sock_queue_rcv_skb(sk, skb); sock_queue_rcv_skb(sk, skb);
...@@ -387,17 +375,22 @@ static int pppoe_rcv(struct sk_buff *skb, ...@@ -387,17 +375,22 @@ static int pppoe_rcv(struct sk_buff *skb,
struct packet_type *pt) struct packet_type *pt)
{ {
struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw; struct pppoe_hdr *ph;
struct pppox_opt *po; struct pppox_opt *po;
struct sock *sk ; struct sock *sk;
int ret; int ret;
po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source); if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto drop;
if (!po) { if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
kfree_skb(skb); goto out;
return NET_RX_DROP;
} ph = (struct pppoe_hdr *) skb->nh.raw;
po = get_item((unsigned long) ph->sid, skb->mac.ethernet->h_source);
if (!po)
goto drop;
sk = po->sk; sk = po->sk;
bh_lock_sock(sk); bh_lock_sock(sk);
...@@ -414,6 +407,10 @@ static int pppoe_rcv(struct sk_buff *skb, ...@@ -414,6 +407,10 @@ static int pppoe_rcv(struct sk_buff *skb,
sock_put(sk); sock_put(sk);
return ret; return ret;
drop:
kfree_skb(skb);
out:
return NET_RX_DROP;
} }
/************************************************************************ /************************************************************************
...@@ -427,9 +424,16 @@ static int pppoe_disc_rcv(struct sk_buff *skb, ...@@ -427,9 +424,16 @@ static int pppoe_disc_rcv(struct sk_buff *skb,
struct packet_type *pt) struct packet_type *pt)
{ {
struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw; struct pppoe_hdr *ph;
struct pppox_opt *po; struct pppox_opt *po;
if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto abort;
if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
goto out;
ph = (struct pppoe_hdr *) skb->nh.raw;
if (ph->code != PADT_CODE) if (ph->code != PADT_CODE)
goto abort; goto abort;
...@@ -457,17 +461,20 @@ static int pppoe_disc_rcv(struct sk_buff *skb, ...@@ -457,17 +461,20 @@ static int pppoe_disc_rcv(struct sk_buff *skb,
abort: abort:
kfree_skb(skb); kfree_skb(skb);
out:
return NET_RX_SUCCESS; /* Lies... :-) */ return NET_RX_SUCCESS; /* Lies... :-) */
} }
struct packet_type pppoes_ptype = { static struct packet_type pppoes_ptype = {
.type = __constant_htons(ETH_P_PPP_SES), .type = __constant_htons(ETH_P_PPP_SES),
.func = pppoe_rcv, .func = pppoe_rcv,
.data = (void *)1,
}; };
struct packet_type pppoed_ptype = { static struct packet_type pppoed_ptype = {
.type = __constant_htons(ETH_P_PPP_DISC), .type = __constant_htons(ETH_P_PPP_DISC),
.func = pppoe_disc_rcv, .func = pppoe_disc_rcv,
.data = (void *)1,
}; };
/*********************************************************************** /***********************************************************************
...@@ -522,7 +529,7 @@ frees: sk_free(sk); ...@@ -522,7 +529,7 @@ frees: sk_free(sk);
goto out; goto out;
} }
int pppoe_release(struct socket *sock) static int pppoe_release(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct pppox_opt *po; struct pppox_opt *po;
...@@ -559,7 +566,7 @@ int pppoe_release(struct socket *sock) ...@@ -559,7 +566,7 @@ int pppoe_release(struct socket *sock)
} }
int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
int sockaddr_len, int flags) int sockaddr_len, int flags)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
...@@ -648,7 +655,7 @@ int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -648,7 +655,7 @@ int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
} }
int pppoe_getname(struct socket *sock, struct sockaddr *uaddr, static int pppoe_getname(struct socket *sock, struct sockaddr *uaddr,
int *usockaddr_len, int peer) int *usockaddr_len, int peer)
{ {
int len = sizeof(struct sockaddr_pppox); int len = sizeof(struct sockaddr_pppox);
...@@ -667,7 +674,7 @@ int pppoe_getname(struct socket *sock, struct sockaddr *uaddr, ...@@ -667,7 +674,7 @@ int pppoe_getname(struct socket *sock, struct sockaddr *uaddr,
} }
int pppoe_ioctl(struct socket *sock, unsigned int cmd, static int pppoe_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
...@@ -769,7 +776,7 @@ int pppoe_ioctl(struct socket *sock, unsigned int cmd, ...@@ -769,7 +776,7 @@ int pppoe_ioctl(struct socket *sock, unsigned int cmd,
} }
int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
int total_len) int total_len)
{ {
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
...@@ -847,7 +854,7 @@ int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, ...@@ -847,7 +854,7 @@ int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
* xmit function for internal use. * xmit function for internal use.
* *
***********************************************************************/ ***********************************************************************/
int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
{ {
struct pppox_opt *po = pppox_sk(sk); struct pppox_opt *po = pppox_sk(sk);
struct net_device *dev = po->pppoe_dev; struct net_device *dev = po->pppoe_dev;
...@@ -921,16 +928,18 @@ int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) ...@@ -921,16 +928,18 @@ int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
* sends PPP frame over PPPoE socket * sends PPP frame over PPPoE socket
* *
***********************************************************************/ ***********************************************************************/
int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb) static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb)
{ {
struct sock *sk = (struct sock *) chan->private; struct sock *sk = (struct sock *) chan->private;
return __pppoe_xmit(sk, skb); return __pppoe_xmit(sk, skb);
} }
struct ppp_channel_ops pppoe_chan_ops = { pppoe_xmit , NULL }; static struct ppp_channel_ops pppoe_chan_ops = {
.start_xmit = pppoe_xmit,
};
int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock, static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *m, int total_len, int flags) struct msghdr *m, int total_len, int flags)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
...@@ -1029,8 +1038,9 @@ static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos) ...@@ -1029,8 +1038,9 @@ static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos)
goto out; goto out;
} }
po = v; po = v;
po = po->next; if (po->next)
if (!po) { po = po->next;
else {
int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote); int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
while (++hash < PPPOE_HASH_SIZE) { while (++hash < PPPOE_HASH_SIZE) {
...@@ -1071,7 +1081,7 @@ static struct file_operations pppoe_seq_fops = { ...@@ -1071,7 +1081,7 @@ static struct file_operations pppoe_seq_fops = {
/* ->ioctl are set at pppox_create */ /* ->ioctl are set at pppox_create */
struct proto_ops pppoe_ops = { static struct proto_ops pppoe_ops = {
.family = AF_PPPOX, .family = AF_PPPOX,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.release = pppoe_release, .release = pppoe_release,
...@@ -1090,14 +1100,14 @@ struct proto_ops pppoe_ops = { ...@@ -1090,14 +1100,14 @@ struct proto_ops pppoe_ops = {
.mmap = sock_no_mmap .mmap = sock_no_mmap
}; };
struct pppox_proto pppoe_proto = { static struct pppox_proto pppoe_proto = {
.create = pppoe_create, .create = pppoe_create,
.ioctl = pppoe_ioctl, .ioctl = pppoe_ioctl,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
int __init pppoe_init(void) static int __init pppoe_init(void)
{ {
int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto);
...@@ -1125,7 +1135,7 @@ int __init pppoe_init(void) ...@@ -1125,7 +1135,7 @@ int __init pppoe_init(void)
goto out; goto out;
} }
void __exit pppoe_exit(void) static void __exit pppoe_exit(void)
{ {
unregister_pppox_proto(PX_PROTO_OE); unregister_pppox_proto(PX_PROTO_OE);
dev_remove_pack(&pppoes_ptype); dev_remove_pack(&pppoes_ptype);
......
...@@ -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 hlist_head 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);
......
...@@ -117,8 +117,9 @@ enum ...@@ -117,8 +117,9 @@ enum
#define XFRM_MSG_EXPIRE (XFRM_MSG_BASE + 8) #define XFRM_MSG_EXPIRE (XFRM_MSG_BASE + 8)
#define XFRM_MSG_UPDPOLICY (XFRM_MSG_BASE + 9) #define XFRM_MSG_UPDPOLICY (XFRM_MSG_BASE + 9)
#define XFRM_MSG_UPDSA (XFRM_MSG_BASE + 10)
#define XFRM_MSG_MAX (XFRM_MSG_UPDPOLICY+1) #define XFRM_MSG_MAX (XFRM_MSG_UPDSA+1)
struct xfrm_user_tmpl { struct xfrm_user_tmpl {
struct xfrm_id id; struct xfrm_id id;
...@@ -136,6 +137,7 @@ struct xfrm_encap_tmpl { ...@@ -136,6 +137,7 @@ struct xfrm_encap_tmpl {
__u16 encap_type; __u16 encap_type;
__u16 encap_sport; __u16 encap_sport;
__u16 encap_dport; __u16 encap_dport;
xfrm_address_t encap_oa;
}; };
/* Netlink message attributes. */ /* Netlink message attributes. */
......
...@@ -767,6 +767,7 @@ extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t ...@@ -767,6 +767,7 @@ extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t
unsigned short family); unsigned short family);
extern int xfrm_state_check_expire(struct xfrm_state *x); extern int xfrm_state_check_expire(struct xfrm_state *x);
extern void xfrm_state_insert(struct xfrm_state *x); extern void xfrm_state_insert(struct xfrm_state *x);
extern int xfrm_state_replace(struct xfrm_state *x, int excl);
extern int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb); extern int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb);
extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family);
extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
......
...@@ -47,15 +47,21 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, ...@@ -47,15 +47,21 @@ 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 hlist_node *node;
struct sock *s;
struct atm_vcc *walk; struct atm_vcc *walk;
for (walk = vcc->dev->vccs; walk; walk = walk->next) sk_for_each(s, node, &vcc_sklist) {
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 +71,16 @@ static int check_ci(struct atm_vcc *vcc,short vpi,int vci) ...@@ -65,17 +71,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 +95,7 @@ int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci) ...@@ -90,7 +95,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 +110,7 @@ int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci) ...@@ -105,7 +110,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;
} }
......
...@@ -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,29 @@ EXPORT_SYMBOL(br2684_ioctl_hook); ...@@ -157,6 +157,29 @@ EXPORT_SYMBOL(br2684_ioctl_hook);
#endif #endif
HLIST_HEAD(vcc_sklist);
rwlock_t vcc_sklist_lock = RW_LOCK_UNLOCKED;
void __vcc_insert_socket(struct sock *sk)
{
sk_add_node(sk, &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);
sk_del_node_init(sk);
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 +198,45 @@ static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) ...@@ -175,16 +198,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,42 +251,48 @@ int atm_create(struct socket *sock,int protocol,int family) ...@@ -199,42 +251,48 @@ 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) {
lock_sock(sk);
vcc_destroy_socket(sock->sk);
release_sock(sk);
sock_put(sk);
}
return 0; return 0;
} }
...@@ -289,7 +347,8 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, int vpi, ...@@ -289,7 +347,8 @@ static int __vcc_connect(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);
...@@ -313,7 +372,7 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, int vpi, ...@@ -313,7 +372,7 @@ static int __vcc_connect(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);
...@@ -327,7 +386,7 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, int vpi, ...@@ -327,7 +386,7 @@ static int __vcc_connect(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;
} }
} }
...@@ -371,7 +430,7 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) ...@@ -371,7 +430,7 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
dev = atm_dev_lookup(itf); dev = atm_dev_lookup(itf);
error = __vcc_connect(vcc, dev, vpi, vci); error = __vcc_connect(vcc, dev, vpi, vci);
if (error) { if (error) {
atm_dev_release(dev); atm_dev_put(dev);
return error; return error;
} }
} else { } else {
...@@ -385,7 +444,7 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) ...@@ -385,7 +444,7 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
spin_unlock(&atm_dev_lock); spin_unlock(&atm_dev_lock);
if (!__vcc_connect(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);
} }
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
#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 vcc_connect(struct socket *sock, int itf, short vpi, int vci); int vcc_connect(struct socket *sock, int itf, short vpi, int vci);
int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
int size, int flags); int size, int flags);
...@@ -24,7 +24,6 @@ int vcc_setsockopt(struct socket *sock, int level, int optname, char *optval, ...@@ -24,7 +24,6 @@ int vcc_setsockopt(struct socket *sock, int level, int optname, char *optval,
int vcc_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);
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);
......
...@@ -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);
......
...@@ -334,9 +334,8 @@ static int atm_devices_info(loff_t pos,char *buf) ...@@ -334,9 +334,8 @@ 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 hlist_node *node;
struct atm_dev *dev; struct sock *s;
struct list_head *p;
struct atm_vcc *vcc; struct atm_vcc *vcc;
int left, clip_info = 0; int left, clip_info = 0;
...@@ -349,25 +348,20 @@ static int atm_pvc_info(loff_t pos,char *buf) ...@@ -349,25 +348,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) { sk_for_each(s, node, &vcc_sklist) {
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) pvc_info(vcc,buf,clip_info);
if (vcc->sk->sk_family == PF_ATMPVC && read_unlock(&vcc_sklist_lock);
vcc->dev && !left--) {
pvc_info(vcc,buf,clip_info);
spin_unlock_irqrestore(&dev->lock, flags);
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 +372,9 @@ static int atm_pvc_info(loff_t pos,char *buf) ...@@ -378,10 +372,9 @@ 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 hlist_node *node;
struct sock *s;
int left; int left;
if (!pos) if (!pos)
...@@ -389,20 +382,16 @@ static int atm_vc_info(loff_t pos,char *buf) ...@@ -389,20 +382,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) { sk_for_each(s, node, &vcc_sklist) {
dev = list_entry(p, struct atm_dev, dev_list); vcc = atm_sk(s);
spin_lock_irqsave(&dev->lock, flags); if (!left--) {
for (vcc = dev->vccs; vcc; vcc = vcc->next) vc_info(vcc,buf);
if (!left--) { read_unlock(&vcc_sklist_lock);
vc_info(vcc,buf); return strlen(buf);
spin_unlock_irqrestore(&dev->lock, flags); }
spin_unlock(&atm_dev_lock);
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 +399,24 @@ static int atm_vc_info(loff_t pos,char *buf) ...@@ -410,29 +399,24 @@ 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 hlist_node *node;
struct atm_dev *dev; struct sock *s;
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) { sk_for_each(s, node, &vcc_sklist) {
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_ATMSVC && !left--) {
for (vcc = dev->vccs; vcc; vcc = vcc->next) svc_info(vcc,buf);
if (vcc->sk->sk_family == PF_ATMSVC && !left--) { read_unlock(&vcc_sklist_lock);
svc_info(vcc,buf); return strlen(buf);
spin_unlock_irqrestore(&dev->lock, flags); }
spin_unlock(&atm_dev_lock);
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)
{ {
...@@ -109,7 +105,7 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, ...@@ -109,7 +105,7 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr,
static struct proto_ops 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,
...@@ -131,7 +127,7 @@ static struct proto_ops pvc_proto_ops = { ...@@ -131,7 +127,7 @@ static struct proto_ops pvc_proto_ops = {
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);
} }
......
...@@ -23,11 +23,6 @@ ...@@ -23,11 +23,6 @@
#include "addr.h" #include "addr.h"
#ifndef NULL
#define NULL 0
#endif
LIST_HEAD(atm_devs); LIST_HEAD(atm_devs);
spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED; spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
...@@ -91,7 +86,7 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, ...@@ -91,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;
...@@ -100,7 +95,7 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, ...@@ -100,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++;
} }
} }
...@@ -402,78 +397,12 @@ int atm_dev_ioctl(unsigned int cmd, unsigned long arg) ...@@ -402,78 +397,12 @@ int atm_dev_ioctl(unsigned int cmd, unsigned long arg)
else else
error = 0; error = 0;
done: done:
atm_dev_release(dev); atm_dev_put(dev);
return error; return error;
} }
struct sock *alloc_atm_vcc_sk(int family)
{
struct sock *sk;
struct atm_vcc *vcc;
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 unlink_vcc(struct atm_vcc *vcc)
{
unsigned long flags;
if (vcc->dev) {
spin_lock_irqsave(&vcc->dev->lock, flags);
if (vcc->prev)
vcc->prev->next = vcc->next;
else
vcc->dev->vccs = vcc->next;
if (vcc->next)
vcc->next->prev = vcc->prev;
else
vcc->dev->last = vcc->prev;
spin_unlock_irqrestore(&vcc->dev->lock, flags);
}
}
void free_atm_vcc_sk(struct sock *sk)
{
unlink_vcc(atm_sk(sk));
sk_free(sk);
}
void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
{
unsigned long flags;
unlink_vcc(vcc);
vcc->dev = dev;
if (dev) {
spin_lock_irqsave(&dev->lock, flags);
vcc->next = NULL;
vcc->prev = dev->last;
if (dev->vccs)
dev->last->next = vcc;
else
dev->vccs = vcc;
dev->last = vcc;
spin_unlock_irqrestore(&dev->lock, flags);
}
}
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,6 @@ extern struct list_head atm_devs; ...@@ -14,8 +14,6 @@ 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);
void free_atm_vcc_sk(struct sock *sk);
int atm_dev_ioctl(unsigned int cmd, unsigned long arg); int atm_dev_ioctl(unsigned int cmd, unsigned long arg);
......
...@@ -200,26 +200,22 @@ void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type, ...@@ -200,26 +200,22 @@ 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;
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 hlist_node *node;
struct atm_dev *dev; struct sock *s;
struct list_head *p;
DPRINTK("sigd_close\n"); DPRINTK("sigd_close\n");
sigd = NULL; sigd = NULL;
...@@ -227,14 +223,14 @@ static void sigd_close(struct atm_vcc *vcc) ...@@ -227,14 +223,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) { sk_for_each(s, node, &vcc_sklist) {
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);
} }
...@@ -257,7 +253,8 @@ int sigd_attach(struct atm_vcc *vcc) ...@@ -257,7 +253,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);
......
...@@ -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); /* VCC pointer is used as a reference, so we must not free it
svc_disconnect(vcc); (thereby subjecting it to re-use) before all pending connections
/* VCC pointer is used as a reference, so we must not free it are closed */
(thereby subjecting it to re-use) before all pending connections sock_hold(sk);
are closed */ vcc_release(sock);
free_atm_vcc_sk(sock->sk); svc_disconnect(vcc);
sock_put(sk);
}
return 0; return 0;
} }
...@@ -542,7 +545,7 @@ static int svc_create(struct socket *sock,int protocol) ...@@ -542,7 +545,7 @@ 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;
......
...@@ -659,8 +659,12 @@ static void icmp_unreach(struct sk_buff *skb) ...@@ -659,8 +659,12 @@ static void icmp_unreach(struct sk_buff *skb)
inet_addr_type(iph->daddr) == RTN_BROADCAST) { inet_addr_type(iph->daddr) == RTN_BROADCAST) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP " printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP "
"error to a broadcast.\n", "type %u, code %u "
NIPQUAD(skb->nh.iph->saddr)); "error to a broadcast: %u.%u.%u.%u on %s\n",
NIPQUAD(iph->saddr),
icmph->type, icmph->code,
NIPQUAD(iph->daddr),
skb->dev->name);
goto out; goto out;
} }
......
...@@ -120,8 +120,8 @@ config IP_NF_MATCH_PKTTYPE ...@@ -120,8 +120,8 @@ config IP_NF_MATCH_PKTTYPE
tristate "Packet type match support" tristate "Packet type match support"
depends on IP_NF_IPTABLES depends on IP_NF_IPTABLES
help help
This patch allows you to match packet in accrodance Packet type matching allows you to match a packet by
to its "class", eg. BROADCAST, MULTICAST, ... its "class", eg. BROADCAST, MULTICAST, ...
Typical usage: Typical usage:
iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
......
...@@ -600,6 +600,22 @@ static int ipv6_get_mtu(struct net_device *dev) ...@@ -600,6 +600,22 @@ static int ipv6_get_mtu(struct net_device *dev)
return mtu; return mtu;
} }
static inline unsigned int ipv6_advmss(unsigned int mtu)
{
if (mtu < ip6_rt_min_advmss)
mtu = ip6_rt_min_advmss;
/*
* Maximal non-jumbo IPv6 payload is 65535 and
* corresponding MSS is 65535 - tcp_header_size.
* 65535 is also valid and means: "any MSS,
* rely only on pmtu discovery"
*/
if (mtu > 65535 - sizeof(struct tcphdr))
mtu = 65535;
return mtu;
}
static int ipv6_get_hoplimit(struct net_device *dev) static int ipv6_get_hoplimit(struct net_device *dev)
{ {
int hoplimit = ipv6_devconf.hop_limit; int hoplimit = ipv6_devconf.hop_limit;
...@@ -790,16 +806,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr) ...@@ -790,16 +806,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr)
if (!rt->u.dst.metrics[RTAX_MTU-1]) if (!rt->u.dst.metrics[RTAX_MTU-1])
rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev); rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
if (!rt->u.dst.metrics[RTAX_ADVMSS-1]) if (!rt->u.dst.metrics[RTAX_ADVMSS-1])
rt->u.dst.metrics[RTAX_ADVMSS-1] = rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&rt->u.dst));
max_t(unsigned int, dst_pmtu(&rt->u.dst) - 60,
ip6_rt_min_advmss);
/* Maximal non-jumbo IPv6 payload is 65535 and corresponding
MSS is 65535 - tcp_header_size. 65535 is also valid and
means: "any MSS, rely only on pmtu discovery"
*/
if (dst_metric(&rt->u.dst, RTAX_ADVMSS) > 65535-20)
rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535;
rt->u.dst.dev = dev; rt->u.dst.dev = dev;
return rt6_ins(rt, nlh, _rtattr); return rt6_ins(rt, nlh, _rtattr);
...@@ -952,9 +959,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, ...@@ -952,9 +959,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
nrt->rt6i_nexthop = neigh_clone(neigh); nrt->rt6i_nexthop = neigh_clone(neigh);
/* Reset pmtu, it may be better */ /* Reset pmtu, it may be better */
nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);
nrt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, dst_pmtu(&nrt->u.dst) - 60, ip6_rt_min_advmss); nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&nrt->u.dst));
if (nrt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20)
nrt->u.dst.metrics[RTAX_ADVMSS-1] = 65535;
if (rt6_ins(nrt, NULL, NULL)) if (rt6_ins(nrt, NULL, NULL))
goto out; goto out;
...@@ -1214,9 +1219,7 @@ int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev) ...@@ -1214,9 +1219,7 @@ int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev)
rt->u.dst.output = ip6_output; rt->u.dst.output = ip6_output;
rt->rt6i_dev = &loopback_dev; rt->rt6i_dev = &loopback_dev;
rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, dst_pmtu(&rt->u.dst) - 60, ip6_rt_min_advmss); rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&rt->u.dst));
if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20)
rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535;
rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ipv6_get_hoplimit(rt->rt6i_dev); rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ipv6_get_hoplimit(rt->rt6i_dev);
rt->u.dst.obsolete = -1; rt->u.dst.obsolete = -1;
...@@ -1312,9 +1315,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) ...@@ -1312,9 +1315,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
(dst_pmtu(&rt->u.dst) < arg->mtu && (dst_pmtu(&rt->u.dst) < arg->mtu &&
dst_pmtu(&rt->u.dst) == idev->cnf.mtu6))) dst_pmtu(&rt->u.dst) == idev->cnf.mtu6)))
rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu; rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu;
rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, arg->mtu - 60, ip6_rt_min_advmss); rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(arg->mtu);
if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20)
rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535;
return 0; return 0;
} }
......
...@@ -1213,7 +1213,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, ...@@ -1213,7 +1213,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
struct sk_buff *out_skb; struct sk_buff *out_skb;
struct sadb_msg *out_hdr; struct sadb_msg *out_hdr;
struct xfrm_state *x; struct xfrm_state *x;
struct xfrm_state *x1; int err;
xfrm_probe_algs(); xfrm_probe_algs();
...@@ -1221,31 +1221,11 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, ...@@ -1221,31 +1221,11 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
if (IS_ERR(x)) if (IS_ERR(x))
return PTR_ERR(x); return PTR_ERR(x);
/* XXX there is race condition */ err = xfrm_state_replace(x, hdr->sadb_msg_type == SADB_ADD);
x1 = pfkey_xfrm_state_lookup(hdr, ext_hdrs); if (err < 0) {
if (!x1) {
x1 = xfrm_find_acq(x->props.mode, x->props.reqid, x->id.proto,
&x->id.daddr,
&x->props.saddr, 0, x->props.family);
if (x1 && x1->id.spi != x->id.spi && x1->id.spi) {
xfrm_state_put(x1);
x1 = NULL;
}
}
if (x1 && ((x1->id.spi && hdr->sadb_msg_type == SADB_ADD) ||
(hdr->sadb_msg_type == SADB_UPDATE && xfrm_state_kern(x1)))) {
x->km.state = XFRM_STATE_DEAD; x->km.state = XFRM_STATE_DEAD;
xfrm_state_put(x); xfrm_state_put(x);
xfrm_state_put(x1); return err;
return -EEXIST;
}
xfrm_state_insert(x);
if (x1) {
xfrm_state_delete(x1);
xfrm_state_put(x1);
} }
out_skb = pfkey_xfrm_state2msg(x, 0, 3); out_skb = pfkey_xfrm_state2msg(x, 0, 3);
......
...@@ -306,6 +306,7 @@ EXPORT_SYMBOL(xfrm_state_alloc); ...@@ -306,6 +306,7 @@ EXPORT_SYMBOL(xfrm_state_alloc);
EXPORT_SYMBOL(__xfrm_state_destroy); EXPORT_SYMBOL(__xfrm_state_destroy);
EXPORT_SYMBOL(xfrm_state_find); EXPORT_SYMBOL(xfrm_state_find);
EXPORT_SYMBOL(xfrm_state_insert); EXPORT_SYMBOL(xfrm_state_insert);
EXPORT_SYMBOL(xfrm_state_replace);
EXPORT_SYMBOL(xfrm_state_check_expire); EXPORT_SYMBOL(xfrm_state_check_expire);
EXPORT_SYMBOL(xfrm_state_check_space); EXPORT_SYMBOL(xfrm_state_check_space);
EXPORT_SYMBOL(xfrm_state_lookup); EXPORT_SYMBOL(xfrm_state_lookup);
......
...@@ -515,7 +515,7 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base, ...@@ -515,7 +515,7 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
for (sp = &data->ht[h1]; (s=*sp) != NULL; sp = &s->next) { for (sp = &data->ht[h1]; (s=*sp) != NULL; sp = &s->next) {
if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] && if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] &&
pinfo->protocol == s->protocol && pinfo && pinfo->protocol == s->protocol &&
memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0
#if RSVP_DST_LEN == 4 #if RSVP_DST_LEN == 4
&& dst[0] == s->dst[0] && dst[0] == s->dst[0]
...@@ -557,9 +557,12 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base, ...@@ -557,9 +557,12 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base,
goto errout; goto errout;
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
memcpy(s->dst, dst, sizeof(s->dst)); memcpy(s->dst, dst, sizeof(s->dst));
s->dpi = pinfo->dpi;
s->protocol = pinfo->protocol; if (pinfo) {
s->tunnelid = pinfo->tunnelid; s->dpi = pinfo->dpi;
s->protocol = pinfo->protocol;
s->tunnelid = pinfo->tunnelid;
}
for (sp = &data->ht[h1]; *sp; sp = &(*sp)->next) { for (sp = &data->ht[h1]; *sp; sp = &(*sp)->next) {
if (((*sp)->dpi.mask&s->dpi.mask) != s->dpi.mask) if (((*sp)->dpi.mask&s->dpi.mask) != s->dpi.mask)
break; break;
......
...@@ -67,8 +67,9 @@ ...@@ -67,8 +67,9 @@
struct teql_master struct teql_master
{ {
struct Qdisc_ops qops; struct Qdisc_ops qops;
struct net_device dev; struct net_device *dev;
struct Qdisc *slaves; struct Qdisc *slaves;
struct list_head master_list;
struct net_device_stats stats; struct net_device_stats stats;
}; };
...@@ -122,13 +123,13 @@ teql_dequeue(struct Qdisc* sch) ...@@ -122,13 +123,13 @@ teql_dequeue(struct Qdisc* sch)
skb = __skb_dequeue(&dat->q); skb = __skb_dequeue(&dat->q);
if (skb == NULL) { if (skb == NULL) {
struct net_device *m = dat->m->dev.qdisc->dev; struct net_device *m = dat->m->dev->qdisc->dev;
if (m) { if (m) {
dat->m->slaves = sch; dat->m->slaves = sch;
netif_wake_queue(m); netif_wake_queue(m);
} }
} }
sch->q.qlen = dat->q.qlen + dat->m->dev.qdisc->q.qlen; sch->q.qlen = dat->q.qlen + dat->m->dev->qdisc->q.qlen;
return skb; return skb;
} }
...@@ -165,9 +166,9 @@ teql_destroy(struct Qdisc* sch) ...@@ -165,9 +166,9 @@ teql_destroy(struct Qdisc* sch)
master->slaves = NEXT_SLAVE(q); master->slaves = NEXT_SLAVE(q);
if (q == master->slaves) { if (q == master->slaves) {
master->slaves = NULL; master->slaves = NULL;
spin_lock_bh(&master->dev.queue_lock); spin_lock_bh(&master->dev->queue_lock);
qdisc_reset(master->dev.qdisc); qdisc_reset(master->dev->qdisc);
spin_unlock_bh(&master->dev.queue_lock); spin_unlock_bh(&master->dev->queue_lock);
} }
} }
skb_queue_purge(&dat->q); skb_queue_purge(&dat->q);
...@@ -185,10 +186,10 @@ static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt) ...@@ -185,10 +186,10 @@ static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt)
struct teql_master *m = (struct teql_master*)sch->ops; struct teql_master *m = (struct teql_master*)sch->ops;
struct teql_sched_data *q = (struct teql_sched_data *)sch->data; struct teql_sched_data *q = (struct teql_sched_data *)sch->data;
if (dev->hard_header_len > m->dev.hard_header_len) if (dev->hard_header_len > m->dev->hard_header_len)
return -EINVAL; return -EINVAL;
if (&m->dev == dev) if (m->dev == dev)
return -ELOOP; return -ELOOP;
q->m = m; q->m = m;
...@@ -196,29 +197,29 @@ static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt) ...@@ -196,29 +197,29 @@ static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt)
skb_queue_head_init(&q->q); skb_queue_head_init(&q->q);
if (m->slaves) { if (m->slaves) {
if (m->dev.flags & IFF_UP) { if (m->dev->flags & IFF_UP) {
if ((m->dev.flags&IFF_POINTOPOINT && !(dev->flags&IFF_POINTOPOINT)) if ((m->dev->flags&IFF_POINTOPOINT && !(dev->flags&IFF_POINTOPOINT))
|| (m->dev.flags&IFF_BROADCAST && !(dev->flags&IFF_BROADCAST)) || (m->dev->flags&IFF_BROADCAST && !(dev->flags&IFF_BROADCAST))
|| (m->dev.flags&IFF_MULTICAST && !(dev->flags&IFF_MULTICAST)) || (m->dev->flags&IFF_MULTICAST && !(dev->flags&IFF_MULTICAST))
|| dev->mtu < m->dev.mtu) || dev->mtu < m->dev->mtu)
return -EINVAL; return -EINVAL;
} else { } else {
if (!(dev->flags&IFF_POINTOPOINT)) if (!(dev->flags&IFF_POINTOPOINT))
m->dev.flags &= ~IFF_POINTOPOINT; m->dev->flags &= ~IFF_POINTOPOINT;
if (!(dev->flags&IFF_BROADCAST)) if (!(dev->flags&IFF_BROADCAST))
m->dev.flags &= ~IFF_BROADCAST; m->dev->flags &= ~IFF_BROADCAST;
if (!(dev->flags&IFF_MULTICAST)) if (!(dev->flags&IFF_MULTICAST))
m->dev.flags &= ~IFF_MULTICAST; m->dev->flags &= ~IFF_MULTICAST;
if (dev->mtu < m->dev.mtu) if (dev->mtu < m->dev->mtu)
m->dev.mtu = dev->mtu; m->dev->mtu = dev->mtu;
} }
q->next = NEXT_SLAVE(m->slaves); q->next = NEXT_SLAVE(m->slaves);
NEXT_SLAVE(m->slaves) = sch; NEXT_SLAVE(m->slaves) = sch;
} else { } else {
q->next = sch; q->next = sch;
m->slaves = sch; m->slaves = sch;
m->dev.mtu = dev->mtu; m->dev->mtu = dev->mtu;
m->dev.flags = (m->dev.flags&~FMASK)|(dev->flags&FMASK); m->dev->flags = (m->dev->flags&~FMASK)|(dev->flags&FMASK);
} }
return 0; return 0;
} }
...@@ -379,9 +380,9 @@ static int teql_master_open(struct net_device *dev) ...@@ -379,9 +380,9 @@ static int teql_master_open(struct net_device *dev)
flags &= ~IFF_MULTICAST; flags &= ~IFF_MULTICAST;
} while ((q = NEXT_SLAVE(q)) != m->slaves); } while ((q = NEXT_SLAVE(q)) != m->slaves);
m->dev.mtu = mtu; m->dev->mtu = mtu;
m->dev.flags = (m->dev.flags&~FMASK) | flags; m->dev->flags = (m->dev->flags&~FMASK) | flags;
netif_start_queue(&m->dev); netif_start_queue(m->dev);
return 0; return 0;
} }
...@@ -417,8 +418,30 @@ static int teql_master_mtu(struct net_device *dev, int new_mtu) ...@@ -417,8 +418,30 @@ static int teql_master_mtu(struct net_device *dev, int new_mtu)
return 0; return 0;
} }
static int teql_master_init(struct net_device *dev) static __init int teql_master_init(struct net_device *dev)
{ {
struct teql_master *master = dev->priv;
struct Qdisc_ops *ops = &master->qops;
master->dev = dev;
strlcpy(ops->id, dev->name, IFNAMSIZ);
ops->priv_size = sizeof(struct teql_sched_data);
ops->enqueue = teql_enqueue;
ops->dequeue = teql_dequeue;
ops->requeue = teql_requeue;
ops->init = teql_qdisc_init;
ops->reset = teql_reset;
ops->destroy = teql_destroy;
ops->owner = THIS_MODULE;
return register_qdisc(ops);
}
static __init void teql_master_setup(struct net_device *dev)
{
dev->init = teql_master_init;
dev->open = teql_master_open; dev->open = teql_master_open;
dev->hard_start_xmit = teql_master_xmit; dev->hard_start_xmit = teql_master_xmit;
dev->stop = teql_master_close; dev->stop = teql_master_close;
...@@ -429,62 +452,58 @@ static int teql_master_init(struct net_device *dev) ...@@ -429,62 +452,58 @@ static int teql_master_init(struct net_device *dev)
dev->tx_queue_len = 100; dev->tx_queue_len = 100;
dev->flags = IFF_NOARP; dev->flags = IFF_NOARP;
dev->hard_header_len = LL_MAX_HEADER; dev->hard_header_len = LL_MAX_HEADER;
return 0; SET_MODULE_OWNER(dev);
} }
static struct teql_master the_master = { static LIST_HEAD(master_dev_list);
{ static spinlock_t master_dev_lock = SPIN_LOCK_UNLOCKED;
.next = NULL, static int max_equalizers = 1;
.cl_ops = NULL, MODULE_PARM(max_equalizers, "i");
.id = "", MODULE_PARM_DESC(max_equalizers, "Max number of link equalizers");
.priv_size = sizeof(struct teql_sched_data),
.enqueue = teql_enqueue,
.dequeue = teql_dequeue,
.requeue = teql_requeue,
.drop = NULL,
.init = teql_qdisc_init,
.reset = teql_reset,
.destroy = teql_destroy,
.dump = NULL,
.owner = THIS_MODULE,
},};
#ifdef MODULE
int init_module(void)
#else
int __init teql_init(void) int __init teql_init(void)
#endif
{ {
int err; int i;
int err = 0;
rtnl_lock();
for (i = 0; i < max_equalizers; i++) {
the_master.dev.priv = (void*)&the_master; struct net_device *dev;
err = dev_alloc_name(&the_master.dev, "teql%d"); struct teql_master *master;
if (err < 0)
return err; dev = alloc_netdev(sizeof(struct teql_master),
memcpy(the_master.qops.id, the_master.dev.name, IFNAMSIZ); "teql%d", teql_master_setup);
the_master.dev.init = teql_master_init; if (!dev)
return -ENOMEM;
SET_MODULE_OWNER(&the_master.dev);
err = register_netdevice(&the_master.dev); if ((err = register_netdev(dev)))
if (err == 0) { goto out;
err = register_qdisc(&the_master.qops);
if (err) master = dev->priv;
unregister_netdevice(&the_master.dev); spin_lock(&master_dev_lock);
list_add_tail(&master->master_list, &master_dev_list);
spin_unlock(&master_dev_lock);
} }
rtnl_unlock(); out:
return err; return err;
} }
#ifdef MODULE static void __exit teql_exit(void)
void cleanup_module(void)
{ {
rtnl_lock(); struct teql_master *master, *nxt;
unregister_qdisc(&the_master.qops);
unregister_netdevice(&the_master.dev); spin_lock(&master_dev_lock);
rtnl_unlock(); list_for_each_entry_safe(master, nxt, &master_dev_list, master_list) {
list_del(&master->master_list);
unregister_qdisc(&master->qops);
unregister_netdev(master->dev);
kfree(master->dev);
}
spin_unlock(&master_dev_lock);
} }
#endif
module_init(teql_init);
module_exit(teql_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -370,11 +370,10 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, ...@@ -370,11 +370,10 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
return x; return x;
} }
void xfrm_state_insert(struct xfrm_state *x) static void __xfrm_state_insert(struct xfrm_state *x)
{ {
unsigned h = xfrm_dst_hash(&x->id.daddr, x->props.family); unsigned h = xfrm_dst_hash(&x->id.daddr, x->props.family);
spin_lock_bh(&xfrm_state_lock);
list_add(&x->bydst, xfrm_state_bydst+h); list_add(&x->bydst, xfrm_state_bydst+h);
xfrm_state_hold(x); xfrm_state_hold(x);
...@@ -386,10 +385,62 @@ void xfrm_state_insert(struct xfrm_state *x) ...@@ -386,10 +385,62 @@ void xfrm_state_insert(struct xfrm_state *x)
if (!mod_timer(&x->timer, jiffies + HZ)) if (!mod_timer(&x->timer, jiffies + HZ))
xfrm_state_hold(x); xfrm_state_hold(x);
spin_unlock_bh(&xfrm_state_lock);
wake_up(&km_waitq); wake_up(&km_waitq);
} }
void xfrm_state_insert(struct xfrm_state *x)
{
spin_lock_bh(&xfrm_state_lock);
__xfrm_state_insert(x);
spin_unlock_bh(&xfrm_state_lock);
}
int xfrm_state_replace(struct xfrm_state *x, int excl)
{
struct xfrm_state_afinfo *afinfo;
struct xfrm_state *x1;
int err;
afinfo = xfrm_state_get_afinfo(x->props.family);
x1 = NULL;
spin_lock_bh(&xfrm_state_lock);
if (afinfo) {
x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto);
if (!x1) {
x1 = afinfo->find_acq(
x->props.mode, x->props.reqid, x->id.proto,
&x->id.daddr, &x->props.saddr, 0);
if (x1 && x1->id.spi != x->id.spi && x1->id.spi) {
xfrm_state_put(x1);
x1 = NULL;
}
}
if (x1 && (excl ? x1->id.spi : xfrm_state_kern(x1))) {
xfrm_state_put(x1);
x1 = NULL;
err = -EEXIST;
goto out;
}
}
__xfrm_state_insert(x);
err = 0;
out:
spin_unlock_bh(&xfrm_state_lock);
if (x1) {
xfrm_state_delete(x1);
xfrm_state_put(x1);
}
xfrm_state_put_afinfo(afinfo);
return err;
}
int xfrm_state_check_expire(struct xfrm_state *x) int xfrm_state_check_expire(struct xfrm_state *x)
{ {
if (!x->curlft.use_time) if (!x->curlft.use_time)
......
...@@ -249,7 +249,7 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, ...@@ -249,7 +249,7 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{ {
struct xfrm_usersa_info *p = NLMSG_DATA(nlh); struct xfrm_usersa_info *p = NLMSG_DATA(nlh);
struct xfrm_state *x, *x1; struct xfrm_state *x;
int err; int err;
err = verify_newsa_info(p, (struct rtattr **) xfrma); err = verify_newsa_info(p, (struct rtattr **) xfrma);
...@@ -260,16 +260,13 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) ...@@ -260,16 +260,13 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
if (!x) if (!x)
return err; return err;
x1 = xfrm_state_lookup(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); err = xfrm_state_replace(x, nlh->nlmsg_type == XFRM_MSG_NEWSA);
if (x1) { if (err < 0) {
x->km.state = XFRM_STATE_DEAD;
xfrm_state_put(x); xfrm_state_put(x);
xfrm_state_put(x1);
return -EEXIST;
} }
xfrm_state_insert(x); return err;
return 0;
} }
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
...@@ -801,6 +798,7 @@ static const int xfrm_msg_min[(XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)] = { ...@@ -801,6 +798,7 @@ static const int xfrm_msg_min[(XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)] = {
NLMSG_LENGTH(sizeof(struct xfrm_user_acquire)), /* ACQUIRE */ NLMSG_LENGTH(sizeof(struct xfrm_user_acquire)), /* ACQUIRE */
NLMSG_LENGTH(sizeof(struct xfrm_user_expire)), /* EXPIRE */ NLMSG_LENGTH(sizeof(struct xfrm_user_expire)), /* EXPIRE */
NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* UPD POLICY */ NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* UPD POLICY */
NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)), /* UPD SA */
}; };
static struct xfrm_link { static struct xfrm_link {
...@@ -823,6 +821,7 @@ static struct xfrm_link { ...@@ -823,6 +821,7 @@ static struct xfrm_link {
{}, {},
{}, {},
{ .doit = xfrm_add_policy }, { .doit = xfrm_add_policy },
{ .doit = xfrm_add_sa, },
}; };
static int xfrm_done(struct netlink_callback *cb) static int xfrm_done(struct netlink_callback *cb)
......
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