## Automatically generated incremental diff ## From: linux-2.5.69-bk3 ## To: linux-2.5.69-bk4 ## Robot: $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $ diff -urN linux-2.5.69-bk3/Makefile linux-2.5.69-bk4/Makefile --- linux-2.5.69-bk3/Makefile 2003-05-09 04:41:27.000000000 -0700 +++ linux-2.5.69-bk4/Makefile 2003-05-09 04:41:31.000000000 -0700 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 69 -EXTRAVERSION = -bk3 +EXTRAVERSION = -bk4 # *DOCUMENTATION* # To see a list of typical targets execute "make help" diff -urN linux-2.5.69-bk3/drivers/atm/eni.c linux-2.5.69-bk4/drivers/atm/eni.c --- linux-2.5.69-bk3/drivers/atm/eni.c 2003-05-04 16:53:07.000000000 -0700 +++ linux-2.5.69-bk4/drivers/atm/eni.c 2003-05-09 04:41:32.000000000 -0700 @@ -1100,9 +1100,9 @@ dma_rd = eni_in(MID_DMA_RD_TX); dma_size = 3; /* JK for descriptor and final fill, plus final size mis-alignment fix */ -DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt); - if (!ATM_SKB(skb)->iovcnt) dma_size += 5; - else dma_size += 5*ATM_SKB(skb)->iovcnt; +DPRINTK("iovcnt = %d\n",skb_shinfo(skb)->nr_frags); + if (!skb_shinfo(skb)->nr_frags) dma_size += 5; + else dma_size += 5*(skb_shinfo(skb)->nr_frags+1); if (dma_size > TX_DMA_BUF) { printk(KERN_CRIT DEV_LABEL "(itf %d): needs %d DMA entries " "(got only %d)\n",vcc->dev->number,dma_size,TX_DMA_BUF); @@ -1123,15 +1123,20 @@ MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) | MID_DT_JK; j++; - if (!ATM_SKB(skb)->iovcnt) + if (!skb_shinfo(skb)->nr_frags) if (aal5) put_dma(tx->index,eni_dev->dma,&j,paddr,skb->len); else put_dma(tx->index,eni_dev->dma,&j,paddr+4,skb->len-4); else { DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */ - for (i = 0; i < ATM_SKB(skb)->iovcnt; i++) - put_dma(tx->index,eni_dev->dma,&j,(unsigned long) - ((struct iovec *) skb->data)[i].iov_base, - ((struct iovec *) skb->data)[i].iov_len); + for (i = -1; i < skb_shinfo(skb)->nr_frags; i++) + if (i == -1) + put_dma(tx->index,eni_dev->dma,&j,(unsigned long) + skb->data, + skb->len - skb->data_len); + else + put_dma(tx->index,eni_dev->dma,&j,(unsigned long) + skb_shinfo(skb)->frags[i].page + skb_shinfo(skb)->frags[i].page_offset, + skb_shinfo(skb)->frags[i].size); } if (skb->len & 3) put_dma(tx->index,eni_dev->dma,&j,zeroes,4-(skb->len & 3)); diff -urN linux-2.5.69-bk3/drivers/atm/he.c linux-2.5.69-bk4/drivers/atm/he.c --- linux-2.5.69-bk3/drivers/atm/he.c 2003-05-09 04:41:27.000000000 -0700 +++ linux-2.5.69-bk4/drivers/atm/he.c 2003-05-09 04:41:32.000000000 -0700 @@ -51,7 +51,7 @@ 4096 supported 'connections' group 0 is used for all traffic interrupt queue 0 is used for all interrupts - aal0 support for receive only + aal0 support (based on work from ulrich.u.muller@nokia.com) */ @@ -114,16 +114,13 @@ #include -#define hprintk(fmt,args...) printk(DEV_LABEL "%d: " fmt, he_dev->number, args) -#define hprintk1(fmt) printk(DEV_LABEL "%d: " fmt, he_dev->number) +#define hprintk(fmt,args...) printk(KERN_ERR DEV_LABEL "%d: " fmt, he_dev->number, ##args) #undef DEBUG #ifdef DEBUG #define HPRINTK(fmt,args...) hprintk(fmt,args) -#define HPRINTK1(fmt) hprintk1(fmt) #else -#define HPRINTK(fmt,args...) -#define HPRINTK1(fmt,args...) +#define HPRINTK(fmt,args...) do { } while(0) #endif /* DEBUG */ @@ -131,10 +128,6 @@ static char *version = "$Id: he.c,v 1.18 2003/05/06 22:57:15 chas Exp $"; -/* defines */ -#define ALIGN_ADDRESS(addr, alignment) \ - ((((unsigned long) (addr)) + (((unsigned long) (alignment)) - 1)) & ~(((unsigned long) (alignment)) - 1)) - /* declarations */ static int he_open(struct atm_vcc *vcc, short vpi, int vci); @@ -555,7 +548,7 @@ CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), &he_dev->tpdrq_phys); if (he_dev->tpdrq_base == NULL) { - hprintk1("failed to alloc tpdrq\n"); + hprintk("failed to alloc tpdrq\n"); return -ENOMEM; } memset(he_dev->tpdrq_base, 0, @@ -799,14 +792,14 @@ #endif if (he_dev->rbps_pool == NULL) { - hprintk1("unable to create rbps pages\n"); + hprintk("unable to create rbps pages\n"); return -ENOMEM; } #else /* !USE_RBPS_POOL */ he_dev->rbps_pages = pci_alloc_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE * CONFIG_RBPS_BUFSIZE, &he_dev->rbps_pages_phys); if (he_dev->rbps_pages == NULL) { - hprintk1("unable to create rbps page pool\n"); + hprintk("unable to create rbps page pool\n"); return -ENOMEM; } #endif /* USE_RBPS_POOL */ @@ -815,7 +808,7 @@ CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys); if (he_dev->rbps_base == NULL) { - hprintk1("failed to alloc rbps\n"); + hprintk("failed to alloc rbps\n"); return -ENOMEM; } memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp)); @@ -871,7 +864,7 @@ #endif if (he_dev->rbpl_pool == NULL) { - hprintk1("unable to create rbpl pool\n"); + hprintk("unable to create rbpl pool\n"); return -ENOMEM; } #else /* !USE_RBPL_POOL */ @@ -879,7 +872,7 @@ CONFIG_RBPL_SIZE * CONFIG_RBPL_BUFSIZE, &he_dev->rbpl_pages_phys); if (he_dev->rbpl_pages == NULL) { - hprintk1("unable to create rbpl pages\n"); + hprintk("unable to create rbpl pages\n"); return -ENOMEM; } #endif /* USE_RBPL_POOL */ @@ -888,7 +881,7 @@ CONFIG_RBPL_SIZE * sizeof(struct he_rbp), &he_dev->rbpl_phys); if (he_dev->rbpl_base == NULL) { - hprintk1("failed to alloc rbpl\n"); + hprintk("failed to alloc rbpl\n"); return -ENOMEM; } memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp)); @@ -932,7 +925,7 @@ CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys); if (he_dev->rbrq_base == NULL) { - hprintk1("failed to allocate rbrq\n"); + hprintk("failed to allocate rbrq\n"); return -ENOMEM; } memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq)); @@ -945,7 +938,7 @@ G0_RBRQ_Q + (group * 16)); if (irq_coalesce) { - hprintk1("coalescing interrupts\n"); + hprintk("coalescing interrupts\n"); he_writel(he_dev, RBRQ_TIME(768) | RBRQ_COUNT(7), G0_RBRQ_I + (group * 16)); } @@ -959,7 +952,7 @@ CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), &he_dev->tbrq_phys); if (he_dev->tbrq_base == NULL) { - hprintk1("failed to allocate tbrq\n"); + hprintk("failed to allocate tbrq\n"); return -ENOMEM; } memset(he_dev->tbrq_base, 0, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq)); @@ -986,7 +979,7 @@ (CONFIG_IRQ_SIZE+1) * sizeof(struct he_irq), &he_dev->irq_phys); if (he_dev->irq_base == NULL) { - hprintk1("failed to allocate irq\n"); + hprintk("failed to allocate irq\n"); return -ENOMEM; } he_dev->irq_tailoffset = (unsigned *) @@ -1074,32 +1067,32 @@ /* 4.3 pci bus controller-specific initialization */ if (pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0) != 0) { - hprintk1("can't read GEN_CNTL_0\n"); + hprintk("can't read GEN_CNTL_0\n"); return -EINVAL; } gen_cntl_0 |= (MRL_ENB | MRM_ENB | IGNORE_TIMEOUT); if (pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0) != 0) { - hprintk1("can't write GEN_CNTL_0.\n"); + hprintk("can't write GEN_CNTL_0.\n"); return -EINVAL; } if (pci_read_config_word(pci_dev, PCI_COMMAND, &command) != 0) { - hprintk1("can't read PCI_COMMAND.\n"); + hprintk("can't read PCI_COMMAND.\n"); return -EINVAL; } command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE); if (pci_write_config_word(pci_dev, PCI_COMMAND, command) != 0) { - hprintk1("can't enable memory.\n"); + hprintk("can't enable memory.\n"); return -EINVAL; } if (pci_read_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, &cache_size)) { - hprintk1("can't read cache line size?\n"); + hprintk("can't read cache line size?\n"); return -EINVAL; } @@ -1112,7 +1105,7 @@ if (pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &timer)) { - hprintk1("can't read latency timer?\n"); + hprintk("can't read latency timer?\n"); return -EINVAL; } @@ -1134,7 +1127,7 @@ } if (!(he_dev->membase = (unsigned long) ioremap(he_dev->membase, HE_REGMAP_SIZE))) { - hprintk1("can't set up page mapping\n"); + hprintk("can't set up page mapping\n"); return -EINVAL; } @@ -1146,7 +1139,7 @@ status = he_readl(he_dev, RESET_CNTL); if ((status & BOARD_RST_STATUS) == 0) { - hprintk1("reset failed\n"); + hprintk("reset failed\n"); return -EINVAL; } @@ -1159,11 +1152,11 @@ if (disable64 == 1) { - hprintk1("disabling 64-bit pci bus transfers\n"); + hprintk("disabling 64-bit pci bus transfers\n"); gen_cntl_0 &= ~ENBL_64; } - if (gen_cntl_0 & ENBL_64) hprintk1("64-bit transfers enabled\n"); + if (gen_cntl_0 & ENBL_64) hprintk("64-bit transfers enabled\n"); pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); @@ -1535,7 +1528,7 @@ #endif if (he_dev->tpd_pool == NULL) { - hprintk1("unable to create tpd pci_pool\n"); + hprintk("unable to create tpd pci_pool\n"); return -ENOMEM; } @@ -1592,7 +1585,7 @@ sizeof(struct he_hsp), &he_dev->hsp_phys); if (he_dev->hsp == NULL) { - hprintk1("failed to allocate host status page\n"); + hprintk("failed to allocate host status page\n"); return -ENOMEM; } memset(he_dev->hsp, 0, sizeof(struct he_hsp)); @@ -1632,7 +1625,7 @@ (1 << (he_dev->vcibits + he_dev->vpibits)), GFP_KERNEL); if (he_dev->he_vcc_table == NULL) { - hprintk1("failed to alloc he_vcc_table\n"); + hprintk("failed to alloc he_vcc_table\n"); return -ENOMEM; } memset(he_dev->he_vcc_table, 0, sizeof(struct he_vcc_table) * @@ -1868,7 +1861,7 @@ struct sk_buff *skb; struct atm_vcc *vcc = NULL; struct he_vcc *he_vcc; - struct iovec *iov; + struct he_iovec *iov; int pdus_assembled = 0; int updated = 0; @@ -1934,7 +1927,7 @@ goto return_host_buffers; } - he_vcc->iov_tail->iov_base = (void *) RBRQ_ADDR(he_dev->rbrq_head); + he_vcc->iov_tail->iov_base = RBRQ_ADDR(he_dev->rbrq_head); he_vcc->iov_tail->iov_len = buf_len; he_vcc->pdu_len += buf_len; ++he_vcc->iov_tail; @@ -1948,7 +1941,7 @@ } #ifdef notdef - if (he_vcc->iov_tail - he_vcc->iov_head > 32) + if ((he_vcc->iov_tail - he_vcc->iov_head) > HE_MAXIOV) { hprintk("iovec full! cid 0x%x\n", cid); goto return_host_buffers; @@ -2000,7 +1993,7 @@ iov < he_vcc->iov_tail; ++iov) { #ifdef USE_RBPS - if ((u32)iov->iov_base & RBP_SMALLBUF) + if (iov->iov_base & RBP_SMALLBUF) memcpy(skb_put(skb, iov->iov_len), he_dev->rbps_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len); else @@ -2055,7 +2048,7 @@ iov < he_vcc->iov_tail; ++iov) { #ifdef USE_RBPS - if ((u32)iov->iov_base & RBP_SMALLBUF) + if (iov->iov_base & RBP_SMALLBUF) rbp = &he_dev->rbps_base[RBP_INDEX(iov->iov_base)]; else #endif @@ -2309,13 +2302,13 @@ he_dev->atm_dev->phy->interrupt(he_dev->atm_dev); HE_SPIN_LOCK(he_dev, flags); #endif - HPRINTK1("phy interrupt\n"); + HPRINTK("phy interrupt\n"); break; case ITYPE_OTHER: switch (type|group) { case ITYPE_PARITY: - hprintk1("parity error\n"); + hprintk("parity error\n"); break; case ITYPE_ABORT: hprintk("abort 0x%x\n", he_readl(he_dev, ABORT_ADDR)); @@ -2387,7 +2380,7 @@ if (he_dev->irq_tail == he_dev->irq_head) { - HPRINTK1("tailoffset not updated?\n"); + HPRINTK("tailoffset not updated?\n"); he_dev->irq_tail = (struct he_irq *) ((unsigned long)he_dev->irq_base | ((he_readl(he_dev, IRQ0_BASE) & IRQ_MASK) << 2)); (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata */ @@ -2395,7 +2388,7 @@ #ifdef DEBUG if (he_dev->irq_head == he_dev->irq_tail /* && !IRQ_PENDING */) - hprintk1("spurious (or shared) interrupt?\n"); + hprintk("spurious (or shared) interrupt?\n"); #endif if (he_dev->irq_head != he_dev->irq_tail) @@ -2527,7 +2520,7 @@ he_vcc = (struct he_vcc *) kmalloc(sizeof(struct he_vcc), GFP_ATOMIC); if (he_vcc == NULL) { - hprintk1("unable to allocate he_vcc during open\n"); + hprintk("unable to allocate he_vcc during open\n"); return -ENOMEM; } @@ -2987,7 +2980,7 @@ #ifndef USE_SCATTERGATHER if (skb_shinfo(skb)->nr_frags) { - hprintk1("no scatter/gather support\n"); + hprintk("no scatter/gather support\n"); if (vcc->pop) vcc->pop(vcc, skb); else diff -urN linux-2.5.69-bk3/drivers/atm/he.h linux-2.5.69-bk4/drivers/atm/he.h --- linux-2.5.69-bk3/drivers/atm/he.h 2003-05-09 04:41:27.000000000 -0700 +++ linux-2.5.69-bk4/drivers/atm/he.h 2003-05-09 04:41:32.000000000 -0700 @@ -355,10 +355,18 @@ struct he_dev *next; }; +struct he_iovec +{ + u32 iov_base; + u32 iov_len; +}; + +#define HE_MAXIOV 20 + struct he_vcc { - struct iovec iov_head[32]; - struct iovec *iov_tail; + struct he_iovec iov_head[HE_MAXIOV]; + struct he_iovec *iov_tail; int pdu_len; int rc_index; diff -urN linux-2.5.69-bk3/drivers/atm/horizon.c linux-2.5.69-bk4/drivers/atm/horizon.c --- linux-2.5.69-bk3/drivers/atm/horizon.c 2003-05-04 16:52:48.000000000 -0700 +++ linux-2.5.69-bk4/drivers/atm/horizon.c 2003-05-09 04:41:32.000000000 -0700 @@ -1768,17 +1768,20 @@ { unsigned int tx_len = skb->len; - unsigned int tx_iovcnt = ATM_SKB(skb)->iovcnt; + unsigned int tx_iovcnt = skb_shinfo(skb)->nr_frags; // remember this so we can free it later dev->tx_skb = skb; if (tx_iovcnt) { // scatter gather transfer dev->tx_regions = tx_iovcnt; - dev->tx_iovec = (struct iovec *) skb->data; + dev->tx_iovec = 0; /* @@@ needs rewritten */ dev->tx_bytes = 0; PRINTD (DBG_TX|DBG_BUS, "TX start scatter-gather transfer (iovec %p, len %d)", skb->data, tx_len); + tx_release (dev); + hrz_kfree_skb (skb); + return -EIO; } else { // simple transfer dev->tx_regions = 0; diff -urN linux-2.5.69-bk3/drivers/atm/idt77252.c linux-2.5.69-bk4/drivers/atm/idt77252.c --- linux-2.5.69-bk3/drivers/atm/idt77252.c 2003-05-04 16:53:14.000000000 -0700 +++ linux-2.5.69-bk4/drivers/atm/idt77252.c 2003-05-09 04:41:32.000000000 -0700 @@ -1986,7 +1986,7 @@ return -EINVAL; } - if (ATM_SKB(skb)->iovcnt != 0) { + if (skb_shinfo(skb)->nr_frags != 0) { printk("%s: No scatter-gather yet.\n", card->name); atomic_inc(&vcc->stats->tx_err); dev_kfree_skb(skb); @@ -2023,8 +2023,7 @@ atomic_inc(&vcc->stats->tx_err); return -ENOMEM; } - atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->sk->wmem_alloc); - ATM_SKB(skb)->iovcnt = 0; + atomic_add(skb->truesize, &vcc->sk->wmem_alloc); memcpy(skb_put(skb, 52), cell, 52); diff -urN linux-2.5.69-bk3/drivers/atm/iphase.c linux-2.5.69-bk4/drivers/atm/iphase.c --- linux-2.5.69-bk3/drivers/atm/iphase.c 2003-05-09 04:41:27.000000000 -0700 +++ linux-2.5.69-bk4/drivers/atm/iphase.c 2003-05-09 04:41:32.000000000 -0700 @@ -1167,7 +1167,6 @@ skb_put(skb,len); // pwang_test ATM_SKB(skb)->vcc = vcc; - ATM_SKB(skb)->iovcnt = 0; ATM_DESC(skb) = desc; skb_queue_tail(&iadev->rx_dma_q, skb); diff -urN linux-2.5.69-bk3/drivers/atm/lanai.c linux-2.5.69-bk4/drivers/atm/lanai.c --- linux-2.5.69-bk3/drivers/atm/lanai.c 2003-05-04 16:53:08.000000000 -0700 +++ linux-2.5.69-bk4/drivers/atm/lanai.c 2003-05-09 04:41:32.000000000 -0700 @@ -2846,7 +2846,6 @@ .phy_get = NULL, .feedback = NULL, .change_qos = lanai_change_qos, - .free_rx_skb = NULL, .proc_read = lanai_proc_read }; diff -urN linux-2.5.69-bk3/drivers/atm/nicstar.c linux-2.5.69-bk4/drivers/atm/nicstar.c --- linux-2.5.69-bk3/drivers/atm/nicstar.c 2003-05-04 16:53:07.000000000 -0700 +++ linux-2.5.69-bk4/drivers/atm/nicstar.c 2003-05-09 04:41:32.000000000 -0700 @@ -882,9 +882,14 @@ return error; } - if (ns_parse_mac(mac[i], card->atmdev->esi)) + if (ns_parse_mac(mac[i], card->atmdev->esi)) { nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, card->atmdev->esi, 6); + if (memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6) == 0) { + nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT, + card->atmdev->esi, 6); + } + } printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i, card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2], @@ -1601,9 +1606,9 @@ card->index); iovb = vc->rx_iov; recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, - ATM_SKB(iovb)->iovcnt); - ATM_SKB(iovb)->iovcnt = 0; - ATM_SKB(iovb)->vcc = NULL; + NS_SKB(iovb)->iovcnt); + NS_SKB(iovb)->iovcnt = 0; + NS_SKB(iovb)->vcc = NULL; ns_grab_int_lock(card, flags); recycle_iov_buf(card, iovb); spin_unlock_irqrestore(&card->int_lock, flags); @@ -1801,7 +1806,7 @@ return -EINVAL; } - if (ATM_SKB(skb)->iovcnt != 0) + if (skb_shinfo(skb)->nr_frags != 0) { printk("nicstar%d: No scatter-gather yet.\n", card->index); atomic_inc(&vcc->stats->tx_err); @@ -2226,30 +2231,30 @@ } } vc->rx_iov = iovb; - ATM_SKB(iovb)->iovcnt = 0; + NS_SKB(iovb)->iovcnt = 0; iovb->len = 0; iovb->tail = iovb->data = iovb->head; - ATM_SKB(iovb)->vcc = vcc; + NS_SKB(iovb)->vcc = vcc; /* IMPORTANT: a pointer to the sk_buff containing the small or large buffer is stored as iovec base, NOT a pointer to the small or large buffer itself. */ } - else if (ATM_SKB(iovb)->iovcnt >= NS_MAX_IOVECS) + else if (NS_SKB(iovb)->iovcnt >= NS_MAX_IOVECS) { printk("nicstar%d: received too big AAL5 SDU.\n", card->index); atomic_inc(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS); - ATM_SKB(iovb)->iovcnt = 0; + NS_SKB(iovb)->iovcnt = 0; iovb->len = 0; iovb->tail = iovb->data = iovb->head; - ATM_SKB(iovb)->vcc = vcc; + NS_SKB(iovb)->vcc = vcc; } - iov = &((struct iovec *) iovb->data)[ATM_SKB(iovb)->iovcnt++]; + iov = &((struct iovec *) iovb->data)[NS_SKB(iovb)->iovcnt++]; iov->iov_base = (void *) skb; iov->iov_len = ns_rsqe_cellcount(rsqe) * 48; iovb->len += iov->iov_len; - if (ATM_SKB(iovb)->iovcnt == 1) + if (NS_SKB(iovb)->iovcnt == 1) { if (skb->list != &card->sbpool.queue) { @@ -2263,7 +2268,7 @@ return; } } - else /* ATM_SKB(iovb)->iovcnt >= 2 */ + else /* NS_SKB(iovb)->iovcnt >= 2 */ { if (skb->list != &card->lbpool.queue) { @@ -2272,7 +2277,7 @@ which_list(card, skb); atomic_inc(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, - ATM_SKB(iovb)->iovcnt); + NS_SKB(iovb)->iovcnt); vc->rx_iov = NULL; recycle_iov_buf(card, iovb); return; @@ -2296,7 +2301,7 @@ printk(".\n"); atomic_inc(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, - ATM_SKB(iovb)->iovcnt); + NS_SKB(iovb)->iovcnt); vc->rx_iov = NULL; recycle_iov_buf(card, iovb); return; @@ -2304,7 +2309,7 @@ /* By this point we (hopefully) have a complete SDU without errors. */ - if (ATM_SKB(iovb)->iovcnt == 1) /* Just a small buffer */ + if (NS_SKB(iovb)->iovcnt == 1) /* Just a small buffer */ { /* skb points to a small buffer */ if (!atm_charge(vcc, skb->truesize)) @@ -2326,7 +2331,7 @@ atomic_inc(&vcc->stats->rx); } } - else if (ATM_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */ + else if (NS_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */ { struct sk_buff *sb; @@ -2403,7 +2408,7 @@ printk("nicstar%d: Out of huge buffers.\n", card->index); atomic_inc(&vcc->stats->rx_drop); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, - ATM_SKB(iovb)->iovcnt); + NS_SKB(iovb)->iovcnt); vc->rx_iov = NULL; recycle_iov_buf(card, iovb); return; @@ -2441,7 +2446,7 @@ if (!atm_charge(vcc, hb->truesize)) { - recycle_iovec_rx_bufs(card, iov, ATM_SKB(iovb)->iovcnt); + recycle_iovec_rx_bufs(card, iov, NS_SKB(iovb)->iovcnt); if (card->hbpool.count < card->hbnr.max) { skb_queue_tail(&card->hbpool.queue, hb); @@ -2464,7 +2469,7 @@ 0, 0); /* Copy all large buffers to the huge buffer and free them */ - for (j = 1; j < ATM_SKB(iovb)->iovcnt; j++) + for (j = 1; j < NS_SKB(iovb)->iovcnt; j++) { lb = (struct sk_buff *) iov->iov_base; tocopy = MIN(remaining, iov->iov_len); diff -urN linux-2.5.69-bk3/drivers/atm/nicstar.h linux-2.5.69-bk4/drivers/atm/nicstar.h --- linux-2.5.69-bk3/drivers/atm/nicstar.h 2003-05-04 16:53:08.000000000 -0700 +++ linux-2.5.69-bk4/drivers/atm/nicstar.h 2003-05-09 04:41:32.000000000 -0700 @@ -96,6 +96,7 @@ /* ESI stuff ******************************************************************/ #define NICSTAR_EPROM_MAC_ADDR_OFFSET 0x6C +#define NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT 0xF6 /* #defines *******************************************************************/ @@ -749,6 +750,15 @@ } vc_map; +struct ns_skb_data +{ + struct atm_vcc *vcc; + int iovcnt; +}; + +#define NS_SKB(skb) (((struct ns_skb_data *) (skb)->cb)) + + typedef struct ns_dev { int index; /* Card ID to the device driver */ diff -urN linux-2.5.69-bk3/drivers/atm/zatm.c linux-2.5.69-bk4/drivers/atm/zatm.c --- linux-2.5.69-bk3/drivers/atm/zatm.c 2003-05-04 16:53:08.000000000 -0700 +++ linux-2.5.69-bk4/drivers/atm/zatm.c 2003-05-09 04:41:33.000000000 -0700 @@ -827,10 +827,10 @@ vcc = ATM_SKB(skb)->vcc; zatm_dev = ZATM_DEV(vcc->dev); zatm_vcc = ZATM_VCC(vcc); - EVENT("iovcnt=%d\n",ATM_SKB(skb)->iovcnt,0); + EVENT("iovcnt=%d\n",skb_shinfo(skb)->nr_frags,0); save_flags(flags); cli(); - if (!ATM_SKB(skb)->iovcnt) { + if (!skb_shinfo(skb)->nr_frags) { if (zatm_vcc->txing == RING_ENTRIES-1) { restore_flags(flags); return RING_BUSY; diff -urN linux-2.5.69-bk3/drivers/char/tty_io.c linux-2.5.69-bk4/drivers/char/tty_io.c --- linux-2.5.69-bk3/drivers/char/tty_io.c 2003-05-09 04:41:27.000000000 -0700 +++ linux-2.5.69-bk4/drivers/char/tty_io.c 2003-05-09 04:41:33.000000000 -0700 @@ -2110,6 +2110,7 @@ #define to_tty_dev(d) container_of(d, struct tty_dev, class_dev) static LIST_HEAD(tty_dev_list); +static spinlock_t tty_dev_list_lock = SPIN_LOCK_UNLOCKED; static ssize_t show_dev(struct class_device *class_dev, char *buf) { @@ -2130,7 +2131,7 @@ memset(tty_dev, 0x00, sizeof(*tty_dev)); /* stupid '/' in tty name strings... */ - temp = strchr(name, '/'); + temp = strrchr(name, '/'); if (temp && (temp[1] != 0x00)) ++temp; else @@ -2144,7 +2145,9 @@ goto error; class_device_create_file (&tty_dev->class_dev, &class_device_attr_dev); tty_dev->dev = dev; + spin_lock(&tty_dev_list_lock); list_add(&tty_dev->node, &tty_dev_list); + spin_unlock(&tty_dev_list_lock); return; error: kfree(tty_dev); @@ -2156,6 +2159,7 @@ struct list_head *tmp; int found = 0; + spin_lock(&tty_dev_list_lock); list_for_each (tmp, &tty_dev_list) { tty_dev = list_entry(tmp, struct tty_dev, node); if ((MAJOR(tty_dev->dev) == MAJOR(dev)) && @@ -2166,8 +2170,11 @@ } if (found) { list_del(&tty_dev->node); + spin_unlock(&tty_dev_list_lock); class_device_unregister(&tty_dev->class_dev); kfree(tty_dev); + } else { + spin_unlock(&tty_dev_list_lock); } } @@ -2196,8 +2203,7 @@ } tty_line_name(driver, index, name); - devfs_register(NULL, name, 0, MAJOR(dev), MINOR(dev), - S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL); + devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, name); /* stupid console driver devfs names... change vc/X into ttyX */ if (driver->type == TTY_DRIVER_TYPE_CONSOLE) diff -urN linux-2.5.69-bk3/drivers/net/acenic.c linux-2.5.69-bk4/drivers/net/acenic.c --- linux-2.5.69-bk3/drivers/net/acenic.c 2003-05-04 16:53:14.000000000 -0700 +++ linux-2.5.69-bk4/drivers/net/acenic.c 2003-05-09 04:41:33.000000000 -0700 @@ -1871,7 +1871,9 @@ } else { printk(KERN_DEBUG "%s: BUG... transmitter died. Kicking it.\n", dev->name); +#if 0 netif_wake_queue(dev); +#endif } } diff -urN linux-2.5.69-bk3/drivers/net/setup.c linux-2.5.69-bk4/drivers/net/setup.c --- linux-2.5.69-bk3/drivers/net/setup.c 2003-05-04 16:53:41.000000000 -0700 +++ linux-2.5.69-bk4/drivers/net/setup.c 2003-05-09 04:41:34.000000000 -0700 @@ -9,7 +9,6 @@ #include #include -extern int slip_init_ctrl_dev(void); extern int x25_asy_init_ctrl_dev(void); extern int dmascc_init(void); @@ -109,9 +108,6 @@ static void __init network_ldisc_init(void) { -#if defined(CONFIG_SLIP) - slip_init_ctrl_dev(); -#endif #if defined(CONFIG_X25_ASY) x25_asy_init_ctrl_dev(); #endif diff -urN linux-2.5.69-bk3/drivers/net/sk98lin/skge.c linux-2.5.69-bk4/drivers/net/sk98lin/skge.c --- linux-2.5.69-bk3/drivers/net/sk98lin/skge.c 2003-05-04 16:53:02.000000000 -0700 +++ linux-2.5.69-bk4/drivers/net/sk98lin/skge.c 2003-05-09 04:41:34.000000000 -0700 @@ -348,12 +348,12 @@ static int SkGeIocMib(DEV_NET*, unsigned int, int); -/*Extern */ +static const char SK_Root_Dir_entry[] = "sk98lin"; +static struct proc_dir_entry *pSkRootDir; -extern struct proc_dir_entry *pSkRootDir; //extern struct proc_dir_entry Our_Proc_Dir; -extern int proc_read(char *buffer, char **buffer_location, +extern int sk_proc_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data); @@ -376,17 +376,6 @@ static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480}; - -void proc_fill_inode(struct inode *inode, int fill) -{ - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - - - /***************************************************************************** * * skge_probe - find all SK-98xx adapters @@ -481,20 +470,20 @@ dev->change_mtu = &SkGeChangeMtu; if(!proc_root_initialized) { - pSkRootDir = create_proc_entry("sk98lin", + pSkRootDir = create_proc_entry(SK_Root_Dir_entry, S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, proc_net); pSkRootDir->owner = THIS_MODULE; - proc_root_initialized = 1; } pProcFile = create_proc_entry(dev->name, S_IFREG | 0444, pSkRootDir); - pProcFile->read_proc = proc_read; + pProcFile->read_proc = sk_proc_read; pProcFile->write_proc = NULL; pProcFile->nlink = 1; pProcFile->size = sizeof(dev->name+1); pProcFile->data = (void*)pProcFile; + pProcFile->owner = THIS_MODULE; /* * Dummy value. @@ -571,11 +560,12 @@ pProcFile = create_proc_entry(dev->name, S_IFREG | 0444, pSkRootDir); - pProcFile->read_proc = proc_read; + pProcFile->read_proc = sk_proc_read; pProcFile->write_proc = NULL; pProcFile->nlink = 1; pProcFile->size = sizeof(dev->name+1); pProcFile->data = (void*)pProcFile; + pProcFile->owner = THIS_MODULE; memcpy((caddr_t) &dev->dev_addr, (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); diff -urN linux-2.5.69-bk3/drivers/net/sk98lin/skproc.c linux-2.5.69-bk4/drivers/net/sk98lin/skproc.c --- linux-2.5.69-bk3/drivers/net/sk98lin/skproc.c 2003-05-04 16:53:01.000000000 -0700 +++ linux-2.5.69-bk4/drivers/net/sk98lin/skproc.c 2003-05-09 04:41:34.000000000 -0700 @@ -54,7 +54,6 @@ //#define SPECIAL 32 /* 0x */ #define LARGE 64 -extern void proc_fill_inode(struct inode *inode, int fill); extern char * SkNumber(char * str, long long num, int base, int size, int precision ,int type); int proc_read(char *buffer, @@ -64,19 +63,8 @@ int *eof, void *data); -static const char SK_Root_Dir_entry[] = "sk98lin"; -extern struct net_device *sk98lin_root_dev; - - -struct proc_dir_entry pSkRootDir = { - 0, - sizeof(SK_Root_Dir_entry)-1, - (const char*)SK_Root_Dir_entry, - S_IFDIR | S_IRUGO, - 2, 0, 0, 0, NULL, - NULL -}; +extern struct net_device *sk98lin_root_dev; /***************************************************************************** * @@ -90,7 +78,7 @@ * Returns: buffer with statistic data * */ -int proc_read(char *buffer, +int sk_proc_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, diff -urN linux-2.5.69-bk3/drivers/net/slip.c linux-2.5.69-bk4/drivers/net/slip.c --- linux-2.5.69-bk3/drivers/net/slip.c 2003-05-04 16:53:57.000000000 -0700 +++ linux-2.5.69-bk4/drivers/net/slip.c 2003-05-09 04:41:34.000000000 -0700 @@ -81,11 +81,7 @@ #include #endif -#ifdef MODULE -#define SLIP_VERSION "0.8.4-NET3.019-NEWTTY-MODULAR" -#else -#define SLIP_VERSION "0.8.4-NET3.019-NEWTTY" -#endif +#define SLIP_VERSION "0.8.4-NET3.019-NEWTTY" typedef struct slip_ctrl { @@ -98,8 +94,6 @@ MODULE_PARM(slip_maxdev, "i"); MODULE_PARM_DESC(slip_maxdev, "Maximum number of slip devices"); -static struct tty_ldisc sl_ldisc; - static int slip_esc(unsigned char *p, unsigned char *d, int len); static void slip_unesc(struct slip *sl, unsigned char c); #ifdef CONFIG_SLIP_MODE_SLIP6 @@ -1309,13 +1303,24 @@ #endif /* VSV changes end */ -/* Initialize SLIP control device -- register SLIP line discipline */ +static struct tty_ldisc sl_ldisc = { + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, + .name = "slip", + .open = slip_open, + .close = slip_close, + .ioctl = slip_ioctl, + .receive_buf = slip_receive_buf, + .receive_room = slip_receive_room, + .write_wakeup = slip_write_wakeup, +}; -int __init slip_init_ctrl_dev(void) +static int __init slip_init(void) { int status; - if (slip_maxdev < 4) slip_maxdev = 4; /* Sanity */ + if (slip_maxdev < 4) + slip_maxdev = 4; /* Sanity */ printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)" #ifdef CONFIG_SLIP_MODE_SLIP6 @@ -1323,16 +1328,15 @@ #endif ".\n", SLIP_VERSION, slip_maxdev ); -#if defined(SL_INCLUDE_CSLIP) && !defined(MODULE) +#if defined(SL_INCLUDE_CSLIP) printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.\n"); #endif #ifdef CONFIG_SLIP_SMART printk(KERN_INFO "SLIP linefill/keepalive option.\n"); #endif - slip_ctrls = (slip_ctrl_t **) kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL); - if (slip_ctrls == NULL) - { + slip_ctrls = kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL); + if (!slip_ctrls) { printk(KERN_ERR "SLIP: Can't allocate slip_ctrls[] array! Uaargh! (-> No SLIP available)\n"); return -ENOMEM; } @@ -1347,28 +1351,7 @@ return status; } -static struct tty_ldisc sl_ldisc = -{ - .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, - .name = "slip", - .open = slip_open, - .close = slip_close, - .ioctl = slip_ioctl, - .receive_buf = slip_receive_buf, - .receive_room = slip_receive_room, - .write_wakeup = slip_write_wakeup, -}; - -#ifdef MODULE - -int init_module(void) -{ - return slip_init_ctrl_dev(); -} - -void -cleanup_module(void) +static void __exit slip_exit(void) { int i; @@ -1425,7 +1408,9 @@ printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i); } } -#endif /* MODULE */ + +module_init(slip_init); +module_exit(slip_exit); #ifdef CONFIG_SLIP_SMART /* diff -urN linux-2.5.69-bk3/drivers/net/slip.h linux-2.5.69-bk4/drivers/net/slip.h --- linux-2.5.69-bk3/drivers/net/slip.h 2003-05-04 16:53:32.000000000 -0700 +++ linux-2.5.69-bk4/drivers/net/slip.h 2003-05-09 04:41:34.000000000 -0700 @@ -116,10 +116,6 @@ #endif }; - - #define SLIP_MAGIC 0x5302 -extern int slip_init(struct net_device *dev); - #endif /* _LINUX_SLIP.H */ diff -urN linux-2.5.69-bk3/drivers/usb/core/file.c linux-2.5.69-bk4/drivers/usb/core/file.c --- linux-2.5.69-bk3/drivers/usb/core/file.c 2003-05-09 04:41:27.000000000 -0700 +++ linux-2.5.69-bk4/drivers/usb/core/file.c 2003-05-09 04:41:34.000000000 -0700 @@ -11,7 +11,7 @@ more docs, etc) * (C) Copyright Yggdrasil Computing, Inc. 2000 * (usb_device_id matching changes by Adam J. Richter) - * (C) Copyright Greg Kroah-Hartman 2002 + * (C) Copyright Greg Kroah-Hartman 2002-2003 * */ @@ -160,8 +160,7 @@ /* handle the devfs registration */ snprintf(name, DEVICE_ID_SIZE, class_driver->name, minor - minor_base); - devfs_register(NULL, name, 0, USB_MAJOR, minor, class_driver->mode, - class_driver->fops, NULL); + devfs_mk_cdev(MKDEV(USB_MAJOR, minor), class_driver->mode, name); /* create a usb class device for this usb interface */ memset(&intf->class_dev, 0x00, sizeof(struct class_device)); diff -urN linux-2.5.69-bk3/drivers/usb/misc/tiglusb.c linux-2.5.69-bk4/drivers/usb/misc/tiglusb.c --- linux-2.5.69-bk3/drivers/usb/misc/tiglusb.c 2003-05-09 04:41:27.000000000 -0700 +++ linux-2.5.69-bk4/drivers/usb/misc/tiglusb.c 2003-05-09 04:41:35.000000000 -0700 @@ -370,7 +370,7 @@ up (&s->mutex); dbg ("bound to interface"); - devfs_mk_cdev(MAJOR(TIUSB_MAJOR, TIUSB_MINOR + s->minor), + devfs_mk_cdev(MKDEV(TIUSB_MAJOR, TIUSB_MINOR) + s->minor, S_IFCHR | S_IRUGO | S_IWUGO, "ticables/usb/%d", s->minor); diff -urN linux-2.5.69-bk3/drivers/usb/serial/usb-serial.c linux-2.5.69-bk4/drivers/usb/serial/usb-serial.c --- linux-2.5.69-bk3/drivers/usb/serial/usb-serial.c 2003-05-04 16:53:13.000000000 -0700 +++ linux-2.5.69-bk4/drivers/usb/serial/usb-serial.c 2003-05-09 04:41:35.000000000 -0700 @@ -1,7 +1,7 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 1999 - 2003 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2000 Peter Berger (pberger@brimson.com) * Copyright (c) 2000 Al Borchers (borchers@steinerpoint.com) * diff -urN linux-2.5.69-bk3/drivers/usb/serial/usb-serial.h linux-2.5.69-bk4/drivers/usb/serial/usb-serial.h --- linux-2.5.69-bk3/drivers/usb/serial/usb-serial.h 2003-05-09 04:41:27.000000000 -0700 +++ linux-2.5.69-bk4/drivers/usb/serial/usb-serial.h 2003-05-09 04:41:35.000000000 -0700 @@ -1,7 +1,7 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2002 + * Copyright (C) 1999 - 2003 * Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify diff -urN linux-2.5.69-bk3/drivers/usb/serial/visor.h linux-2.5.69-bk4/drivers/usb/serial/visor.h --- linux-2.5.69-bk3/drivers/usb/serial/visor.h 2003-05-04 16:53:40.000000000 -0700 +++ linux-2.5.69-bk4/drivers/usb/serial/visor.h 2003-05-09 04:41:35.000000000 -0700 @@ -1,7 +1,7 @@ /* * USB HandSpring Visor driver * - * Copyright (C) 1999 - 2002 + * Copyright (C) 1999 - 2003 * Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify diff -urN linux-2.5.69-bk3/drivers/usb/usb-skeleton.c linux-2.5.69-bk4/drivers/usb/usb-skeleton.c --- linux-2.5.69-bk3/drivers/usb/usb-skeleton.c 2003-05-09 04:41:27.000000000 -0700 +++ linux-2.5.69-bk4/drivers/usb/usb-skeleton.c 2003-05-09 04:41:35.000000000 -0700 @@ -1,7 +1,7 @@ /* * USB Skeleton driver - 1.1 * - * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff -urN linux-2.5.69-bk3/include/linux/atmdev.h linux-2.5.69-bk4/include/linux/atmdev.h --- linux-2.5.69-bk3/include/linux/atmdev.h 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/include/linux/atmdev.h 2003-05-09 04:41:36.000000000 -0700 @@ -30,9 +30,6 @@ #define ATM_DS3_PCR (8000*12) /* DS3: 12 cells in a 125 usec time slot */ -#define ATM_PDU_OVHD 0 /* number of bytes to charge against buffer - quota per PDU */ - #define atm_sk(__sk) ((struct atm_vcc *)(__sk)->protinfo) #define ATM_SD(s) (atm_sk((s)->sk)) @@ -289,10 +286,6 @@ struct atm_sap sap; /* SAP */ void (*push)(struct atm_vcc *vcc,struct sk_buff *skb); void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */ - struct sk_buff *(*alloc_tx)(struct atm_vcc *vcc,unsigned int size); - /* TX allocation routine - can be */ - /* modified by protocol or by driver.*/ - /* NOTE: this interface will change */ int (*push_oam)(struct atm_vcc *vcc,void *cell); int (*send)(struct atm_vcc *vcc,struct sk_buff *skb); void *dev_data; /* per-device data */ @@ -378,8 +371,6 @@ void (*feedback)(struct atm_vcc *vcc,struct sk_buff *skb, unsigned long start,unsigned long dest,int len); int (*change_qos)(struct atm_vcc *vcc,struct atm_qos *qos,int flags); - void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb); - /* @@@ temporary hack */ int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page); struct module *owner; }; @@ -394,7 +385,6 @@ struct atm_skb_data { struct atm_vcc *vcc; /* ATM VCC */ - int iovcnt; /* 0 for "normal" operation */ unsigned long atm_options; /* ATM layer options */ }; @@ -421,19 +411,19 @@ static __inline__ void atm_force_charge(struct atm_vcc *vcc,int truesize) { - atomic_add(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc); + atomic_add(truesize, &vcc->sk->rmem_alloc); } static __inline__ void atm_return(struct atm_vcc *vcc,int truesize) { - atomic_sub(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc); + atomic_sub(truesize, &vcc->sk->rmem_alloc); } static __inline__ int atm_may_send(struct atm_vcc *vcc,unsigned int size) { - return size+atomic_read(&vcc->sk->wmem_alloc)+ATM_PDU_OVHD < vcc->sk->sndbuf; + return (size + atomic_read(&vcc->sk->wmem_alloc)) < vcc->sk->sndbuf; } diff -urN linux-2.5.69-bk3/include/net/sctp/command.h linux-2.5.69-bk4/include/net/sctp/command.h --- linux-2.5.69-bk3/include/net/sctp/command.h 2003-05-04 16:53:56.000000000 -0700 +++ linux-2.5.69-bk4/include/net/sctp/command.h 2003-05-09 04:41:37.000000000 -0700 @@ -182,7 +182,7 @@ /* Create a new sctp_command_sequence. * Return NULL if creating a new sequence fails. */ -sctp_cmd_seq_t *sctp_new_cmd_seq(int priority); +sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp); /* Initialize a block of memory as a command sequence. * Return 0 if the initialization fails. diff -urN linux-2.5.69-bk3/include/net/sctp/constants.h linux-2.5.69-bk4/include/net/sctp/constants.h --- linux-2.5.69-bk3/include/net/sctp/constants.h 2003-05-04 16:53:09.000000000 -0700 +++ linux-2.5.69-bk4/include/net/sctp/constants.h 2003-05-09 04:41:37.000000000 -0700 @@ -6,46 +6,42 @@ * * This file is part of the SCTP kernel reference Implementation * - * This file is part of the implementation of the add-IP extension, - * based on June 29, 2001, - * for the SCTP kernel reference Implementation. - * - * The SCTP reference implementation is free software; + * The SCTP reference implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * the SCTP reference implementation is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * The SCTP reference implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied * ************************ - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * - * Please send any bug reports or fixes you make to one of the following email - * addresses: - * - * La Monte H.P. Yarroll - * Karl Knutson - * Randall Stewart - * Ken Morneau - * Qiaobing Xie - * Xingang Guo - * Sridhar Samudrala - * Daisy Chang + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Randall Stewart + * Ken Morneau + * Qiaobing Xie + * Xingang Guo + * Sridhar Samudrala + * Daisy Chang * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. - * - * There are still LOTS of bugs in this code... I always run on the motto - * "it is a wonder any code ever works :)" - * - * */ #ifndef __sctp_constants_h__ @@ -220,7 +216,7 @@ * - A socket in SCTP_SS_LISTENING state indicates that it is willing to * accept new associations, but cannot initiate the creation of new ones. * - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single - * association in ESTABLISHED state. + * association. */ typedef enum { SCTP_SS_CLOSED = TCP_CLOSE, @@ -336,10 +332,18 @@ #define SCTP_SIGNATURE_SIZE 20 /* size of a SLA-1 signature */ -#define SCTP_COOKIE_MULTIPLE 64 /* Pad out our cookie to make our hash +#define SCTP_COOKIE_MULTIPLE 32 /* Pad out our cookie to make our hash * functions simpler to write. */ +#if defined (CONFIG_SCTP_HMAC_MD5) +#define SCTP_COOKIE_HMAC_ALG "md5" +#elif defined (CONFIG_SCTP_HMAC_SHA1) +#define SCTP_COOKIE_HMAC_ALG "sha1" +#else +#define SCTP_COOKIE_HMAC_ALG NULL +#endif + /* These return values describe the success or failure of a number of * routines which form the lower interface to SCTP_outqueue. */ diff -urN linux-2.5.69-bk3/include/net/sctp/sctp.h linux-2.5.69-bk4/include/net/sctp/sctp.h --- linux-2.5.69-bk3/include/net/sctp/sctp.h 2003-05-04 16:53:08.000000000 -0700 +++ linux-2.5.69-bk4/include/net/sctp/sctp.h 2003-05-09 04:41:37.000000000 -0700 @@ -125,65 +125,61 @@ extern struct sock *sctp_get_ctl_sock(void); extern int sctp_copy_local_addr_list(struct sctp_protocol *, struct sctp_bind_addr *, - sctp_scope_t, int priority, int flags); + sctp_scope_t, int gfp, int flags); extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); extern int sctp_register_pf(struct sctp_pf *, sa_family_t); /* * sctp/socket.c */ -extern int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); -extern int sctp_inet_listen(struct socket *sock, int backlog); -extern void sctp_write_space(struct sock *sk); -extern unsigned int sctp_poll(struct file *file, struct socket *sock, +int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); +int sctp_inet_listen(struct socket *sock, int backlog); +void sctp_write_space(struct sock *sk); +unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait); /* * sctp/primitive.c */ -extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg); -extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg); -extern int sctp_primitive_ABORT(sctp_association_t *, void *arg); -extern int sctp_primitive_SEND(sctp_association_t *, void *arg); -extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg); +int sctp_primitive_ASSOCIATE(struct sctp_association *, void *arg); +int sctp_primitive_SHUTDOWN(struct sctp_association *, void *arg); +int sctp_primitive_ABORT(struct sctp_association *, void *arg); +int sctp_primitive_SEND(struct sctp_association *, void *arg); +int sctp_primitive_REQUESTHEARTBEAT(struct sctp_association *, void *arg); /* * sctp/crc32c.c */ -extern __u32 sctp_start_cksum(__u8 *ptr, __u16 count); -extern __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum); -extern __u32 sctp_end_cksum(__u32 cksum); +__u32 sctp_start_cksum(__u8 *ptr, __u16 count); +__u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum); +__u32 sctp_end_cksum(__u32 cksum); +__u32 sctp_update_copy_cksum(__u8 *, __u8 *, __u16 count, __u32 cksum); /* * sctp/input.c */ -extern int sctp_rcv(struct sk_buff *skb); -extern void sctp_v4_err(struct sk_buff *skb, u32 info); -extern void sctp_hash_established(sctp_association_t *); -extern void __sctp_hash_established(sctp_association_t *); -extern void sctp_unhash_established(sctp_association_t *); -extern void __sctp_unhash_established(sctp_association_t *); -extern void sctp_hash_endpoint(sctp_endpoint_t *); -extern void __sctp_hash_endpoint(sctp_endpoint_t *); -extern void sctp_unhash_endpoint(sctp_endpoint_t *); -extern void __sctp_unhash_endpoint(sctp_endpoint_t *); -extern sctp_association_t *__sctp_lookup_association(const union sctp_addr *, - const union sctp_addr *, - struct sctp_transport **); -extern struct sock *sctp_err_lookup(int family, struct sk_buff *, - struct sctphdr *, struct sctp_endpoint **, - struct sctp_association **, - struct sctp_transport **); -extern void sctp_err_finish(struct sock *, struct sctp_endpoint *, +int sctp_rcv(struct sk_buff *skb); +void sctp_v4_err(struct sk_buff *skb, u32 info); +void sctp_hash_established(struct sctp_association *); +void __sctp_hash_established(struct sctp_association *); +void sctp_unhash_established(struct sctp_association *); +void __sctp_unhash_established(struct sctp_association *); +void sctp_hash_endpoint(struct sctp_endpoint *); +void __sctp_hash_endpoint(struct sctp_endpoint *); +void sctp_unhash_endpoint(struct sctp_endpoint *); +void __sctp_unhash_endpoint(struct sctp_endpoint *); +struct sctp_association *__sctp_lookup_association( + const union sctp_addr *, + const union sctp_addr *, + struct sctp_transport **); +struct sock *sctp_err_lookup(int family, struct sk_buff *, + struct sctphdr *, struct sctp_endpoint **, + struct sctp_association **, + struct sctp_transport **); +void sctp_err_finish(struct sock *, struct sctp_endpoint *, struct sctp_association *); -extern void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, - struct sctp_transport *t, __u32 pmtu); -/* - * sctp/hashdriver.c - */ -extern void sctp_hash_digest(const char *secret, const int secret_len, - const char *text, const int text_len, - __u8 *digest); +void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, + struct sctp_transport *t, __u32 pmtu); /* * Section: Macros, externs, and inlines @@ -281,6 +277,7 @@ extern atomic_t sctp_dbg_objcnt_bind_addr; extern atomic_t sctp_dbg_objcnt_addr; extern atomic_t sctp_dbg_objcnt_ssnmap; +extern atomic_t sctp_dbg_objcnt_datamsg; /* Macros to atomically increment/decrement objcnt counters. */ #define SCTP_DBG_OBJCNT_INC(name) \ @@ -296,8 +293,8 @@ #define SCTP_DBG_OBJCNT_ENTRY(name) \ {.label= #name, .counter= &sctp_dbg_objcnt_## name} -extern void sctp_dbg_objcnt_init(void); -extern void sctp_dbg_objcnt_exit(void); +void sctp_dbg_objcnt_init(void); +void sctp_dbg_objcnt_exit(void); #else @@ -310,8 +307,8 @@ #endif /* CONFIG_SCTP_DBG_OBJCOUNT */ #if defined CONFIG_SYSCTL -extern void sctp_sysctl_register(void); -extern void sctp_sysctl_unregister(void); +void sctp_sysctl_register(void); +void sctp_sysctl_unregister(void); #else static inline void sctp_sysctl_register(void) { return; } static inline void sctp_sysctl_unregister(void) { return; } @@ -322,9 +319,9 @@ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -extern int sctp_v6_init(void); -extern void sctp_v6_exit(void); -extern void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +int sctp_v6_init(void); +void sctp_v6_exit(void); +void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __u32 info); #else /* #ifdef defined(CONFIG_IPV6) */ @@ -334,15 +331,26 @@ #endif /* #if defined(CONFIG_IPV6) */ +/* Some wrappers, in case crypto not available. */ +#if defined (CONFIG_CRYPTO_HMAC) +#define sctp_crypto_alloc_tfm crypto_alloc_tfm +#define sctp_crypto_free_tfm crypto_free_tfm +#define sctp_crypto_hmac crypto_hmac +#else +#define sctp_crypto_alloc_tfm(x...) NULL +#define sctp_crypto_free_tfm(x...) +#define sctp_crypto_hmac(x...) +#endif + + /* Map an association to an assoc_id. */ -static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc) +static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc) { return (sctp_assoc_t) asoc; } - /* Look up the association by its id. */ -sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id); +struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id); /* A macro to walk a list of skbs. */ @@ -422,12 +430,16 @@ } /* Break down data chunks at this point. */ -static inline int sctp_frag_point(int pmtu) +static inline int sctp_frag_point(const struct sctp_opt *sp, int pmtu) { - pmtu -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk); - pmtu -= sizeof(struct sctp_sack_chunk); + int frag = pmtu; + frag -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk); + frag -= sizeof(struct sctp_sack_chunk); - return pmtu; + if (sp->user_frag) + frag = min_t(int, frag, sp->user_frag); + + return frag; } /* Walk through a list of TLV parameters. Don't trust the @@ -475,7 +487,7 @@ extern struct proto sctp_prot; extern struct proc_dir_entry *proc_net_sctp; -extern void sctp_put_port(struct sock *sk); +void sctp_put_port(struct sock *sk); /* Static inline functions. */ @@ -501,10 +513,10 @@ /* Perform some sanity checks. */ static inline int sctp_sanity_check(void) { - SCTP_ASSERT(sizeof(struct sctp_ulpevent) <= + SCTP_ASSERT(sizeof(struct sctp_ulpevent) <= sizeof(((struct sk_buff *)0)->cb), "SCTP: ulpevent does not fit in skb!\n", return 0); - + return 1; } @@ -566,4 +578,26 @@ #define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp) +/* Is a socket of this style? */ +#define sctp_style(sk, style) __sctp_style((sk), (SCTP_SOCKET_##style)) +int static inline __sctp_style(const struct sock *sk, sctp_socket_type_t style) +{ + return sctp_sk(sk)->type == style; +} + +/* Is the association in this state? */ +#define sctp_state(asoc, state) __sctp_state((asoc), (SCTP_STATE_##state)) +int static inline __sctp_state(const struct sctp_association *asoc, + sctp_state_t state) +{ + return asoc->state == state; +} + +/* Is the socket in this state? */ +#define sctp_sstate(sk, state) __sctp_sstate((sk), (SCTP_SS_##state)) +int static inline __sctp_sstate(const struct sock *sk, sctp_sock_state_t state) +{ + return sk->state == state; +} + #endif /* __net_sctp_h__ */ diff -urN linux-2.5.69-bk3/include/net/sctp/sm.h linux-2.5.69-bk4/include/net/sctp/sm.h --- linux-2.5.69-bk3/include/net/sctp/sm.h 2003-05-04 16:53:14.000000000 -0700 +++ linux-2.5.69-bk4/include/net/sctp/sm.h 2003-05-09 04:41:37.000000000 -0700 @@ -6,10 +6,6 @@ * * This file is part of the SCTP kernel reference Implementation * - * This file is part of the implementation of the add-IP extension, - * based on June 29, 2001, - * for the SCTP kernel reference Implementation. - * * These are definitions needed by the state machine. * * The SCTP reference implementation is free software; @@ -50,7 +46,6 @@ * be incorporated into the next SCTP release. */ - #include #include #include @@ -81,8 +76,8 @@ int action; } sctp_sm_command_t; -typedef sctp_disposition_t (sctp_state_fn_t) (const sctp_endpoint_t *, - const sctp_association_t *, +typedef sctp_disposition_t (sctp_state_fn_t) (const struct sctp_endpoint *, + const struct sctp_association *, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *); @@ -209,109 +204,104 @@ void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag); /* Prototypes for chunk-building functions. */ -sctp_chunk_t *sctp_make_init(const sctp_association_t *, - const sctp_bind_addr_t *, - int priority, int vparam_len); -sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *, - const sctp_chunk_t *, - const int priority, +struct sctp_chunk *sctp_make_init(const struct sctp_association *, + const struct sctp_bind_addr *, + int gfp, int vparam_len); +struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *, + const struct sctp_chunk *, + const int gfp, const int unkparam_len); -sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_cwr(const sctp_association_t *, +struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_cwr(const struct sctp_association *, const __u32 lowest_tsn, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_datafrag(sctp_association_t *, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_datafrag(struct sctp_association *, const struct sctp_sndrcvinfo *sinfo, int len, const __u8 *data, __u8 flags, __u16 ssn); -sctp_chunk_t * sctp_make_datafrag_empty(sctp_association_t *, +struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *, const struct sctp_sndrcvinfo *sinfo, int len, const __u8 flags, __u16 ssn); -sctp_chunk_t *sctp_make_data(sctp_association_t *, +struct sctp_chunk *sctp_make_data(struct sctp_association *, const struct sctp_sndrcvinfo *sinfo, int len, const __u8 *data); -sctp_chunk_t *sctp_make_data_empty(sctp_association_t *, +struct sctp_chunk *sctp_make_data_empty(struct sctp_association *, const struct sctp_sndrcvinfo *, int len); -sctp_chunk_t *sctp_make_ecne(const sctp_association_t *, +struct sctp_chunk *sctp_make_ecne(const struct sctp_association *, const __u32); -sctp_chunk_t *sctp_make_sack(const sctp_association_t *); -sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc); -sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *, - const sctp_chunk_t *); -void sctp_init_cause(sctp_chunk_t *, __u16 cause, const void *, size_t); -sctp_chunk_t *sctp_make_abort(const sctp_association_t *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_sack(const struct sctp_association *); +struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc); +struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_shutdown_complete(const struct sctp_association *, + const struct sctp_chunk *); +void sctp_init_cause(struct sctp_chunk *, __u16 cause, const void *, size_t); +struct sctp_chunk *sctp_make_abort(const struct sctp_association *, + const struct sctp_chunk *, const size_t hint); -sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_abort_no_data(const struct sctp_association *, + const struct sctp_chunk *, __u32 tsn); -sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *, + const struct sctp_chunk *, const struct msghdr *); -sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *, +struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *, const struct sctp_transport *, const void *payload, const size_t paylen); -sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *, + const struct sctp_chunk *, const void *payload, const size_t paylen); -sctp_chunk_t *sctp_make_op_error(const sctp_association_t *, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_op_error(const struct sctp_association *, + const struct sctp_chunk *chunk, __u16 cause_code, const void *payload, size_t paylen); -void sctp_chunk_assign_tsn(sctp_chunk_t *); -void sctp_chunk_assign_ssn(sctp_chunk_t *); -int sctp_datachunks_from_user(sctp_association_t *, - const struct sctp_sndrcvinfo *, - struct msghdr *, int len, - struct sk_buff_head *); - +void sctp_chunk_assign_tsn(struct sctp_chunk *); +void sctp_chunk_assign_ssn(struct sctp_chunk *); /* Prototypes for statetable processing. */ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, sctp_state_t state, - sctp_endpoint_t *, - sctp_association_t *asoc, + struct sctp_endpoint *, + struct sctp_association *asoc, void *event_arg, - int priority); + int gfp); int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, sctp_state_t state, - sctp_endpoint_t *, - sctp_association_t *asoc, + struct sctp_endpoint *, + struct sctp_association *asoc, void *event_arg, sctp_disposition_t status, sctp_cmd_seq_t *commands, - int priority); + int gfp); /* 2nd level prototypes */ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, sctp_state_t state, - sctp_endpoint_t *ep, - sctp_association_t *asoc, + struct sctp_endpoint *ep, + struct sctp_association *asoc, void *event_arg, sctp_disposition_t status, sctp_cmd_seq_t *retval, - int priority); + int gfp); -int sctp_gen_sack(sctp_association_t *, int force, sctp_cmd_seq_t *); -void sctp_do_TSNdup(sctp_association_t *, sctp_chunk_t *, long gap); +int sctp_gen_sack(struct sctp_association *, int force, sctp_cmd_seq_t *); +void sctp_do_TSNdup(struct sctp_association *, struct sctp_chunk *, long gap); void sctp_generate_t3_rtx_event(unsigned long peer); void sctp_generate_heartbeat_event(unsigned long peer); -sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *); +sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *); struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *, const struct sctp_association *, struct sctp_chunk *chunk, @@ -325,21 +315,21 @@ sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *, const struct sctp_chunk *, int *cookie_len, const __u8 *, int addrs_len); -sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *, - const sctp_association_t *, - sctp_chunk_t *, int priority, int *err, - sctp_chunk_t **err_chk_p); -int sctp_addip_addr_config(sctp_association_t *, sctp_param_t, +struct sctp_association *sctp_unpack_cookie(const struct sctp_endpoint *, + const struct sctp_association *, + struct sctp_chunk *, int gfp, int *err, + struct sctp_chunk **err_chk_p); +int sctp_addip_addr_config(struct sctp_association *, sctp_param_t, struct sockaddr_storage*, int); -void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, sctp_cmd_seq_t *commands, - sctp_chunk_t *err_chunk); + struct sctp_chunk *err_chunk); /* 3rd level prototypes */ -__u32 sctp_generate_tag(const sctp_endpoint_t *); -__u32 sctp_generate_tsn(const sctp_endpoint_t *); +__u32 sctp_generate_tag(const struct sctp_endpoint *); +__u32 sctp_generate_tsn(const struct sctp_endpoint *); /* 4th level prototypes */ void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *, @@ -361,7 +351,7 @@ /* Get the size of a DATA chunk payload. */ -static inline __u16 sctp_data_size(sctp_chunk_t *chunk) +static inline __u16 sctp_data_size(struct sctp_chunk *chunk) { __u16 size; @@ -449,8 +439,8 @@ * tag and the T bit is set in the Chunk Flags. */ static inline int -sctp_vtag_verify_either(const sctp_chunk_t *chunk, - const sctp_association_t *asoc) +sctp_vtag_verify_either(const struct sctp_chunk *chunk, + const struct sctp_association *asoc) { /* RFC 2960 Section 8.5.1, sctpimpguide-06 Section 2.13.2 * diff -urN linux-2.5.69-bk3/include/net/sctp/structs.h linux-2.5.69-bk4/include/net/sctp/structs.h --- linux-2.5.69-bk3/include/net/sctp/structs.h 2003-05-04 16:53:57.000000000 -0700 +++ linux-2.5.69-bk4/include/net/sctp/structs.h 2003-05-09 04:41:37.000000000 -0700 @@ -70,7 +70,6 @@ struct sockaddr sa; }; - /* Forward declarations for data structures. */ struct sctp_protocol; struct sctp_endpoint; @@ -83,14 +82,9 @@ struct sctp_bind_addr; struct sctp_ulpq; struct sctp_opt; -struct sctp_endpoint_common; +struct sctp_ep_common; struct sctp_ssnmap; -typedef struct sctp_endpoint sctp_endpoint_t; -typedef struct sctp_association sctp_association_t; -typedef struct sctp_chunk sctp_chunk_t; -typedef struct sctp_bind_addr sctp_bind_addr_t; -typedef struct sctp_endpoint_common sctp_endpoint_common_t; #include #include @@ -114,7 +108,7 @@ /* Used for hashing all associations. */ typedef struct sctp_hashbucket { rwlock_t lock; - sctp_endpoint_common_t *chain; + struct sctp_ep_common *chain; } sctp_hashbucket_t __attribute__((__aligned__(8))); @@ -235,7 +229,9 @@ int saddr); void (*from_sk) (union sctp_addr *, struct sock *sk); - void (*to_sk) (union sctp_addr *, + void (*to_sk_saddr) (union sctp_addr *, + struct sock *sk); + void (*to_sk_daddr) (union sctp_addr *, struct sock *sk); int (*addr_valid) (union sctp_addr *); sctp_scope_t (*scope) (union sctp_addr *); @@ -243,6 +239,7 @@ int (*is_any) (const union sctp_addr *); int (*available) (const union sctp_addr *); int (*skb_iif) (const struct sk_buff *sk); + int (*is_ce) (const struct sk_buff *sk); __u16 net_header_len; int sockaddr_len; sa_family_t sa_family; @@ -283,8 +280,11 @@ /* PF_ family specific functions. */ struct sctp_pf *pf; + /* Access to HMAC transform. */ + struct crypto_tfm *hmac; + /* What is our base endpointer? */ - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; /* Various Socket Options. */ __u16 default_stream; @@ -293,10 +293,12 @@ struct sctp_rtoinfo rtoinfo; struct sctp_paddrparams paddrparam; struct sctp_event_subscribe subscribe; + int user_frag; __u32 autoclose; __u8 nodelay; __u8 disable_fragments; __u8 pd_mode; + __u8 v4mapped; /* Receive to here while partial delivery is in effect. */ struct sk_buff_head pd_lobby; @@ -448,6 +450,37 @@ return stream->ssn[id]++; } +/* Structure to track chunk fragments that have been acked, but peer + * fragments of the same message have not. + */ +struct sctp_datamsg { + /* Chunks waiting to be submitted to lower layer. */ + struct list_head chunks; + /* Chunks that have been transmitted. */ + struct list_head track; + /* Reference counting. */ + atomic_t refcnt; + /* When is this message no longer interesting to the peer? */ + unsigned long expires_at; + /* Did the messenge fail to send? */ + int send_error; + char send_failed; + /* Control whether fragments from this message can expire. */ + char can_expire; +}; + +struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *, + struct sctp_sndrcvinfo *, + struct msghdr *, int len); +struct sctp_datamsg *sctp_datamsg_new(int gfp); +void sctp_datamsg_put(struct sctp_datamsg *); +void sctp_datamsg_hold(struct sctp_datamsg *); +void sctp_datamsg_free(struct sctp_datamsg *); +void sctp_datamsg_track(struct sctp_chunk *); +void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *); +void sctp_datamsg_fail(struct sctp_chunk *, int error); +int sctp_datamsg_expires(struct sctp_chunk *); + /* RFC2960 1.4 Key Terms * @@ -462,9 +495,10 @@ * three elements of struct sk_buff. This allows us to reuse * all the skb_* queue management functions. */ - sctp_chunk_t *next; - sctp_chunk_t *prev; + struct sctp_chunk *next; + struct sctp_chunk *prev; struct sk_buff_head *list; + atomic_t refcnt; /* This is our link to the per-transport transmitted list. */ struct list_head transmitted_list; @@ -514,43 +548,52 @@ struct sctp_association *asoc; /* What endpoint received this chunk? */ - sctp_endpoint_common_t *rcvr; + struct sctp_ep_common *rcvr; /* We fill this in if we are calculating RTT. */ unsigned long sent_at; - __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ - __u8 num_times_sent; /* How man times did we send this? */ - __u8 has_tsn; /* Does this chunk have a TSN yet? */ - __u8 has_ssn; /* Does this chunk have a SSN yet? */ - __u8 singleton; /* Was this the only chunk in the packet? */ - __u8 end_of_packet; /* Was this the last chunk in the packet? */ - __u8 ecn_ce_done; /* Have we processed the ECN CE bit? */ - __u8 pdiscard; /* Discard the whole packet now? */ - __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ - __u8 fast_retransmit; /* Is this chunk fast retransmitted? */ - __u8 tsn_missing_report; /* Data chunk missing counter. */ - /* What is the origin IP address for this chunk? */ union sctp_addr source; /* Destination address for this chunk. */ union sctp_addr dest; + /* For outbound message, track all fragments for SEND_FAILED. */ + struct sctp_datamsg *msg; + /* For an inbound chunk, this tells us where it came from. * For an outbound chunk, it tells us where we'd like it to * go. It is NULL if we have no preference. */ struct sctp_transport *transport; + + __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ + __u8 resent; /* Has this chunk ever been retransmitted. */ + __u8 has_tsn; /* Does this chunk have a TSN yet? */ + __u8 has_ssn; /* Does this chunk have a SSN yet? */ + __u8 singleton; /* Was this the only chunk in the packet? */ + __u8 end_of_packet; /* Was this the last chunk in the packet? */ + __u8 ecn_ce_done; /* Have we processed the ECN CE bit? */ + __u8 pdiscard; /* Discard the whole packet now? */ + __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ + __u8 fast_retransmit; /* Is this chunk fast retransmitted? */ + __u8 tsn_missing_report; /* Data chunk missing counter. */ }; -sctp_chunk_t *sctp_make_chunk(const struct sctp_association *, __u8 type, - __u8 flags, int size); -void sctp_free_chunk(sctp_chunk_t *); -void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data); -sctp_chunk_t *sctp_chunkify(struct sk_buff *, const struct sctp_association *, - struct sock *); -void sctp_init_addrs(sctp_chunk_t *, union sctp_addr *, union sctp_addr *); -const union sctp_addr *sctp_source(const sctp_chunk_t *chunk); +void sctp_chunk_hold(struct sctp_chunk *); +void sctp_chunk_put(struct sctp_chunk *); +int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len, + struct iovec *data); +struct sctp_chunk *sctp_make_chunk(const struct sctp_association *, __u8 type, + __u8 flags, int size); +void sctp_chunk_free(struct sctp_chunk *); +void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data); +struct sctp_chunk *sctp_chunkify(struct sk_buff *, + const struct sctp_association *, + struct sock *); +void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *, + union sctp_addr *); +const union sctp_addr *sctp_source(const struct sctp_chunk *chunk); /* This is a structure for holding either an IPv6 or an IPv4 address. */ /* sin_family -- AF_INET or AF_INET6 @@ -562,7 +605,7 @@ union sctp_addr a; }; -typedef sctp_chunk_t *(sctp_packet_phandler_t)(struct sctp_association *); +typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *); /* This structure holds lists of chunks as we are assembling for * transmission. @@ -619,7 +662,7 @@ int ecn_capable, sctp_packet_phandler_t *get_prepend_chunk); typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *, - sctp_chunk_t *); + struct sctp_chunk *); typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *); sctp_outq_ohandler_init_t sctp_packet_init; @@ -697,7 +740,6 @@ */ int rto_pending; - /* * These are the congestion stats. */ @@ -771,9 +813,6 @@ */ int max_retrans; - /* We use this name for debugging output... */ - char *debug_name; - /* Per : A timer used by each destination. * Destination : * Timer : @@ -799,6 +838,35 @@ struct list_head send_ready; int malloced; /* Is this structure kfree()able? */ + + /* State information saved for SFR_CACC algorithm. The key + * idea in SFR_CACC is to maintain state at the sender on a + * per-destination basis when a changeover happens. + * char changeover_active; + * char cycling_changeover; + * __u32 next_tsn_at_change; + * char cacc_saw_newack; + */ + struct { + /* An unsigned integer, which stores the next TSN to be + * used by the sender, at the moment of changeover. + */ + __u32 next_tsn_at_change; + + /* A flag which indicates the occurrence of a changeover */ + char changeover_active; + + /* A glag which indicates whether the change of primary is + * the first switch to this destination address during an + * active switch. + */ + char cycling_changeover; + + /* A temporary flag, which is used during the processing of + * a SACK to estimate the causative TSN(s)'s group. + */ + char cacc_saw_newack; + } cacc; }; struct sctp_transport *sctp_transport_new(const union sctp_addr *, int); @@ -831,7 +899,7 @@ /* This is the packet which is currently off the in queue and is * being worked on through the inbound chunk processing. */ - sctp_chunk_t *in_progress; + struct sctp_chunk *in_progress; /* This is the delayed task to finish delivering inbound * messages. @@ -844,7 +912,7 @@ struct sctp_inq *sctp_inq_new(void); void sctp_inq_init(struct sctp_inq *); void sctp_inq_free(struct sctp_inq *); -void sctp_inq_push(struct sctp_inq *, sctp_chunk_t *packet); +void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet); struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *); @@ -904,18 +972,21 @@ /* How many unackd bytes do we have in-flight? */ __u32 outstanding_bytes; + /* Corked? */ + char cork; + /* Is this structure empty? */ - int empty; + char empty; /* Are we kfree()able? */ - int malloced; + char malloced; }; struct sctp_outq *sctp_outq_new(struct sctp_association *); void sctp_outq_init(struct sctp_association *, struct sctp_outq *); void sctp_outq_teardown(struct sctp_outq *); void sctp_outq_free(struct sctp_outq*); -int sctp_outq_tail(struct sctp_outq *, sctp_chunk_t *chunk); +int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk); int sctp_outq_flush(struct sctp_outq *, int); int sctp_outq_sack(struct sctp_outq *, sctp_sackhdr_t *); int sctp_outq_is_empty(const struct sctp_outq *); @@ -926,10 +997,16 @@ sctp_outq_ohandler_t build, sctp_outq_ohandler_force_t force); void sctp_outq_restart(struct sctp_outq *); + void sctp_retransmit(struct sctp_outq *, struct sctp_transport *, sctp_retransmit_reason_t); void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8); - +int sctp_outq_uncork(struct sctp_outq *); +/* Uncork and flush an outqueue. */ +static inline void sctp_outq_cork(struct sctp_outq *q) +{ + q->cork = 1; +} /* These bind address data fields common between endpoints and associations */ struct sctp_bind_addr { @@ -952,15 +1029,16 @@ int malloced; /* Are we kfree()able? */ }; -sctp_bind_addr_t *sctp_bind_addr_new(int gfp_mask); -void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port); -void sctp_bind_addr_free(sctp_bind_addr_t *); -int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, +struct sctp_bind_addr *sctp_bind_addr_new(int gfp_mask); +void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port); +void sctp_bind_addr_free(struct sctp_bind_addr *); +int sctp_bind_addr_copy(struct sctp_bind_addr *dest, + const struct sctp_bind_addr *src, sctp_scope_t scope, int gfp,int flags); -int sctp_add_bind_addr(sctp_bind_addr_t *, union sctp_addr *, +int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, int gfp); -int sctp_del_bind_addr(sctp_bind_addr_t *, union sctp_addr *); -int sctp_bind_addr_match(sctp_bind_addr_t *, const union sctp_addr *, +int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *); +int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *, struct sctp_opt *); union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, int *addrs_len, int gfp); @@ -973,7 +1051,7 @@ int sctp_addr_is_valid(const union sctp_addr *addr); -/* What type of sctp_endpoint_common? */ +/* What type of endpoint? */ typedef enum { SCTP_EP_TYPE_SOCKET, SCTP_EP_TYPE_ASSOCIATION, @@ -995,10 +1073,10 @@ * */ -struct sctp_endpoint_common { +struct sctp_ep_common { /* Fields to help us manage our entries in the hash tables. */ - sctp_endpoint_common_t *next; - sctp_endpoint_common_t **pprev; + struct sctp_ep_common *next; + struct sctp_ep_common **pprev; int hashent; /* Runtime type information. What kind of endpoint is this? */ @@ -1024,7 +1102,7 @@ * bind_addr.port is our shared port number. * bind_addr.address_list is our set of local IP addresses. */ - sctp_bind_addr_t bind_addr; + struct sctp_bind_addr bind_addr; /* Protection during address list comparisons. */ rwlock_t addr_lock; @@ -1052,12 +1130,7 @@ struct sctp_endpoint { /* Common substructure for endpoint and association. */ - sctp_endpoint_common_t base; - - /* These are the system-wide defaults and other stuff which is - * endpoint-independent. - */ - struct sctp_protocol *proto; + struct sctp_ep_common base; /* Associations: A list of current associations and mappings * to the data consumers for each association. This @@ -1092,28 +1165,29 @@ }; /* Recover the outter endpoint structure. */ -static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base) +static inline struct sctp_endpoint *sctp_ep(struct sctp_ep_common *base) { - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; - ep = container_of(base, sctp_endpoint_t, base); + ep = container_of(base, struct sctp_endpoint, base); return ep; } /* These are function signatures for manipulating endpoints. */ -sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *, struct sock *, int); -sctp_endpoint_t *sctp_endpoint_init(struct sctp_endpoint *, - struct sctp_protocol *, - struct sock *, int gfp); -void sctp_endpoint_free(sctp_endpoint_t *); -void sctp_endpoint_put(sctp_endpoint_t *); -void sctp_endpoint_hold(sctp_endpoint_t *); -void sctp_endpoint_add_asoc(sctp_endpoint_t *, struct sctp_association *asoc); -struct sctp_association *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, - const union sctp_addr *paddr, - struct sctp_transport **); -int sctp_endpoint_is_peeled_off(sctp_endpoint_t *, const union sctp_addr *); -sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, +struct sctp_endpoint *sctp_endpoint_new(struct sock *, int); +struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *, + struct sock *, int gfp); +void sctp_endpoint_free(struct sctp_endpoint *); +void sctp_endpoint_put(struct sctp_endpoint *); +void sctp_endpoint_hold(struct sctp_endpoint *); +void sctp_endpoint_add_asoc(struct sctp_endpoint *, struct sctp_association *); +struct sctp_association *sctp_endpoint_lookup_assoc( + const struct sctp_endpoint *ep, + const union sctp_addr *paddr, + struct sctp_transport **); +int sctp_endpoint_is_peeled_off(struct sctp_endpoint *, + const union sctp_addr *); +struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *, const union sctp_addr *); int sctp_has_association(const union sctp_addr *laddr, const union sctp_addr *paddr); @@ -1126,8 +1200,8 @@ sctp_init_chunk_t *init, int gfp); int sctp_process_param(struct sctp_association *, union sctp_params param, const union sctp_addr *from, int gfp); -__u32 sctp_generate_tag(const sctp_endpoint_t *); -__u32 sctp_generate_tsn(const sctp_endpoint_t *); +__u32 sctp_generate_tag(const struct sctp_endpoint *); +__u32 sctp_generate_tsn(const struct sctp_endpoint *); /* RFC2960 @@ -1150,7 +1224,7 @@ * In this context, it represents the associations's view * of the local endpoint of the association. */ - sctp_endpoint_common_t base; + struct sctp_ep_common base; /* Associations on the same socket. */ struct list_head asocs; @@ -1162,7 +1236,7 @@ __u32 eyecatcher; /* This is our parent endpoint. */ - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; /* These are those association elements needed in the cookie. */ sctp_cookie_t c; @@ -1337,7 +1411,6 @@ /* The largest timeout or RTO value to use in attempting an INIT */ __u16 max_init_timeo; - int timeouts[SCTP_NUM_TIMEOUT_TYPES]; struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; @@ -1438,9 +1511,6 @@ */ struct sctp_ulpq ulpq; - /* Need to send an ECNE Chunk? */ - int need_ecne; - /* Last TSN that caused an ECNE Chunk to be sent. */ __u32 last_ecne_tsn; @@ -1453,9 +1523,6 @@ /* Number of seconds of idle time before an association is closed. */ __u32 autoclose; - /* Name for debugging output... */ - char *debug_name; - /* These are to support * "SCTP Extensions for Dynamic Reconfiguration of IP Addresses * and Enforcement of Flow and Message Limits" @@ -1463,8 +1530,7 @@ * or "ADDIP" for short. */ - /* Is the ADDIP extension enabled for this association? */ - int addip_enable; + /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks * @@ -1480,7 +1546,7 @@ * [This is our one-and-only-one ASCONF in flight. If we do * not have an ASCONF in flight, this is NULL.] */ - sctp_chunk_t *addip_last_asconf; + struct sctp_chunk *addip_last_asconf; /* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. * @@ -1495,7 +1561,7 @@ * [This is our saved ASCONF-ACK. We invalidate it when a new * ASCONF serial number arrives.] */ - sctp_chunk_t *addip_last_asconf_ack; + struct sctp_chunk *addip_last_asconf_ack; /* These ASCONF chunks are waiting to be sent. * @@ -1548,6 +1614,15 @@ * after reaching 4294967295. */ __u32 addip_serial; + + /* Is the ADDIP extension enabled for this association? */ + char addip_enable; + + /* Need to send an ECNE Chunk? */ + char need_ecne; + + /* Is it a temporary association? */ + char temp; }; @@ -1559,7 +1634,7 @@ }; /* Recover the outter association structure. */ -static inline struct sctp_association *sctp_assoc(sctp_endpoint_common_t *base) +static inline struct sctp_association *sctp_assoc(struct sctp_ep_common *base) { struct sctp_association *asoc; @@ -1571,10 +1646,10 @@ struct sctp_association * -sctp_association_new(const sctp_endpoint_t *, const struct sock *, +sctp_association_new(const struct sctp_endpoint *, const struct sock *, sctp_scope_t scope, int gfp); struct sctp_association * -sctp_association_init(struct sctp_association *, const sctp_endpoint_t *, +sctp_association_init(struct sctp_association *, const struct sctp_endpoint *, const struct sock *, sctp_scope_t scope, int gfp); void sctp_association_free(struct sctp_association *); @@ -1614,8 +1689,8 @@ int sctp_cmp_addr_exact(const union sctp_addr *ss1, const union sctp_addr *ss2); -sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc); -sctp_chunk_t *sctp_get_no_prepend(struct sctp_association *asoc); +struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc); +struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc); /* A convenience structure to parse out SCTP specific CMSGs. */ typedef struct sctp_cmsgs { diff -urN linux-2.5.69-bk3/include/net/sctp/tsnmap.h linux-2.5.69-bk4/include/net/sctp/tsnmap.h --- linux-2.5.69-bk3/include/net/sctp/tsnmap.h 2003-05-04 16:53:35.000000000 -0700 +++ linux-2.5.69-bk4/include/net/sctp/tsnmap.h 2003-05-09 04:41:37.000000000 -0700 @@ -114,7 +114,7 @@ }; /* Create a new tsnmap. */ -struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int priority); +struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int gfp); /* Dispose of a tsnmap. */ void sctp_tsnmap_free(struct sctp_tsnmap *); diff -urN linux-2.5.69-bk3/include/net/sctp/ulpevent.h linux-2.5.69-bk4/include/net/sctp/ulpevent.h --- linux-2.5.69-bk3/include/net/sctp/ulpevent.h 2003-05-04 16:53:02.000000000 -0700 +++ linux-2.5.69-bk4/include/net/sctp/ulpevent.h 2003-05-09 04:41:37.000000000 -0700 @@ -10,13 +10,15 @@ * sctp_ulpevent type is used to carry information from the state machine * upwards to the ULP. * - * The SCTP reference implementation is free software; + * This file is part of the SCTP kernel reference Implementation + * + * The SCTP reference implementation is free software; * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * the SCTP reference implementation is distributed in the hope that it + * The SCTP reference implementation is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied * ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. @@ -27,12 +29,17 @@ * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * - * Please send any bug reports or fixes you make to one of the - * following email addresses: - * - * Jon Grimm - * La Monte H.P. Yarroll - * Karl Knutson + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm + * La Monte H.P. Yarroll + * Karl Knutson * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -64,7 +71,7 @@ return (struct sctp_ulpevent *)skb->cb; } -struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int priority); +struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int gfp); struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags); void sctp_ulpevent_free(struct sctp_ulpevent *); int sctp_ulpevent_is_notification(const struct sctp_ulpevent *); @@ -76,7 +83,7 @@ __u16 error, __u16 outbound, __u16 inbound, - int priority); + int gfp); struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( const struct sctp_association *asoc, @@ -84,32 +91,32 @@ int flags, int state, int error, - int priority); + int gfp); struct sctp_ulpevent *sctp_ulpevent_make_remote_error( const struct sctp_association *asoc, struct sctp_chunk *chunk, __u16 flags, - int priority); + int gfp); struct sctp_ulpevent *sctp_ulpevent_make_send_failed( const struct sctp_association *asoc, struct sctp_chunk *chunk, __u16 flags, __u32 error, - int priority); + int gfp); struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( const struct sctp_association *asoc, __u16 flags, - int priority); + int gfp); struct sctp_ulpevent *sctp_ulpevent_make_pdapi( const struct sctp_association *asoc, - __u32 indication, int priority); + __u32 indication, int gfp); struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, struct sctp_chunk *chunk, - int priority); + int gfp); void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, struct msghdr *); diff -urN linux-2.5.69-bk3/include/net/sctp/ulpqueue.h linux-2.5.69-bk4/include/net/sctp/ulpqueue.h --- linux-2.5.69-bk3/include/net/sctp/ulpqueue.h 2003-05-04 16:53:09.000000000 -0700 +++ linux-2.5.69-bk4/include/net/sctp/ulpqueue.h 2003-05-09 04:41:37.000000000 -0700 @@ -50,14 +50,15 @@ struct sctp_ulpq { char malloced; char pd_mode; - sctp_association_t *asoc; + struct sctp_association *asoc; struct sk_buff_head reasm; struct sk_buff_head lobby; }; /* Prototypes. */ -struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority); -struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *); +struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp); +struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, + struct sctp_association *); void sctp_ulpq_free(struct sctp_ulpq *); /* Add a new DATA chunk for processing. */ diff -urN linux-2.5.69-bk3/include/net/sctp/user.h linux-2.5.69-bk4/include/net/sctp/user.h --- linux-2.5.69-bk3/include/net/sctp/user.h 2003-05-04 16:52:49.000000000 -0700 +++ linux-2.5.69-bk4/include/net/sctp/user.h 2003-05-09 04:41:37.000000000 -0700 @@ -110,6 +110,10 @@ #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS SCTP_NODELAY, /* Get/set nodelay option. */ #define SCTP_NODELAY SCTP_NODELAY + SCTP_I_WANT_MAPPED_V4_ADDR, /* Turn on/off mapped v4 addresses */ +#define SCTP_I_WANT_MAPPED_V4_ADDR SCTP_I_WANT_MAPPED_V4_ADDR + SCTP_MAXSEG, /* Get/set maximum fragment. */ +#define SCTP_MAXSEG SCTP_MAXSEG }; diff -urN linux-2.5.69-bk3/net/atm/br2684.c linux-2.5.69-bk4/net/atm/br2684.c --- linux-2.5.69-bk3/net/atm/br2684.c 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/net/atm/br2684.c 2003-05-09 04:41:38.000000000 -0700 @@ -481,6 +481,7 @@ } brdev->stats.rx_packets++; brdev->stats.rx_bytes += skb->len; + memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(skb); } diff -urN linux-2.5.69-bk3/net/atm/clip.c linux-2.5.69-bk4/net/atm/clip.c --- linux-2.5.69-bk3/net/atm/clip.c 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/net/atm/clip.c 2003-05-09 04:41:38.000000000 -0700 @@ -223,6 +223,7 @@ clip_vcc->last_use = jiffies; PRIV(skb->dev)->stats.rx_packets++; PRIV(skb->dev)->stats.rx_bytes += skb->len; + memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(skb); } @@ -432,7 +433,6 @@ ((u16 *) here)[3] = skb->protocol; } atomic_add(skb->truesize,&vcc->sk->wmem_alloc); - ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = vcc->atm_options; entry->vccs->last_use = jiffies; DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev); diff -urN linux-2.5.69-bk3/net/atm/common.c linux-2.5.69-bk4/net/atm/common.c --- linux-2.5.69-bk3/net/atm/common.c 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/net/atm/common.c 2003-05-09 04:41:38.000000000 -0700 @@ -98,7 +98,7 @@ } while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule(); DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->sk->wmem_alloc),skb->truesize); - atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc); + atomic_add(skb->truesize, &vcc->sk->wmem_alloc); return skb; } @@ -114,7 +114,6 @@ vcc = atm_sk(sk); memset(&vcc->flags,0,sizeof(vcc->flags)); vcc->dev = NULL; - vcc->alloc_tx = alloc_tx; vcc->callback = NULL; memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc)); memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc)); @@ -144,9 +143,7 @@ if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */ while ((skb = skb_dequeue(&vcc->sk->receive_queue))) { atm_return(vcc,skb->truesize); - if (vcc->dev->ops->free_rx_skb) - vcc->dev->ops->free_rx_skb(vcc,skb); - else kfree_skb(skb); + kfree_skb(skb); } spin_lock (&atm_dev_lock); fops_put (vcc->dev->ops); @@ -394,31 +391,8 @@ (unsigned long) buff,eff_len); DPRINTK("RcvM %d -= %d\n",atomic_read(&vcc->sk->rmem_alloc),skb->truesize); atm_return(vcc,skb->truesize); - if (ATM_SKB(skb)->iovcnt) { /* @@@ hack */ - /* iovcnt set, use scatter-gather for receive */ - int el, cnt; - struct iovec *iov = (struct iovec *)skb->data; - unsigned char *p = (unsigned char *)buff; - - el = eff_len; - error = 0; - for (cnt = 0; (cnt < ATM_SKB(skb)->iovcnt) && el; cnt++) { -/*printk("s-g???: %p -> %p (%d)\n",iov->iov_base,p,iov->iov_len);*/ - error = copy_to_user(p,iov->iov_base, - (iov->iov_len > el) ? el : iov->iov_len) ? - -EFAULT : 0; - if (error) break; - p += iov->iov_len; - el -= (iov->iov_len > el)?el:iov->iov_len; - iov++; - } - if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb); - else vcc->dev->ops->free_rx_skb(vcc, skb); - return error ? error : eff_len; - } error = copy_to_user(buff,skb->data,eff_len) ? -EFAULT : 0; - if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb); - else vcc->dev->ops->free_rx_skb(vcc, skb); + kfree_skb(skb); return error ? error : eff_len; } @@ -450,7 +424,7 @@ add_wait_queue(&vcc->sleep,&wait); set_current_state(TASK_INTERRUPTIBLE); error = 0; - while (!(skb = vcc->alloc_tx(vcc,eff))) { + while (!(skb = alloc_tx(vcc,eff))) { if (m->msg_flags & MSG_DONTWAIT) { error = -EAGAIN; break; @@ -475,7 +449,6 @@ remove_wait_queue(&vcc->sleep,&wait); if (error) return error; skb->dev = NULL; /* for paths shared with net_device interfaces */ - ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = vcc->atm_options; if (copy_from_user(skb_put(skb,size),buff,size)) { kfree_skb(skb); @@ -502,8 +475,7 @@ mask |= POLLHUP; if (sock->state != SS_CONNECTING) { if (vcc->qos.txtp.traffic_class != ATM_NONE && - vcc->qos.txtp.max_sdu+atomic_read(&vcc->sk->wmem_alloc)+ - ATM_PDU_OVHD <= vcc->sk->sndbuf) + vcc->qos.txtp.max_sdu+atomic_read(&vcc->sk->wmem_alloc) <= vcc->sk->sndbuf) mask |= POLLOUT | POLLWRNORM; } else if (vcc->reply != WAITING) { @@ -570,7 +542,7 @@ goto done; } ret_val = put_user(vcc->sk->sndbuf- - atomic_read(&vcc->sk->wmem_alloc)-ATM_PDU_OVHD, + atomic_read(&vcc->sk->wmem_alloc), (int *) arg) ? -EFAULT : 0; goto done; case SIOCINQ: diff -urN linux-2.5.69-bk3/net/atm/lec.c linux-2.5.69-bk4/net/atm/lec.c --- linux-2.5.69-bk3/net/atm/lec.c 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/net/atm/lec.c 2003-05-09 04:41:38.000000000 -0700 @@ -204,7 +204,6 @@ if (atm_may_send(vcc, skb->len)) { atomic_add(skb->truesize, &vcc->sk->wmem_alloc); ATM_SKB(skb)->vcc = vcc; - ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = vcc->atm_options; priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len; @@ -399,7 +398,7 @@ int i; char *tmp; /* FIXME */ - atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->sk->wmem_alloc); + atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); mesg = (struct atmlec_msg *)skb->data; tmp = skb->data; tmp += sizeof(struct atmlec_msg); @@ -715,6 +714,7 @@ skb->protocol = eth_type_trans(skb, dev); priv->stats.rx_packets++; priv->stats.rx_bytes += skb->len; + memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(skb); } } diff -urN linux-2.5.69-bk3/net/atm/mpc.c linux-2.5.69-bk4/net/atm/mpc.c --- linux-2.5.69-bk3/net/atm/mpc.c 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/net/atm/mpc.c 2003-05-09 04:41:38.000000000 -0700 @@ -523,7 +523,6 @@ } atomic_add(skb->truesize, &entry->shortcut->sk->wmem_alloc); - ATM_SKB(skb)->iovcnt = 0; /* just to be safe ... */ ATM_SKB(skb)->atm_options = entry->shortcut->atm_options; entry->shortcut->send(entry->shortcut, skb); entry->packets_fwded++; @@ -732,6 +731,7 @@ eg->packets_rcvd++; mpc->eg_ops->put(eg); + memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(new_skb); return; @@ -863,7 +863,7 @@ struct mpoa_client *mpc = find_mpc_by_vcc(vcc); struct k_message *mesg = (struct k_message*)skb->data; - atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->sk->wmem_alloc); + atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); if (mpc == NULL) { printk("mpoa: msg_from_mpoad: no mpc found\n"); diff -urN linux-2.5.69-bk3/net/atm/pppoatm.c linux-2.5.69-bk4/net/atm/pppoatm.c --- linux-2.5.69-bk3/net/atm/pppoatm.c 2003-05-04 16:53:33.000000000 -0700 +++ linux-2.5.69-bk4/net/atm/pppoatm.c 2003-05-09 04:41:38.000000000 -0700 @@ -232,7 +232,6 @@ return 1; } atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->sk->wmem_alloc); - ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; DPRINTK("(unit %d): atm_skb(%p)->vcc(%p)->dev(%p)\n", pvcc->chan.unit, skb, ATM_SKB(skb)->vcc, diff -urN linux-2.5.69-bk3/net/atm/raw.c linux-2.5.69-bk4/net/atm/raw.c --- linux-2.5.69-bk3/net/atm/raw.c 2003-05-04 16:53:41.000000000 -0700 +++ linux-2.5.69-bk4/net/atm/raw.c 2003-05-09 04:41:38.000000000 -0700 @@ -37,7 +37,7 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) { DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->sk->wmem_alloc,skb->truesize); - atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc); + atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); dev_kfree_skb_any(skb); wake_up(&vcc->sleep); } diff -urN linux-2.5.69-bk3/net/atm/signaling.c linux-2.5.69-bk4/net/atm/signaling.c --- linux-2.5.69-bk3/net/atm/signaling.c 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/net/atm/signaling.c 2003-05-09 04:41:38.000000000 -0700 @@ -98,7 +98,7 @@ struct atm_vcc *session_vcc; msg = (struct atmsvc_msg *) skb->data; - atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc); + atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type, (unsigned long) msg->vcc); vcc = *(struct atm_vcc **) &msg->vcc; diff -urN linux-2.5.69-bk3/net/core/pktgen.c linux-2.5.69-bk4/net/core/pktgen.c --- linux-2.5.69-bk3/net/core/pktgen.c 2003-05-04 16:53:35.000000000 -0700 +++ linux-2.5.69-bk4/net/core/pktgen.c 2003-05-09 04:41:38.000000000 -0700 @@ -226,21 +226,20 @@ { struct net_device *odev; - rtnl_lock(); - odev = __dev_get_by_name(info->outdev); + odev = dev_get_by_name(info->outdev); if (!odev) { sprintf(info->result, "No such netdevice: \"%s\"", info->outdev); - goto out_unlock; + goto out; } if (odev->type != ARPHRD_ETHER) { sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev); - goto out_unlock; + goto out_put; } if (!netif_running(odev)) { sprintf(info->result, "Device is down: \"%s\"", info->outdev); - goto out_unlock; + goto out_put; } /* Default to the interface's mac if not explicitly set. */ @@ -257,13 +256,13 @@ info->saddr_min = 0; info->saddr_max = 0; if (strlen(info->src_min) == 0) { - if (odev->ip_ptr) { - struct in_device *in_dev = odev->ip_ptr; - + struct in_device *in_dev = in_dev_get(odev); + if (in_dev) { if (in_dev->ifa_list) { info->saddr_min = in_dev->ifa_list->ifa_address; info->saddr_max = info->saddr_min; } + in_dev_put(in_dev); } } else { @@ -282,13 +281,11 @@ info->cur_udp_dst = info->udp_dst_min; info->cur_udp_src = info->udp_src_min; - atomic_inc(&odev->refcnt); - rtnl_unlock(); - return odev; -out_unlock: - rtnl_unlock(); +out_put: + dev_put(odev); +out: return NULL; } @@ -1258,7 +1255,6 @@ } if (!strcmp(name, "inject") || !strcmp(name, "start")) { - MOD_INC_USE_COUNT; if (info->busy) { strcpy(info->result, "Already running...\n"); } @@ -1268,7 +1264,6 @@ inject(info); info->busy = 0; } - MOD_DEC_USE_COUNT; return count; } @@ -1337,6 +1332,7 @@ pginfos[i].proc_ent->read_proc = proc_read; pginfos[i].proc_ent->write_proc = proc_write; pginfos[i].proc_ent->data = (void*)(long)(i); + pginfos[i].proc_ent->owner = THIS_MODULE; sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i", PG_PROC_DIR, i); pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0); diff -urN linux-2.5.69-bk3/net/decnet/dn_dev.c linux-2.5.69-bk4/net/decnet/dn_dev.c --- linux-2.5.69-bk3/net/decnet/dn_dev.c 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/net/decnet/dn_dev.c 2003-05-09 04:41:38.000000000 -0700 @@ -561,7 +561,6 @@ struct dn_dev *dn_db; struct net_device *dev; struct dn_ifaddr *ifa = NULL, **ifap = NULL; - int exclusive = 0; int ret = 0; if (copy_from_user(ifr, arg, DN_IFREQ_SIZE)) @@ -580,13 +579,13 @@ return -EACCES; if (sdn->sdn_family != AF_DECnet) return -EINVAL; - rtnl_lock(); - exclusive = 1; break; default: return -EINVAL; } + rtnl_lock(); + if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) { ret = -ENODEV; goto done; @@ -626,15 +625,13 @@ ret = dn_dev_set_ifa(dev, ifa); } done: - if (exclusive) - rtnl_unlock(); + rtnl_unlock(); return ret; rarok: if (copy_to_user(arg, ifr, DN_IFREQ_SIZE)) - return -EFAULT; - - return 0; + ret = -EFAULT; + goto done; } static struct dn_dev *dn_dev_by_index(int ifindex) diff -urN linux-2.5.69-bk3/net/decnet/dn_fib.c linux-2.5.69-bk4/net/decnet/dn_fib.c --- linux-2.5.69-bk3/net/decnet/dn_fib.c 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/net/decnet/dn_fib.c 2003-05-09 04:41:38.000000000 -0700 @@ -218,7 +218,7 @@ if (!(dev->flags&IFF_UP)) return -ENETDOWN; nh->nh_dev = dev; - atomic_inc(&dev->refcnt); + dev_hold(dev); nh->nh_scope = RT_SCOPE_LINK; return 0; } @@ -242,7 +242,7 @@ nh->nh_dev = DN_FIB_RES_DEV(res); if (nh->nh_dev == NULL) goto out; - atomic_inc(&nh->nh_dev->refcnt); + dev_hold(nh->nh_dev); err = -ENETDOWN; if (!(nh->nh_dev->flags & IFF_UP)) goto out; @@ -262,7 +262,7 @@ if (!(dev->flags&IFF_UP)) return -ENETDOWN; nh->nh_dev = dev; - atomic_inc(&nh->nh_dev->refcnt); + dev_hold(nh->nh_dev); nh->nh_scope = RT_SCOPE_HOST; } diff -urN linux-2.5.69-bk3/net/decnet/dn_rules.c linux-2.5.69-bk4/net/decnet/dn_rules.c --- linux-2.5.69-bk3/net/decnet/dn_rules.c 2003-05-04 16:53:36.000000000 -0700 +++ linux-2.5.69-bk4/net/decnet/dn_rules.c 2003-05-09 04:41:38.000000000 -0700 @@ -173,9 +173,11 @@ memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ); new_r->r_ifname[IFNAMSIZ-1] = 0; new_r->r_ifindex = -1; - dev = __dev_get_by_name(new_r->r_ifname); - if (dev) + dev = dev_get_by_name(new_r->r_ifname); + if (dev) { new_r->r_ifindex = dev->ifindex; + dev_put(dev); + } } rp = &dn_fib_rules; diff -urN linux-2.5.69-bk3/net/econet/af_econet.c linux-2.5.69-bk4/net/econet/af_econet.c --- linux-2.5.69-bk3/net/econet/af_econet.c 2003-05-04 16:53:14.000000000 -0700 +++ linux-2.5.69-bk4/net/econet/af_econet.c 2003-05-09 04:41:38.000000000 -0700 @@ -325,7 +325,7 @@ { /* Real hardware Econet. We're not worthy etc. */ #ifdef CONFIG_ECONET_NATIVE - atomic_inc(&dev->refcnt); + dev_hold(dev); skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, msg->msg_flags & MSG_DONTWAIT, &err); diff -urN linux-2.5.69-bk3/net/ipv4/ipcomp.c linux-2.5.69-bk4/net/ipv4/ipcomp.c --- linux-2.5.69-bk3/net/ipv4/ipcomp.c 2003-05-04 16:53:40.000000000 -0700 +++ linux-2.5.69-bk4/net/ipv4/ipcomp.c 2003-05-09 04:41:38.000000000 -0700 @@ -94,7 +94,9 @@ memcpy(&tmp_iph, iph, iph->ihl * 4); nexthdr = *(u8 *)skb->data; skb_pull(skb, sizeof(struct ipcomp_hdr)); + skb->nh.raw += sizeof(struct ipcomp_hdr); memcpy(skb->nh.raw, &tmp_iph, tmp_iph.iph.ihl * 4); + iph = skb->nh.iph; iph->tot_len = htons(ntohs(iph->tot_len) - sizeof(struct ipcomp_hdr)); iph->protocol = nexthdr; skb->h.raw = skb->data; diff -urN linux-2.5.69-bk3/net/ipv4/netfilter/ip_nat_core.c linux-2.5.69-bk4/net/ipv4/netfilter/ip_nat_core.c --- linux-2.5.69-bk3/net/ipv4/netfilter/ip_nat_core.c 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/net/ipv4/netfilter/ip_nat_core.c 2003-05-09 04:41:38.000000000 -0700 @@ -861,6 +861,7 @@ } *inside; unsigned int i; struct ip_nat_info *info = &conntrack->nat.info; + int hdrlen; if (!skb_ip_make_writable(pskb,(*pskb)->nh.iph->ihl*4+sizeof(*inside))) return 0; @@ -868,10 +869,12 @@ /* We're actually going to mangle it beyond trivial checksum adjustment, so make sure the current checksum is correct. */ - if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY - && (u16)csum_fold(skb_checksum(*pskb, (*pskb)->nh.iph->ihl*4, - (*pskb)->len, 0))) - return 0; + if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) { + hdrlen = (*pskb)->nh.iph->ihl * 4; + if ((u16)csum_fold(skb_checksum(*pskb, hdrlen, + (*pskb)->len - hdrlen, 0))) + return 0; + } /* Must be RELATED */ IP_NF_ASSERT((*pskb)->nfct @@ -948,10 +951,12 @@ } READ_UNLOCK(&ip_nat_lock); + hdrlen = (*pskb)->nh.iph->ihl * 4; + inside->icmp.checksum = 0; - inside->icmp.checksum = csum_fold(skb_checksum(*pskb, - (*pskb)->nh.iph->ihl*4, - (*pskb)->len, 0)); + inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen, + (*pskb)->len - hdrlen, + 0)); return 1; unlock_fail: diff -urN linux-2.5.69-bk3/net/ipv4/route.c linux-2.5.69-bk4/net/ipv4/route.c --- linux-2.5.69-bk3/net/ipv4/route.c 2003-05-04 16:53:56.000000000 -0700 +++ linux-2.5.69-bk4/net/ipv4/route.c 2003-05-09 04:41:38.000000000 -0700 @@ -431,16 +431,17 @@ rth->u.dst.expires; } -static int rt_may_expire(struct rtable *rth, int tmo1, int tmo2) +static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2) { - int age; + unsigned long age; int ret = 0; if (atomic_read(&rth->u.dst.__refcnt)) goto out; ret = 1; - if (rth->u.dst.expires && (long)(rth->u.dst.expires - jiffies) <= 0) + if (rth->u.dst.expires && + time_after_eq(jiffies, rth->u.dst.expires)) goto out; age = jiffies - rth->u.dst.lastuse; @@ -462,7 +463,7 @@ for (t = ip_rt_gc_interval << rt_hash_log; t >= 0; t -= ip_rt_gc_timeout) { - unsigned tmo = ip_rt_gc_timeout; + unsigned long tmo = ip_rt_gc_timeout; i = (i + 1) & rt_hash_mask; rthp = &rt_hash_table[i].chain; @@ -471,7 +472,7 @@ while ((rth = *rthp) != NULL) { if (rth->u.dst.expires) { /* Entry is expired even if it is in use */ - if ((long)(now - rth->u.dst.expires) <= 0) { + if (time_before_eq(now, rth->u.dst.expires)) { tmo >>= 1; rthp = &rth->u.rt_next; continue; @@ -489,7 +490,7 @@ spin_unlock(&rt_hash_table[i].lock); /* Fallback loop breaker. */ - if ((jiffies - now) > 0) + if (time_after(jiffies, now)) break; } rover = i; @@ -591,7 +592,7 @@ static int rt_garbage_collect(void) { - static unsigned expire = RT_GC_TIMEOUT; + static unsigned long expire = RT_GC_TIMEOUT; static unsigned long last_gc; static int rover; static int equilibrium; @@ -643,7 +644,7 @@ int i, k; for (i = rt_hash_mask, k = rover; i >= 0; i--) { - unsigned tmo = expire; + unsigned long tmo = expire; k = (k + 1) & rt_hash_mask; rthp = &rt_hash_table[k].chain; @@ -689,7 +690,7 @@ if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size) goto out; - } while (!in_softirq() && jiffies - now < 1); + } while (!in_softirq() && time_before_eq(jiffies, now)); if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size) goto out; @@ -1067,7 +1068,7 @@ /* No redirected packets during ip_rt_redirect_silence; * reset the algorithm. */ - if (jiffies - rt->u.dst.rate_last > ip_rt_redirect_silence) + if (time_after(jiffies, rt->u.dst.rate_last + ip_rt_redirect_silence)) rt->u.dst.rate_tokens = 0; /* Too many ignored redirects; do not send anything @@ -1081,8 +1082,9 @@ /* Check for load limit; set rate_last to the latest sent * redirect. */ - if (jiffies - rt->u.dst.rate_last > - (ip_rt_redirect_load << rt->u.dst.rate_tokens)) { + if (time_after(jiffies, + (rt->u.dst.rate_last + + (ip_rt_redirect_load << rt->u.dst.rate_tokens)))) { icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway); rt->u.dst.rate_last = jiffies; ++rt->u.dst.rate_tokens; diff -urN linux-2.5.69-bk3/net/ipv6/ip6_fib.c linux-2.5.69-bk4/net/ipv6/ip6_fib.c --- linux-2.5.69-bk3/net/ipv6/ip6_fib.c 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/net/ipv6/ip6_fib.c 2003-05-09 04:41:38.000000000 -0700 @@ -434,9 +434,6 @@ if (fn->fn_flags&RTN_TL_ROOT && fn->leaf == &ip6_null_entry && !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF | RTF_ALLONLINK)) ){ - /* - * The top fib of ip6 routing table includes ip6_null_entry. - */ fn->leaf = rt; rt->u.next = NULL; goto out; diff -urN linux-2.5.69-bk3/net/ipx/af_ipx.c linux-2.5.69-bk4/net/ipx/af_ipx.c --- linux-2.5.69-bk3/net/ipx/af_ipx.c 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/net/ipx/af_ipx.c 2003-05-09 04:41:39.000000000 -0700 @@ -15,7 +15,7 @@ * liability nor provide warranty for any of this software. This material * is provided as is and at no charge. * - * Portions Copyright (c) 2000-2002 Conectiva, Inc. + * Portions Copyright (c) 2000-2003 Conectiva, Inc. * Neither Arnaldo Carvalho de Melo nor Conectiva, Inc. admit liability nor * provide warranty for any of this software. This material is provided * "AS-IS" and at no charge. @@ -371,6 +371,7 @@ if (intrfc->if_dev) dev_put(intrfc->if_dev); kfree(intrfc); + module_put(THIS_MODULE); } static void ipxitf_down(struct ipx_interface *intrfc) @@ -936,6 +937,7 @@ intrfc->if_sklist = NULL; atomic_set(&intrfc->refcnt, 1); spin_lock_init(&intrfc->if_sklist_lock); + __module_get(THIS_MODULE); } return intrfc; @@ -2260,9 +2262,9 @@ static unsigned char ipx_8022_type = 0xE0; static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 }; static char ipx_banner[] __initdata = - KERN_INFO "NET4: Linux IPX 0.50 for NET4.0\n" + KERN_INFO "NET4: Linux IPX 0.51 for NET4.0\n" KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n" \ - KERN_INFO "IPX Portions Copyright (c) 2000-2002 Conectiva, Inc.\n"; + KERN_INFO "IPX Portions Copyright (c) 2000-2003 Conectiva, Inc.\n"; static char ipx_EII_err_msg[] __initdata = KERN_CRIT "IPX: Unable to register with Ethernet II\n"; static char ipx_8023_err_msg[] __initdata = @@ -2310,6 +2312,10 @@ * when a interface is created we increment the module usage count, so * the module will only be unloaded when there are no more interfaces */ + if (unlikely(!list_empty(&ipx_interfaces))) + BUG(); + if (unlikely(!list_empty(&ipx_routes))) + BUG(); ipx_proc_exit(); ipx_unregister_sysctl(); diff -urN linux-2.5.69-bk3/net/sched/sch_atm.c linux-2.5.69-bk4/net/sched/sch_atm.c --- linux-2.5.69-bk3/net/sched/sch_atm.c 2003-05-04 16:53:14.000000000 -0700 +++ linux-2.5.69-bk4/net/sched/sch_atm.c 2003-05-09 04:41:39.000000000 -0700 @@ -509,7 +509,6 @@ memcpy(skb_push(skb,flow->hdr_len),flow->hdr, flow->hdr_len); atomic_add(skb->truesize,&flow->vcc->sk->wmem_alloc); - ATM_SKB(skb)->iovcnt = 0; /* atm.atm_options are already set by atm_tc_enqueue */ (void) flow->vcc->send(flow->vcc,skb); } diff -urN linux-2.5.69-bk3/net/sctp/Kconfig linux-2.5.69-bk4/net/sctp/Kconfig --- linux-2.5.69-bk3/net/sctp/Kconfig 2003-05-04 16:53:07.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/Kconfig 2003-05-09 04:41:39.000000000 -0700 @@ -43,12 +43,12 @@ bool "SCTP: Use old checksum (Adler-32)" depends on IP_SCTP help - RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP. + RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP. This has been deprecated and replaced by an algorithm now referred to as crc32c. - If you say Y, this will use the Adler-32 algorithm, this might be useful - for interoperation with downlevel peers. + If you say Y, this will use the Adler-32 algorithm, this might be + useful for interoperation with downlevel peers. If unsure, say N. @@ -58,19 +58,46 @@ help If you say Y, this will enable verbose debugging messages. - If unsure, say N. However, if you are running into problems, use this - option to gather detailed trace information + If unsure, say N. However, if you are running into problems, use + this option to gather detailed trace information config SCTP_DBG_OBJCNT bool "SCTP: Debug object counts" depends on IP_SCTP help - If you say Y, this will enable debugging support for counting the types - of objects that are currently allocated. This is useful for identifying - memory leaks. If the /proc filesystem is enabled this debug information - can be viewed by 'cat /proc/net/sctp/sctp_dbg_objcnt' + If you say Y, this will enable debugging support for counting the + type of objects that are currently allocated. This is useful for + identifying memory leaks. If the /proc filesystem is enabled this + debug information can be viewed by + 'cat /proc/net/sctp/sctp_dbg_objcnt' If unsure, say N -endmenu +choice + prompt "SCTP: Cookie HMAC Algorithm" + help + HMAC algorithm to be used during association initialization. It + is strongly recommended to use HMAC-SHA1 or HMAC-MD5. See + configuration for Cryptographic API and enable those algorithms + to make usable by SCTP. + +config SCTP_HMAC_NONE + bool "None" + help + Choosing this disables the use of an HMAC during association + establishment. It is advised to use either HMAC-MD5 or HMAC-SHA1. + +config SCTP_HMAC_SHA1 + bool "HMAC-SHA1" if CRYPTO_HMAC=y && CRYPTO_SHA1=y || CRYPTO_SHA1=m + help + Enable the use of HMAC-SHA1 during association establishment. It + is advised to use either HMAC-MD5 or HMAC-SHA1. +config SCTP_HMAC_MD5 + bool "HMAC-MD5" if CRYPTO_HMAC=y && CRYPTO_MD5=y || CRYPTO_MD5=m + help + Enable the use of HMAC-MD5 during association establishment. It is + advised to use either HMAC-MD5 or HMAC-SHA1. + +endchoice +endmenu diff -urN linux-2.5.69-bk3/net/sctp/Makefile linux-2.5.69-bk4/net/sctp/Makefile --- linux-2.5.69-bk3/net/sctp/Makefile 2003-05-04 16:53:57.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/Makefile 2003-05-09 04:41:39.000000000 -0700 @@ -6,11 +6,10 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ protocol.o endpointola.o associola.o \ - transport.o sm_make_chunk.o ulpevent.o \ + transport.o chunk.o sm_make_chunk.o ulpevent.o \ inqueue.o outqueue.o ulpqueue.o command.o \ tsnmap.o bind_addr.o socket.o primitive.o \ - output.o input.o hashdriver.o sla1.o \ - debug.o ssnmap.o proc.o + output.o input.o debug.o ssnmap.o proc.o ifeq ($(CONFIG_SCTP_ADLER32), y) sctp-y += adler32.o diff -urN linux-2.5.69-bk3/net/sctp/adler32.c linux-2.5.69-bk4/net/sctp/adler32.c --- linux-2.5.69-bk3/net/sctp/adler32.c 2003-05-04 16:53:37.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/adler32.c 2003-05-09 04:41:39.000000000 -0700 @@ -2,43 +2,43 @@ * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2003 International Business Machines, Corp. - * + * * This file is part of the SCTP kernel reference Implementation - * - * This file has direct heritage from the SCTP user-level reference + * + * This file has direct heritage from the SCTP user-level reference * implementation by R. Stewart, et al. These functions implement the - * Adler-32 algorithm as specified by RFC 2960. - * - * The SCTP reference implementation is free software; - * you can redistribute it and/or modify it under the terms of + * Adler-32 algorithm as specified by RFC 2960. + * + * The SCTP reference implementation is free software; + * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * - * The SCTP reference implementation is distributed in the hope that it + * + * The SCTP reference implementation is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied * ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * + * Boston, MA 02111-1307, USA. + * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers - * + * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * - * Written or modified by: + * Written or modified by: * Randall Stewart * Ken Morneau * Qiaobing Xie * Sridhar Samudrala - * + * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ @@ -65,7 +65,7 @@ * tad, but I have commented the original lines below */ -#include +#include #include #define BASE 65521 /* largest prime smaller than 65536 */ @@ -111,7 +111,7 @@ * This would then be (2 * BASE) - 2, which * will still only do one subtract. On Intel * this is much better to do this way and - * avoid the divide. Have not -pg'd on + * avoid the divide. Have not -pg'd on * sparc. */ if (s2 >= BASE) { @@ -135,7 +135,7 @@ __u32 zero = 0L; /* Calculate the CRC up to the checksum field. */ - adler = update_adler32(adler, ptr, + adler = update_adler32(adler, ptr, sizeof(struct sctphdr) - sizeof(__u32)); /* Skip over the checksum field. */ adler = update_adler32(adler, (unsigned char *) &zero, @@ -156,6 +156,15 @@ return adler; } +__u32 sctp_update_copy_cksum(__u8 *to, __u8 *from, __u16 count, __u32 adler) +{ + /* Its not worth it to try harder. Adler32 is obsolescent. */ + adler = update_adler32(adler, from, count); + memcpy(to, from, count); + + return adler; +} + __u32 sctp_end_cksum(__u32 adler) { return adler; diff -urN linux-2.5.69-bk3/net/sctp/associola.c linux-2.5.69-bk4/net/sctp/associola.c --- linux-2.5.69-bk3/net/sctp/associola.c 2003-05-04 16:52:59.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/associola.c 2003-05-09 04:41:39.000000000 -0700 @@ -58,23 +58,23 @@ #include /* Forward declarations for internal functions. */ -static void sctp_assoc_bh_rcv(sctp_association_t *asoc); +static void sctp_assoc_bh_rcv(struct sctp_association *asoc); /* 1st Level Abstractions. */ /* Allocate and initialize a new association */ -sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep, +struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep, const struct sock *sk, - sctp_scope_t scope, int priority) + sctp_scope_t scope, int gfp) { - sctp_association_t *asoc; + struct sctp_association *asoc; - asoc = t_new(sctp_association_t, priority); + asoc = t_new(struct sctp_association, gfp); if (!asoc) goto fail; - if (!sctp_association_init(asoc, ep, sk, scope, priority)) + if (!sctp_association_init(asoc, ep, sk, scope, gfp)) goto fail_init; asoc->base.malloced = 1; @@ -89,23 +89,24 @@ } /* Initialize a new association from provided memory. */ -sctp_association_t *sctp_association_init(sctp_association_t *asoc, - const sctp_endpoint_t *ep, +struct sctp_association *sctp_association_init(struct sctp_association *asoc, + const struct sctp_endpoint *ep, const struct sock *sk, sctp_scope_t scope, - int priority) + int gfp) { struct sctp_opt *sp; + struct sctp_protocol *proto = sctp_get_protocol(); int i; /* Retrieve the SCTP per socket area. */ sp = sctp_sk((struct sock *)sk); /* Init all variables to a known value. */ - memset(asoc, 0, sizeof(sctp_association_t)); + memset(asoc, 0, sizeof(struct sctp_association)); /* Discarding const is appropriate here. */ - asoc->ep = (sctp_endpoint_t *)ep; + asoc->ep = (struct sctp_endpoint *)ep; sctp_endpoint_hold(asoc->ep); /* Hold the sock. */ @@ -136,10 +137,10 @@ asoc->frag_point = 0; /* Initialize the default association max_retrans and RTO values. */ - asoc->max_retrans = ep->proto->max_retrans_association; - asoc->rto_initial = ep->proto->rto_initial; - asoc->rto_max = ep->proto->rto_max; - asoc->rto_min = ep->proto->rto_min; + asoc->max_retrans = proto->max_retrans_association; + asoc->rto_initial = proto->rto_initial; + asoc->rto_max = proto->rto_max; + asoc->rto_min = proto->rto_min; asoc->overall_error_threshold = 0; asoc->overall_error_count = 0; @@ -147,7 +148,7 @@ /* Initialize the maximum mumber of new data packets that can be sent * in a burst. */ - asoc->max_burst = ep->proto->max_burst; + asoc->max_burst = proto->max_burst; /* Copy things from the endpoint. */ for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { @@ -255,7 +256,7 @@ sctp_packet_transmit_chunk, sctp_packet_transmit); - if (NULL == sctp_ulpq_init(&asoc->ulpq, asoc)) + if (!sctp_ulpq_init(&asoc->ulpq, asoc)) goto fail_init; /* Set up the tsn tracking. */ @@ -265,7 +266,6 @@ asoc->need_ecne = 0; - asoc->debug_name = "unnamedasoc"; asoc->eyecatcher = SCTP_ASSOC_EYECATCHER; /* Assume that peer would support both address types unless we are @@ -288,7 +288,7 @@ /* Free this association if possible. There may still be users, so * the actual deallocation may be delayed. */ -void sctp_association_free(sctp_association_t *asoc) +void sctp_association_free(struct sctp_association *asoc) { struct sock *sk = asoc->base.sk; struct sctp_transport *transport; @@ -298,8 +298,7 @@ list_del(&asoc->asocs); /* Decrement the backlog value for a TCP-style listening socket. */ - if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && - (SCTP_SS_LISTENING == sk->state)) + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) sk->ack_backlog--; /* Mark as dead, so other users can know this structure is @@ -351,7 +350,7 @@ } /* Cleanup and free up an association. */ -static void sctp_association_destroy(sctp_association_t *asoc) +static void sctp_association_destroy(struct sctp_association *asoc) { SCTP_ASSERT(asoc->base.dead, "Assoc is not dead", return); @@ -379,31 +378,56 @@ */ if (transport->active) asoc->peer.active_path = transport; + + /* + * SFR-CACC algorithm: + * Upon the receipt of a request to change the primary + * destination address, on the data structure for the new + * primary destination, the sender MUST do the following: + * + * 1) If CHANGEOVER_ACTIVE is set, then there was a switch + * to this destination address earlier. The sender MUST set + * CYCLING_CHANGEOVER to indicate that this switch is a + * double switch to the same destination address. + */ + if (transport->cacc.changeover_active) + transport->cacc.cycling_changeover = 1; + + /* 2) The sender MUST set CHANGEOVER_ACTIVE to indicate that + * a changeover has occurred. + */ + transport->cacc.changeover_active = 1; + + /* 3) The sender MUST store the next TSN to be sent in + * next_tsn_at_change. + */ + transport->cacc.next_tsn_at_change = asoc->next_tsn; } /* Add a transport address to an association. */ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, const union sctp_addr *addr, - int priority) + int gfp) { struct sctp_transport *peer; struct sctp_opt *sp; unsigned short port; + sp = sctp_sk(asoc->base.sk); + /* AF_INET and AF_INET6 share common port field. */ port = addr->v4.sin_port; /* Set the port if it has not been set yet. */ - if (0 == asoc->peer.port) { + if (0 == asoc->peer.port) asoc->peer.port = port; - } /* Check to see if this is a duplicate. */ peer = sctp_assoc_lookup_paddr(asoc, addr); if (peer) return peer; - peer = sctp_transport_new(addr, priority); + peer = sctp_transport_new(addr, gfp); if (!peer) return NULL; @@ -425,7 +449,7 @@ SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to " "%d\n", asoc, asoc->pmtu); - asoc->frag_point = sctp_frag_point(asoc->pmtu); + asoc->frag_point = sctp_frag_point(sp, asoc->pmtu); /* The asoc->peer.port might not be meaningful yet, but * initialize the packet structure anyway. @@ -470,14 +494,14 @@ /* Initialize the peer's heartbeat interval based on the * sock configured value. */ - sp = sctp_sk(asoc->base.sk); + peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ; /* Attach the remote transport to our asoc. */ list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); /* If we do not yet have a primary path, set one. */ - if (NULL == asoc->peer.primary_path) { + if (!asoc->peer.primary_path) { sctp_assoc_set_primary(asoc, peer); asoc->peer.retran_path = peer; } @@ -489,8 +513,9 @@ } /* Lookup a transport by address. */ -struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *asoc, - const union sctp_addr *address) +struct sctp_transport *sctp_assoc_lookup_paddr( + const struct sctp_association *asoc, + const union sctp_addr *address) { struct sctp_transport *t; struct list_head *pos; @@ -510,7 +535,7 @@ * Mark the transport up or down and send a notification to the user. * Select and update the new active and retran paths. */ -void sctp_assoc_control_transport(sctp_association_t *asoc, +void sctp_assoc_control_transport(struct sctp_association *asoc, struct sctp_transport *transport, sctp_transport_cmd_t command, sctp_sn_error_t error) @@ -589,7 +614,7 @@ /* If we failed to find a usable transport, just camp on the * primary, even if it is inactive. */ - if (NULL == first) { + if (!first) { first = asoc->peer.primary_path; second = asoc->peer.primary_path; } @@ -600,7 +625,7 @@ } /* Hold a reference to an association. */ -void sctp_association_hold(sctp_association_t *asoc) +void sctp_association_hold(struct sctp_association *asoc) { atomic_inc(&asoc->base.refcnt); } @@ -608,7 +633,7 @@ /* Release a reference to an association and cleanup * if there are no more references. */ -void sctp_association_put(sctp_association_t *asoc) +void sctp_association_put(struct sctp_association *asoc) { if (atomic_dec_and_test(&asoc->base.refcnt)) sctp_association_destroy(asoc); @@ -617,7 +642,7 @@ /* Allocate the next TSN, Transmission Sequence Number, for the given * association. */ -__u32 sctp_association_get_next_tsn(sctp_association_t *asoc) +__u32 sctp_association_get_next_tsn(struct sctp_association *asoc) { /* From Section 1.6 Serial Number Arithmetic: * Transmission Sequence Numbers wrap around when they reach @@ -632,7 +657,7 @@ } /* Allocate 'num' TSNs by incrementing the association's TSN by num. */ -__u32 sctp_association_get_tsn_block(sctp_association_t *asoc, int num) +__u32 sctp_association_get_tsn_block(struct sctp_association *asoc, int num) { __u32 retval = asoc->next_tsn; @@ -662,7 +687,7 @@ * Note: We are sly and return a shared, prealloced chunk. FIXME: * No we don't, but we could/should. */ -sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc) +struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc) { struct sctp_chunk *chunk; @@ -680,7 +705,7 @@ /* Use this function for the packet prepend callback when no ECNE * packet is desired (e.g. some packets don't like to be bundled). */ -sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc) +struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc) { return NULL; } @@ -688,13 +713,14 @@ /* * Find which transport this TSN was sent on. */ -struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn) +struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc, + __u32 tsn) { struct sctp_transport *active; struct sctp_transport *match; struct list_head *entry, *pos; struct sctp_transport *transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; __u32 key = htonl(tsn); match = NULL; @@ -717,7 +743,7 @@ active = asoc->peer.active_path; list_for_each(entry, &active->transmitted) { - chunk = list_entry(entry, sctp_chunk_t, transmitted_list); + chunk = list_entry(entry, struct sctp_chunk, transmitted_list); if (key == chunk->subh.data_hdr->tsn) { match = active; @@ -732,7 +758,7 @@ if (transport == active) break; list_for_each(entry, &transport->transmitted) { - chunk = list_entry(entry, sctp_chunk_t, + chunk = list_entry(entry, struct sctp_chunk, transmitted_list); if (key == chunk->subh.data_hdr->tsn) { match = transport; @@ -745,7 +771,7 @@ } /* Is this the association we are looking for? */ -struct sctp_transport *sctp_assoc_is_match(sctp_association_t *asoc, +struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc, const union sctp_addr *laddr, const union sctp_addr *paddr) { @@ -771,10 +797,10 @@ } /* Do delayed input processing. This is scheduled by sctp_rcv(). */ -static void sctp_assoc_bh_rcv(sctp_association_t *asoc) +static void sctp_assoc_bh_rcv(struct sctp_association *asoc) { - sctp_endpoint_t *ep; - sctp_chunk_t *chunk; + struct sctp_endpoint *ep; + struct sctp_chunk *chunk; struct sock *sk; struct sctp_inq *inqueue; int state, subtype; @@ -819,7 +845,7 @@ } /* This routine moves an association from its old sk to a new sk. */ -void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) +void sctp_assoc_migrate(struct sctp_association *assoc, struct sock *newsk) { struct sctp_opt *newsp = sctp_sk(newsk); struct sock *oldsk = assoc->base.sk; @@ -830,7 +856,7 @@ list_del(&assoc->asocs); /* Decrement the backlog value for a TCP-style socket. */ - if (SCTP_SOCKET_TCP == sctp_sk(oldsk)->type) + if (sctp_style(oldsk, TCP)) oldsk->ack_backlog--; /* Release references to the old endpoint and the sock. */ @@ -850,7 +876,8 @@ } /* Update an association (possibly from unexpected COOKIE-ECHO processing). */ -void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) +void sctp_assoc_update(struct sctp_association *asoc, + struct sctp_association *new) { /* Copy in new parameters of peer. */ asoc->c = new->c; @@ -872,7 +899,7 @@ * current next_tsn in case data sent to peer * has been discarded and needs retransmission. */ - if (SCTP_STATE_ESTABLISHED == asoc->state) { + if (sctp_state(asoc, ESTABLISHED)) { asoc->next_tsn = new->next_tsn; asoc->ctsn_ack_point = new->ctsn_ack_point; @@ -898,7 +925,7 @@ * through the inactive transports as this is the next best thing * we can try. */ -void sctp_assoc_update_retran_path(sctp_association_t *asoc) +void sctp_assoc_update_retran_path(struct sctp_association *asoc) { struct sctp_transport *t, *next; struct list_head *head = &asoc->peer.transport_addr_list; @@ -944,7 +971,8 @@ } /* Choose the transport for sending a SHUTDOWN packet. */ -struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) +struct sctp_transport *sctp_assoc_choose_shutdown_transport( + struct sctp_association *asoc) { /* If this is the first time SHUTDOWN is sent, use the active path, * else use the retran path. If the last SHUTDOWN was sent over the @@ -963,7 +991,7 @@ /* Update the association's pmtu and frag_point by going through all the * transports. This routine is called when a transport's PMTU has changed. */ -void sctp_assoc_sync_pmtu(sctp_association_t *asoc) +void sctp_assoc_sync_pmtu(struct sctp_association *asoc) { struct sctp_transport *t; struct list_head *pos; @@ -980,8 +1008,9 @@ } if (pmtu) { + struct sctp_opt *sp = sctp_sk(asoc->base.sk); asoc->pmtu = pmtu; - asoc->frag_point = sctp_frag_point(pmtu); + asoc->frag_point = sctp_frag_point(sp, pmtu); } SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n", @@ -1007,9 +1036,9 @@ } /* Increase asoc's rwnd by len and send any window update SACK if needed. */ -void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len) +void sctp_assoc_rwnd_increase(struct sctp_association *asoc, int len) { - sctp_chunk_t *sack; + struct sctp_chunk *sack; struct timer_list *timer; if (asoc->rwnd_over) { @@ -1053,7 +1082,7 @@ } /* Decrease asoc's rwnd by len. */ -void sctp_assoc_rwnd_decrease(sctp_association_t *asoc, int len) +void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, int len) { SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return); @@ -1092,7 +1121,7 @@ } /* Build the association's bind address list from the cookie. */ -int sctp_assoc_set_bind_addr_from_cookie(sctp_association_t *asoc, +int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc, sctp_cookie_t *cookie, int gfp) { int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length); diff -urN linux-2.5.69-bk3/net/sctp/bind_addr.c linux-2.5.69-bk4/net/sctp/bind_addr.c --- linux-2.5.69-bk3/net/sctp/bind_addr.c 2003-05-04 16:53:40.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/bind_addr.c 2003-05-09 04:41:39.000000000 -0700 @@ -52,16 +52,17 @@ #include /* Forward declarations for internal helpers. */ -static int sctp_copy_one_addr(sctp_bind_addr_t *, union sctp_addr *, +static int sctp_copy_one_addr(struct sctp_bind_addr *, union sctp_addr *, sctp_scope_t scope, int gfp, int flags); -static void sctp_bind_addr_clean(sctp_bind_addr_t *); +static void sctp_bind_addr_clean(struct sctp_bind_addr *); /* First Level Abstractions. */ /* Copy 'src' to 'dest' taking 'scope' into account. Omit addresses * in 'src' which have a broader scope than 'scope'. */ -int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, +int sctp_bind_addr_copy(struct sctp_bind_addr *dest, + const struct sctp_bind_addr *src, sctp_scope_t scope, int gfp, int flags) { struct sockaddr_storage_list *addr; @@ -80,6 +81,22 @@ goto out; } + /* If there are no addresses matching the scope and + * this is global scope, try to get a link scope address, with + * the assumption that we must be sitting behind a NAT. + */ + if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) { + list_for_each(pos, &src->address_list) { + addr = list_entry(pos, struct sockaddr_storage_list, + list); + error = sctp_copy_one_addr(dest, &addr->a, + SCTP_SCOPE_LINK, gfp, + flags); + if (error < 0) + goto out; + } + } + out: if (error) sctp_bind_addr_clean(dest); @@ -88,11 +105,11 @@ } /* Create a new SCTP_bind_addr from nothing. */ -sctp_bind_addr_t *sctp_bind_addr_new(int gfp) +struct sctp_bind_addr *sctp_bind_addr_new(int gfp) { - sctp_bind_addr_t *retval; + struct sctp_bind_addr *retval; - retval = t_new(sctp_bind_addr_t, gfp); + retval = t_new(struct sctp_bind_addr, gfp); if (!retval) goto nomem; @@ -107,7 +124,7 @@ /* Initialize the SCTP_bind_addr structure for either an endpoint or * an association. */ -void sctp_bind_addr_init(sctp_bind_addr_t *bp, __u16 port) +void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port) { bp->malloced = 0; @@ -116,7 +133,7 @@ } /* Dispose of the address list. */ -static void sctp_bind_addr_clean(sctp_bind_addr_t *bp) +static void sctp_bind_addr_clean(struct sctp_bind_addr *bp) { struct sockaddr_storage_list *addr; struct list_head *pos, *temp; @@ -131,7 +148,7 @@ } /* Dispose of an SCTP_bind_addr structure */ -void sctp_bind_addr_free(sctp_bind_addr_t *bp) +void sctp_bind_addr_free(struct sctp_bind_addr *bp) { /* Empty the bind address list. */ sctp_bind_addr_clean(bp); @@ -143,7 +160,7 @@ } /* Add an address to the bind address list in the SCTP_bind_addr structure. */ -int sctp_add_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *new, +int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new, int gfp) { struct sockaddr_storage_list *addr; @@ -171,7 +188,7 @@ /* Delete an address from the bind address list in the SCTP_bind_addr * structure. */ -int sctp_del_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *del_addr) +int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr) { struct list_head *pos, *temp; struct sockaddr_storage_list *addr; @@ -196,7 +213,7 @@ * * The second argument is the return value for the length. */ -union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, +union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, int *addrs_len, int gfp) { union sctp_params addrparms; @@ -214,6 +231,14 @@ len += sizeof(sctp_addr_param_t); } + /* Don't even bother embedding an address if there + * is only one. + */ + if (len == sizeof(sctp_addr_param_t)) { + retval.v = NULL; + goto end_raw; + } + retval.v = kmalloc(len, gfp); if (!retval.v) goto end_raw; @@ -237,7 +262,7 @@ * Create an address list out of the raw address list format (IPv4 and IPv6 * address parameters). */ -int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, +int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, int addrs_len, __u16 port, int gfp) { sctp_addr_param_t *rawaddr; @@ -283,7 +308,8 @@ ********************************************************************/ /* Does this contain a specified address? Allow wildcarding. */ -int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr, +int sctp_bind_addr_match(struct sctp_bind_addr *bp, + const union sctp_addr *addr, struct sctp_opt *opt) { struct sockaddr_storage_list *laddr; @@ -299,7 +325,8 @@ } /* Copy out addresses from the global local address list. */ -static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr, +static int sctp_copy_one_addr(struct sctp_bind_addr *dest, + union sctp_addr *addr, sctp_scope_t scope, int gfp, int flags) { struct sctp_protocol *proto = sctp_get_protocol(); diff -urN linux-2.5.69-bk3/net/sctp/chunk.c linux-2.5.69-bk4/net/sctp/chunk.c --- linux-2.5.69-bk3/net/sctp/chunk.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.69-bk4/net/sctp/chunk.c 2003-05-09 04:41:39.000000000 -0700 @@ -0,0 +1,327 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 2003 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * This file contains the code relating the the chunk abstraction. + * + * The SCTP reference implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * The SCTP reference implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* This file is mostly in anticipation of future work, but initially + * populate with fragment tracking for an outbound message. + */ + +/* Initialize datamsg from memory. */ +void sctp_datamsg_init(struct sctp_datamsg *msg) +{ + atomic_set(&msg->refcnt, 1); + msg->send_failed = 0; + msg->send_error = 0; + msg->can_expire = 0; + INIT_LIST_HEAD(&msg->chunks); +} + +/* Allocate and initialize datamsg. */ +struct sctp_datamsg *sctp_datamsg_new(int gfp) +{ + struct sctp_datamsg *msg; + msg = kmalloc(sizeof(struct sctp_datamsg), gfp); + if (msg) + sctp_datamsg_init(msg); + SCTP_DBG_OBJCNT_INC(datamsg); + return msg; +} + +/* Final destructruction of datamsg memory. */ +static void sctp_datamsg_destroy(struct sctp_datamsg *msg) +{ + struct list_head *pos, *temp; + struct sctp_chunk *chunk; + struct sctp_opt *sp; + struct sctp_ulpevent *ev; + struct sctp_association *asoc = NULL; + int error = 0, notify; + + /* If we failed, we may need to notify. */ + notify = msg->send_failed ? -1 : 0; + + /* Release all references. */ + list_for_each_safe(pos, temp, &msg->chunks) { + list_del(pos); + chunk = list_entry(pos, struct sctp_chunk, frag_list); + /* Check whether we _really_ need to notify. */ + if (notify < 0) { + asoc = chunk->asoc; + if (msg->send_error) + error = msg->send_error; + else + error = asoc->outqueue.error; + + sp = sctp_sk(asoc->base.sk); + notify = sctp_ulpevent_type_enabled(SCTP_SEND_FAILED, + &sp->subscribe); + } + + /* Generate a SEND FAILED event only if enabled. */ + if (notify > 0) { + int sent; + if (chunk->has_tsn) + sent = SCTP_DATA_SENT; + else + sent = SCTP_DATA_UNSENT; + + ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent, + error, GFP_ATOMIC); + if (ev) + sctp_ulpq_tail_event(&asoc->ulpq, ev); + } + + sctp_chunk_put(chunk); + } + + SCTP_DBG_OBJCNT_DEC(datamsg); + kfree(msg); +} + +/* Hold a reference. */ +void sctp_datamsg_hold(struct sctp_datamsg *msg) +{ + atomic_inc(&msg->refcnt); +} + +/* Release a reference. */ +void sctp_datamsg_put(struct sctp_datamsg *msg) +{ + if (atomic_dec_and_test(&msg->refcnt)) + sctp_datamsg_destroy(msg); +} + +/* Free a message. Really just give up a reference, the + * really free happens in sctp_datamsg_destroy(). + */ +void sctp_datamsg_free(struct sctp_datamsg *msg) +{ + sctp_datamsg_put(msg); +} + +/* Hold on to all the fragments until all chunks have been sent. */ +void sctp_datamsg_track(struct sctp_chunk *chunk) +{ + sctp_chunk_hold(chunk); +} + +/* Assign a chunk to this datamsg. */ +void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk) +{ + sctp_datamsg_hold(msg); + chunk->msg = msg; +} + + +/* A data chunk can have a maximum payload of (2^16 - 20). Break + * down any such message into smaller chunks. Opportunistically, fragment + * the chunks down to the current MTU constraints. We may get refragmented + * later if the PMTU changes, but it is _much better_ to fragment immediately + * with a reasonable guess than always doing our fragmentation on the + * soft-interrupt. + */ +struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, + struct sctp_sndrcvinfo *sinfo, + struct msghdr *msgh, int msg_len) +{ + int max, whole, i, offset, over, err; + int len, first_len; + struct sctp_chunk *chunk; + struct sctp_datamsg *msg; + struct list_head *pos, *temp; + __u8 frag; + + msg = sctp_datamsg_new(GFP_KERNEL); + if (!msg) + return NULL; + + /* Note: Calculate this outside of the loop, so that all fragments + * have the same expiration. + */ + if (sinfo->sinfo_timetolive) { + struct timeval tv; + __u32 ttl = sinfo->sinfo_timetolive; + + /* sinfo_timetolive is in milliseconds */ + tv.tv_sec = ttl / 1000; + tv.tv_usec = ttl % 1000 * 1000; + msg->expires_at = jiffies + timeval_to_jiffies(&tv); + msg->can_expire = 1; + } + + /* What is a reasonable fragmentation point right now? */ + max = asoc->pmtu; + if (max < SCTP_MIN_PMTU) + max = SCTP_MIN_PMTU; + max -= SCTP_IP_OVERHEAD; + + /* Make sure not beyond maximum chunk size. */ + if (max > SCTP_MAX_CHUNK_LEN) + max = SCTP_MAX_CHUNK_LEN; + + /* Subtract out the overhead of a data chunk header. */ + max -= sizeof(struct sctp_data_chunk); + whole = 0; + + /* If user has specified smaller fragmentation, make it so. */ + if (sctp_sk(asoc->base.sk)->user_frag) + max = min_t(int, max, sctp_sk(asoc->base.sk)->user_frag); + + first_len = max; + + /* Encourage Cookie-ECHO bundling. */ + if (asoc->state < SCTP_STATE_COOKIE_ECHOED) { + whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN); + + /* Account for the DATA to be bundled with the COOKIE-ECHO. */ + if (whole) { + first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN; + msg_len -= first_len; + whole = 1; + } + } + + /* How many full sized? How many bytes leftover? */ + whole += msg_len / max; + over = msg_len % max; + offset = 0; + + if ((whole > 1) || (whole && over)) + SCTP_INC_STATS_USER(SctpFragUsrMsgs); + + /* Create chunks for all the full sized DATA chunks. */ + for (i=0, len=first_len; i < whole; i++) { + frag = SCTP_DATA_MIDDLE_FRAG; + + if (0 == i) + frag |= SCTP_DATA_FIRST_FRAG; + + if ((i == (whole - 1)) && !over) + frag |= SCTP_DATA_LAST_FRAG; + + chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); + + if (!chunk) + goto errout; + err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov); + if (err < 0) + goto errout; + + offset += len; + + /* Put the chunk->skb back into the form expected by send. */ + __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr + - (__u8 *)chunk->skb->data); + + sctp_datamsg_assign(msg, chunk); + list_add_tail(&chunk->frag_list, &msg->chunks); + + /* The first chunk, the first chunk was likely short + * to allow bundling, so reset to full size. + */ + if (0 == i) + len = max; + } + + /* .. now the leftover bytes. */ + if (over) { + if (!whole) + frag = SCTP_DATA_NOT_FRAG; + else + frag = SCTP_DATA_LAST_FRAG; + + chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); + + if (!chunk) + goto errout; + + err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov); + + /* Put the chunk->skb back into the form expected by send. */ + __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr + - (__u8 *)chunk->skb->data); + if (err < 0) + goto errout; + + sctp_datamsg_assign(msg, chunk); + list_add_tail(&chunk->frag_list, &msg->chunks); + } + + return msg; + +errout: + list_for_each_safe(pos, temp, &msg->chunks) { + list_del(pos); + chunk = list_entry(pos, struct sctp_chunk, frag_list); + sctp_chunk_free(chunk); + } + sctp_datamsg_free(msg); + return NULL; +} + +/* Check whether this message has expired. */ +int sctp_datamsg_expires(struct sctp_chunk *chunk) +{ + struct sctp_datamsg *msg = chunk->msg; + + /* FIXME: When PR-SCTP is supported we can make this + * check more lenient. + */ + if (!msg->can_expire) + return 0; + + if (time_after(jiffies, msg->expires_at)) + return 1; + + return 0; +} + +/* This chunk (and consequently entire message) has failed in its sending. */ +void sctp_datamsg_fail(struct sctp_chunk *chunk, int error) +{ + chunk->msg->send_failed = 1; + chunk->msg->send_error = error; +} diff -urN linux-2.5.69-bk3/net/sctp/command.c linux-2.5.69-bk4/net/sctp/command.c --- linux-2.5.69-bk3/net/sctp/command.c 2003-05-04 16:53:33.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/command.c 2003-05-09 04:41:39.000000000 -0700 @@ -43,9 +43,9 @@ #include /* Create a new sctp_command_sequence. */ -sctp_cmd_seq_t *sctp_new_cmd_seq(int priority) +sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp) { - sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, priority); + sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, gfp); if (retval) sctp_init_cmd_seq(retval); diff -urN linux-2.5.69-bk3/net/sctp/crc32c.c linux-2.5.69-bk4/net/sctp/crc32c.c --- linux-2.5.69-bk3/net/sctp/crc32c.c 2003-05-04 16:53:37.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/crc32c.c 2003-05-09 04:41:39.000000000 -0700 @@ -170,6 +170,23 @@ return crc32; } +__u32 sctp_update_copy_cksum(__u8 *to, __u8 *from, __u16 length, __u32 crc32) +{ + __u32 i; + __u32 *_to = (__u32 *)to; + __u32 *_from = (__u32 *)from; + + for (i = 0; i < (length/4); i++) { + _to[i] = _from[i]; + CRC32C(crc32, from[i*4]); + CRC32C(crc32, from[i*4+1]); + CRC32C(crc32, from[i*4+2]); + CRC32C(crc32, from[i*4+3]); + } + + return crc32; +} + __u32 sctp_end_cksum(__u32 crc32) { __u32 result; diff -urN linux-2.5.69-bk3/net/sctp/endpointola.c linux-2.5.69-bk4/net/sctp/endpointola.c --- linux-2.5.69-bk3/net/sctp/endpointola.c 2003-05-04 16:53:02.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/endpointola.c 2003-05-09 04:41:39.000000000 -0700 @@ -54,27 +54,27 @@ #include #include #include /* get_random_bytes() */ +#include #include #include #include #include /* Forward declarations for internal helpers. */ -static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep); +static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep); -/* Create a sctp_endpoint_t with all that boring stuff initialized. +/* Create a sctp_endpoint with all that boring stuff initialized. * Returns NULL if there isn't enough memory. */ -sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *proto, - struct sock *sk, int priority) +struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp) { - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; /* Build a local endpoint. */ - ep = t_new(sctp_endpoint_t, priority); + ep = t_new(struct sctp_endpoint, gfp); if (!ep) goto fail; - if (!sctp_endpoint_init(ep, proto, sk, priority)) + if (!sctp_endpoint_init(ep, sk, gfp)) goto fail_init; ep->base.malloced = 1; SCTP_DBG_OBJCNT_INC(ep); @@ -89,12 +89,11 @@ /* * Initialize the base fields of the endpoint structure. */ -sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, - struct sctp_protocol *proto, - struct sock *sk, int priority) +struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, + struct sock *sk, int gfp) { struct sctp_opt *sp = sctp_sk(sk); - memset(ep, 0, sizeof(sctp_endpoint_t)); + memset(ep, 0, sizeof(struct sctp_endpoint)); /* Initialize the base structure. */ /* What type of endpoint are we? */ @@ -110,8 +109,7 @@ /* Set its top-half handler */ sctp_inq_set_th_handler(&ep->base.inqueue, - (void (*)(void *))sctp_endpoint_bh_rcv, - ep); + (void (*)(void *))sctp_endpoint_bh_rcv, ep); /* Initialize the bind addr area */ sctp_bind_addr_init(&ep->base.bind_addr, 0); @@ -121,21 +119,16 @@ ep->base.sk = sk; sock_hold(ep->base.sk); - /* This pointer is useful to access the default protocol parameter - * values. - */ - ep->proto = proto; - /* Create the lists of associations. */ INIT_LIST_HEAD(&ep->asocs); /* Set up the base timeout information. */ ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; - ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = SCTP_DEFAULT_TIMEOUT_T1_COOKIE; - ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = SCTP_DEFAULT_TIMEOUT_T1_INIT; - ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = + ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = sp->rtoinfo.srto_initial; ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; @@ -146,11 +139,11 @@ ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] = 5 * sp->rtoinfo.srto_max; - ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = + ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; - ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = + ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = SCTP_DEFAULT_TIMEOUT_SACK; - ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = + ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; /* Set up the default send/receive buffer space. */ @@ -175,7 +168,8 @@ } /* Add an association to an endpoint. */ -void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc) +void sctp_endpoint_add_asoc(struct sctp_endpoint *ep, + struct sctp_association *asoc) { struct sock *sk = ep->base.sk; @@ -183,22 +177,21 @@ list_add_tail(&asoc->asocs, &ep->asocs); /* Increment the backlog value for a TCP-style listening socket. */ - if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && - (SCTP_SS_LISTENING == sk->state)) + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) sk->ack_backlog++; } /* Free the endpoint structure. Delay cleanup until * all users have released their reference count on this structure. */ -void sctp_endpoint_free(sctp_endpoint_t *ep) +void sctp_endpoint_free(struct sctp_endpoint *ep) { ep->base.dead = 1; sctp_endpoint_put(ep); } /* Final destructor for endpoint. */ -void sctp_endpoint_destroy(sctp_endpoint_t *ep) +void sctp_endpoint_destroy(struct sctp_endpoint *ep) { SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); @@ -207,9 +200,12 @@ /* Unlink this endpoint, so we can't find it again! */ sctp_unhash_endpoint(ep); - /* Cleanup the inqueue. */ - sctp_inq_free(&ep->base.inqueue); + /* Free up the HMAC transform. */ + if (sctp_sk(ep->base.sk)->hmac) + sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac); + /* Cleanup. */ + sctp_inq_free(&ep->base.inqueue); sctp_bind_addr_free(&ep->base.bind_addr); /* Remove and free the port */ @@ -228,7 +224,7 @@ } /* Hold a reference to an endpoint. */ -void sctp_endpoint_hold(sctp_endpoint_t *ep) +void sctp_endpoint_hold(struct sctp_endpoint *ep) { atomic_inc(&ep->base.refcnt); } @@ -236,17 +232,17 @@ /* Release a reference to an endpoint and clean up if there are * no more references. */ -void sctp_endpoint_put(sctp_endpoint_t *ep) +void sctp_endpoint_put(struct sctp_endpoint *ep) { if (atomic_dec_and_test(&ep->base.refcnt)) sctp_endpoint_destroy(ep); } /* Is this the endpoint we are looking for? */ -sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, - const union sctp_addr *laddr) +struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep, + const union sctp_addr *laddr) { - sctp_endpoint_t *retval; + struct sctp_endpoint *retval; sctp_read_lock(&ep->base.addr_lock); if (ep->base.bind_addr.port == laddr->v4.sin_port) { @@ -268,19 +264,19 @@ * We do a linear search of the associations for this endpoint. * We return the matching transport address too. */ -sctp_association_t *__sctp_endpoint_lookup_assoc( - const sctp_endpoint_t *endpoint, +struct sctp_association *__sctp_endpoint_lookup_assoc( + const struct sctp_endpoint *ep, const union sctp_addr *paddr, struct sctp_transport **transport) { int rport; - sctp_association_t *asoc; + struct sctp_association *asoc; struct list_head *pos; rport = paddr->v4.sin_port; - list_for_each(pos, &endpoint->asocs) { - asoc = list_entry(pos, sctp_association_t, asocs); + list_for_each(pos, &ep->asocs) { + asoc = list_entry(pos, struct sctp_association, asocs); if (rport == asoc->peer.port) { sctp_read_lock(&asoc->base.addr_lock); *transport = sctp_assoc_lookup_paddr(asoc, paddr); @@ -296,12 +292,12 @@ } /* Lookup association on an endpoint based on a peer address. BH-safe. */ -sctp_association_t *sctp_endpoint_lookup_assoc( - const sctp_endpoint_t *ep, +struct sctp_association *sctp_endpoint_lookup_assoc( + const struct sctp_endpoint *ep, const union sctp_addr *paddr, struct sctp_transport **transport) { - sctp_association_t *asoc; + struct sctp_association *asoc; sctp_local_bh_disable(); asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport); @@ -313,12 +309,12 @@ /* Look for any peeled off association from the endpoint that matches the * given peer address. */ -int sctp_endpoint_is_peeled_off(sctp_endpoint_t *ep, +int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep, const union sctp_addr *paddr) { struct list_head *pos; struct sockaddr_storage_list *addr; - sctp_bind_addr_t *bp; + struct sctp_bind_addr *bp; sctp_read_lock(&ep->base.addr_lock); bp = &ep->base.bind_addr; @@ -337,12 +333,12 @@ /* Do delayed input processing. This is scheduled by sctp_rcv(). * This may be called on BH or task time. */ -static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) +static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct sock *sk; struct sctp_transport *transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sctp_inq *inqueue; sctp_subtype_t subtype; sctp_state_t state; @@ -355,7 +351,7 @@ inqueue = &ep->base.inqueue; sk = ep->base.sk; - while (NULL != (chunk = sctp_inq_pop(inqueue))) { + while (NULL != (chunk = sctp_inq_pop(inqueue))) { subtype.chunk = chunk->chunk_hdr->type; /* We might have grown an association since last we diff -urN linux-2.5.69-bk3/net/sctp/input.c linux-2.5.69-bk4/net/sctp/input.c --- linux-2.5.69-bk3/net/sctp/input.c 2003-05-04 16:53:01.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/input.c 2003-05-09 04:41:39.000000000 -0700 @@ -63,11 +63,11 @@ /* Forward declarations for internal helpers. */ static int sctp_rcv_ootb(struct sk_buff *); -sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, +struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, const union sctp_addr *laddr, const union sctp_addr *paddr, struct sctp_transport **transportp); -sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr); +struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr); /* Calculate the SCTP checksum of an SCTP packet. */ @@ -102,11 +102,11 @@ int sctp_rcv(struct sk_buff *skb) { struct sock *sk; - sctp_association_t *asoc; - sctp_endpoint_t *ep = NULL; - sctp_endpoint_common_t *rcvr; + struct sctp_association *asoc; + struct sctp_endpoint *ep = NULL; + struct sctp_ep_common *rcvr; struct sctp_transport *transport = NULL; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sctphdr *sh; union sctp_addr src; union sctp_addr dest; @@ -128,11 +128,11 @@ if (sctp_rcv_checksum(skb) < 0) goto bad_packet; - skb_pull(skb, sizeof(struct sctphdr)); + skb_pull(skb, sizeof(struct sctphdr)); family = ipver2af(skb->nh.iph->version); af = sctp_get_af_specific(family); - if (unlikely(!af)) + if (unlikely(!af)) goto bad_packet; /* Initialize local addresses for lookups. */ @@ -224,9 +224,7 @@ return ret; bad_packet: -#if 0 /* FIXME */ - SCTP_INC_STATS(SctpInErrs); -#endif /* FIXME*/ + SCTP_INC_STATS(SctpChecksumErrors); discard_it: kfree_skb(skb); @@ -252,13 +250,13 @@ */ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) { - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sctp_inq *inqueue; /* One day chunk will live inside the skb, but for * now this works. */ - chunk = (sctp_chunk_t *) skb; + chunk = (struct sctp_chunk *) skb; inqueue = &chunk->rcvr->inqueue; sctp_inq_push(inqueue, chunk); @@ -286,8 +284,8 @@ /* Common lookup code for icmp/icmpv6 error handler. */ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, struct sctphdr *sctphdr, - struct sctp_endpoint **epp, - struct sctp_association **app, + struct sctp_endpoint **epp, + struct sctp_association **app, struct sctp_transport **tpp) { union sctp_addr saddr; @@ -309,15 +307,15 @@ af->from_skb(&saddr, skb, 1); af->from_skb(&daddr, skb, 0); - /* Look for an association that matches the incoming ICMP error + /* Look for an association that matches the incoming ICMP error * packet. */ asoc = __sctp_lookup_association(&saddr, &daddr, &transport); if (!asoc) { /* If there is no matching association, see if it matches any - * endpoint. This may happen for an ICMP error generated in - * response to an INIT_ACK. - */ + * endpoint. This may happen for an ICMP error generated in + * response to an INIT_ACK. + */ ep = __sctp_rcv_lookup_endpoint(&daddr); if (!ep) { return NULL; @@ -345,25 +343,25 @@ *app = asoc; *tpp = transport; return sk; - + out: sock_put(sk); if (asoc) sctp_association_put(asoc); - if (ep) + if (ep) sctp_endpoint_put(ep); return NULL; } /* Common cleanup code for icmp/icmpv6 error handler. */ -void sctp_err_finish(struct sock *sk, struct sctp_endpoint *ep, +void sctp_err_finish(struct sock *sk, struct sctp_endpoint *ep, struct sctp_association *asoc) { sctp_bh_unlock_sock(sk); sock_put(sk); if (asoc) sctp_association_put(asoc); - if (ep) + if (ep) sctp_endpoint_put(ep); } @@ -389,8 +387,8 @@ int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct sock *sk; - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; struct sctp_transport *transport; struct inet_opt *inet; char *saveip, *savesctp; @@ -414,7 +412,7 @@ ICMP_INC_STATS_BH(IcmpInErrors); return; } - /* Warning: The sock lock is held. Remember to call + /* Warning: The sock lock is held. Remember to call * sctp_err_finish! */ @@ -520,10 +518,10 @@ } /* Insert endpoint into the hash table. */ -void __sctp_hash_endpoint(sctp_endpoint_t *ep) +void __sctp_hash_endpoint(struct sctp_endpoint *ep) { - sctp_endpoint_common_t **epp; - sctp_endpoint_common_t *epb; + struct sctp_ep_common **epp; + struct sctp_ep_common *epb; sctp_hashbucket_t *head; epb = &ep->base; @@ -542,7 +540,7 @@ } /* Add an endpoint to the hash. Local BH-safe. */ -void sctp_hash_endpoint(sctp_endpoint_t *ep) +void sctp_hash_endpoint(struct sctp_endpoint *ep) { sctp_local_bh_disable(); __sctp_hash_endpoint(ep); @@ -550,10 +548,10 @@ } /* Remove endpoint from the hash table. */ -void __sctp_unhash_endpoint(sctp_endpoint_t *ep) +void __sctp_unhash_endpoint(struct sctp_endpoint *ep) { sctp_hashbucket_t *head; - sctp_endpoint_common_t *epb; + struct sctp_ep_common *epb; epb = &ep->base; @@ -574,7 +572,7 @@ } /* Remove endpoint from the hash. Local BH-safe. */ -void sctp_unhash_endpoint(sctp_endpoint_t *ep) +void sctp_unhash_endpoint(struct sctp_endpoint *ep) { sctp_local_bh_disable(); __sctp_unhash_endpoint(ep); @@ -582,11 +580,11 @@ } /* Look up an endpoint. */ -sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr) +struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr) { sctp_hashbucket_t *head; - sctp_endpoint_common_t *epb; - sctp_endpoint_t *ep; + struct sctp_ep_common *epb; + struct sctp_endpoint *ep; int hash; hash = sctp_ep_hashfn(laddr->v4.sin_port); @@ -609,7 +607,7 @@ } /* Add an association to the hash. Local BH-safe. */ -void sctp_hash_established(sctp_association_t *asoc) +void sctp_hash_established(struct sctp_association *asoc) { sctp_local_bh_disable(); __sctp_hash_established(asoc); @@ -617,10 +615,10 @@ } /* Insert association into the hash table. */ -void __sctp_hash_established(sctp_association_t *asoc) +void __sctp_hash_established(struct sctp_association *asoc) { - sctp_endpoint_common_t **epp; - sctp_endpoint_common_t *epb; + struct sctp_ep_common **epp; + struct sctp_ep_common *epb; sctp_hashbucket_t *head; epb = &asoc->base; @@ -641,7 +639,7 @@ } /* Remove association from the hash table. Local BH-safe. */ -void sctp_unhash_established(sctp_association_t *asoc) +void sctp_unhash_established(struct sctp_association *asoc) { sctp_local_bh_disable(); __sctp_unhash_established(asoc); @@ -649,10 +647,10 @@ } /* Remove association from the hash table. */ -void __sctp_unhash_established(sctp_association_t *asoc) +void __sctp_unhash_established(struct sctp_association *asoc) { sctp_hashbucket_t *head; - sctp_endpoint_common_t *epb; + struct sctp_ep_common *epb; epb = &asoc->base; @@ -674,13 +672,14 @@ } /* Look up an association. */ -sctp_association_t *__sctp_lookup_association(const union sctp_addr *local, - const union sctp_addr *peer, - struct sctp_transport **pt) +struct sctp_association *__sctp_lookup_association( + const union sctp_addr *local, + const union sctp_addr *peer, + struct sctp_transport **pt) { sctp_hashbucket_t *head; - sctp_endpoint_common_t *epb; - sctp_association_t *asoc; + struct sctp_ep_common *epb; + struct sctp_association *asoc; struct sctp_transport *transport; int hash; @@ -710,11 +709,11 @@ } /* Look up an association. BH-safe. */ -sctp_association_t *sctp_lookup_association(const union sctp_addr *laddr, +struct sctp_association *sctp_lookup_association(const union sctp_addr *laddr, const union sctp_addr *paddr, struct sctp_transport **transportp) { - sctp_association_t *asoc; + struct sctp_association *asoc; sctp_local_bh_disable(); asoc = __sctp_lookup_association(laddr, paddr, transportp); @@ -727,7 +726,7 @@ int sctp_has_association(const union sctp_addr *laddr, const union sctp_addr *paddr) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct sctp_transport *transport; if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) { @@ -757,10 +756,10 @@ * in certain circumstances. * */ -static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb, +static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, const union sctp_addr *laddr, struct sctp_transport **transportp) { - sctp_association_t *asoc; + struct sctp_association *asoc; union sctp_addr addr; union sctp_addr *paddr = &addr; struct sctphdr *sh = (struct sctphdr *) skb->h.raw; @@ -815,12 +814,12 @@ } /* Lookup an association for an inbound skb. */ -sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, +struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, const union sctp_addr *paddr, const union sctp_addr *laddr, struct sctp_transport **transportp) { - sctp_association_t *asoc; + struct sctp_association *asoc; asoc = __sctp_lookup_association(laddr, paddr, transportp); diff -urN linux-2.5.69-bk3/net/sctp/inqueue.c linux-2.5.69-bk4/net/sctp/inqueue.c --- linux-2.5.69-bk3/net/sctp/inqueue.c 2003-05-04 16:53:35.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/inqueue.c 2003-05-09 04:41:39.000000000 -0700 @@ -75,17 +75,17 @@ /* Release the memory associated with an SCTP inqueue. */ void sctp_inq_free(struct sctp_inq *queue) { - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; /* Empty the queue. */ - while ((chunk = (sctp_chunk_t *) skb_dequeue(&queue->in)) != NULL) - sctp_free_chunk(chunk); + while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in))) + sctp_chunk_free(chunk); /* If there is a packet which is currently being worked on, * free it as well. */ if (queue->in_progress) - sctp_free_chunk(queue->in_progress); + sctp_chunk_free(queue->in_progress); if (queue->malloced) { /* Dump the master memory segment. */ @@ -96,7 +96,7 @@ /* Put a new packet in an SCTP inqueue. * We assume that packet->sctp_hdr is set and in host byte order. */ -void sctp_inq_push(struct sctp_inq *q, sctp_chunk_t *packet) +void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet) { /* Directly call the packet handling routine. */ @@ -114,23 +114,23 @@ * WARNING: If you need to put the chunk on another queue, you need to * make a shallow copy (clone) of it. */ -sctp_chunk_t *sctp_inq_pop(struct sctp_inq *queue) +struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) { - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; sctp_chunkhdr_t *ch = NULL; /* The assumption is that we are safe to process the chunks * at this time. */ - if ((chunk = queue->in_progress) != NULL) { + if ((chunk = queue->in_progress)) { /* There is a packet that we have been working on. * Any post processing work to do before we move on? */ if (chunk->singleton || chunk->end_of_packet || chunk->pdiscard) { - sctp_free_chunk(chunk); + sctp_chunk_free(chunk); chunk = queue->in_progress = NULL; } else { /* Nothing to do. Next chunk in the packet, please. */ @@ -149,7 +149,7 @@ return NULL; chunk = queue->in_progress = - (sctp_chunk_t *) skb_dequeue(&queue->in); + (struct sctp_chunk *) skb_dequeue(&queue->in); /* This is the first chunk in the packet. */ chunk->singleton = 1; diff -urN linux-2.5.69-bk3/net/sctp/ipv6.c linux-2.5.69-bk4/net/sctp/ipv6.c --- linux-2.5.69-bk3/net/sctp/ipv6.c 2003-05-04 16:53:32.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/ipv6.c 2003-05-09 04:41:39.000000000 -0700 @@ -96,8 +96,8 @@ struct ipv6hdr *iph = (struct ipv6hdr *)skb->data; struct sctphdr *sh = (struct sctphdr *)(skb->data + offset); struct sock *sk; - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; struct sctp_transport *transport; struct ipv6_pinfo *np; char *saveip, *savesctp; @@ -119,7 +119,7 @@ goto out; } - /* Warning: The sock lock is held. Remember to call + /* Warning: The sock lock is held. Remember to call * sctp_err_finish! */ @@ -148,21 +148,19 @@ } /* Based on tcp_v6_xmit() in tcp_ipv6.c. */ -static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, +static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, int ipfragok) { struct sock *sk = skb->sk; struct ipv6_pinfo *np = inet6_sk(sk); struct flowi fl; - struct dst_entry *dst = skb->dst; - struct rt6_info *rt6 = (struct rt6_info *)dst; fl.proto = sk->protocol; /* Fill in the dest address from the route entry passed with the skb * and the source address from the transport. */ - fl.fl6_dst = &rt6->rt6i_dst.addr; + fl.fl6_dst = &transport->ipaddr.v6.sin6_addr; fl.fl6_src = &transport->saddr.v6.sin6_addr; fl.fl6_flowlabel = np->flow_label; @@ -193,7 +191,7 @@ /* Returns the dst cache entry for the given source and destination ip * addresses. */ -struct dst_entry *sctp_v6_get_dst(sctp_association_t *asoc, +struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, union sctp_addr *daddr, union sctp_addr *saddr) { @@ -251,10 +249,10 @@ /* Fills in the source address(saddr) based on the destination address(daddr) * and asoc's bind address list. */ -void sctp_v6_get_saddr(sctp_association_t *asoc, struct dst_entry *dst, +void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst, union sctp_addr *daddr, union sctp_addr *saddr) { - sctp_bind_addr_t *bp; + struct sctp_bind_addr *bp; rwlock_t *addr_lock; struct sockaddr_storage_list *laddr; struct list_head *pos; @@ -376,11 +374,17 @@ } /* Initialize sk->rcv_saddr from sctp_addr. */ -static void sctp_v6_to_sk(union sctp_addr *addr, struct sock *sk) +static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr; } +/* Initialize sk->daddr from sctp_addr. */ +static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) +{ + inet6_sk(sk)->daddr = addr->v6.sin6_addr; +} + /* Initialize a sctp_addr from a dst_entry. */ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, unsigned short port) @@ -391,7 +395,7 @@ ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr); } -/* Compare addresses exactly. +/* Compare addresses exactly. * FIXME: v4-mapped-v6. */ static int sctp_v6_cmp_addr(const union sctp_addr *addr1, @@ -521,6 +525,7 @@ newsk->family = PF_INET6; newsk->protocol = IPPROTO_SCTP; newsk->backlog_rcv = sk->prot->backlog_rcv; + newsk->shutdown = sk->shutdown; newsctp6sk = (struct sctp6_sock *)newsk; newsctp6sk->pinet6 = &newsctp6sk->inet6; @@ -530,10 +535,28 @@ memcpy(newnp, np, sizeof(struct ipv6_pinfo)); - ipv6_addr_copy(&newnp->daddr, &asoc->peer.primary_addr.v6.sin6_addr); - + /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname() + * and getpeername(). + */ newinet->sport = inet->sport; - newinet->dport = asoc->peer.port; + newnp->saddr = np->saddr; + newnp->rcv_saddr = np->rcv_saddr; + newinet->dport = htons(asoc->peer.port); + newnp->daddr = asoc->peer.primary_addr.v6.sin6_addr; + + /* Init the ipv4 part of the socket since we can have sockets + * using v6 API for ipv4. + */ + newinet->ttl = sysctl_ip_default_ttl; + newinet->mc_loop = 1; + newinet->mc_ttl = 1; + newinet->mc_index = 0; + newinet->mc_list = NULL; + + if (ipv4_config.no_pmtu_disc) + newinet->pmtudisc = IP_PMTUDISC_DONT; + else + newinet->pmtudisc = IP_PMTUDISC_WANT; #ifdef INET_REFCNT_DEBUG atomic_inc(&inet6_sock_nr); @@ -556,6 +579,12 @@ return opt->iif; } +/* Was this packet marked by Explicit Congestion Notification? */ +static int sctp_v6_is_ce(const struct sk_buff *skb) +{ + return *((__u32 *)(skb->nh.ipv6h)) & htonl(1<<20); +} + /* Initialize a PF_INET6 socket msg_name. */ static void sctp_inet6_msgname(char *msgname, int *addr_len) { @@ -569,7 +598,7 @@ } /* Initialize a PF_INET msgname from a ulpevent. */ -static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, +static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, char *msgname, int *addrlen) { struct sockaddr_in6 *sin6, *sin6from; @@ -596,7 +625,7 @@ sin6from = &event->asoc->peer.primary_addr.v6; ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr); - if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin6->sin6_scope_id = sin6from->sin6_scope_id; } } @@ -696,7 +725,7 @@ if (addr->v6.sin6_scope_id) sk->bound_dev_if = addr->v6.sin6_scope_id; if (!sk->bound_dev_if) - return 0; + return 0; } af = opt->pf->af; } @@ -726,11 +755,11 @@ if (addr->v6.sin6_scope_id) sk->bound_dev_if = addr->v6.sin6_scope_id; if (!sk->bound_dev_if) - return 0; + return 0; } af = opt->pf->af; } - + return af != NULL; } @@ -807,7 +836,8 @@ .copy_addrlist = sctp_v6_copy_addrlist, .from_skb = sctp_v6_from_skb, .from_sk = sctp_v6_from_sk, - .to_sk = sctp_v6_to_sk, + .to_sk_saddr = sctp_v6_to_sk_saddr, + .to_sk_daddr = sctp_v6_to_sk_daddr, .dst_saddr = sctp_v6_dst_saddr, .cmp_addr = sctp_v6_cmp_addr, .scope = sctp_v6_scope, @@ -816,6 +846,7 @@ .is_any = sctp_v6_is_any, .available = sctp_v6_available, .skb_iif = sctp_v6_skb_iif, + .is_ce = sctp_v6_is_ce, .net_header_len = sizeof(struct ipv6hdr), .sockaddr_len = sizeof(struct sockaddr_in6), .sa_family = AF_INET6, diff -urN linux-2.5.69-bk3/net/sctp/objcnt.c linux-2.5.69-bk4/net/sctp/objcnt.c --- linux-2.5.69-bk3/net/sctp/objcnt.c 2003-05-04 16:53:00.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/objcnt.c 2003-05-09 04:41:39.000000000 -0700 @@ -55,6 +55,7 @@ SCTP_DBG_OBJCNT(chunk); SCTP_DBG_OBJCNT(addr); SCTP_DBG_OBJCNT(ssnmap); +SCTP_DBG_OBJCNT(datamsg); /* An array to make it easy to pretty print the debug information * to the proc fs. @@ -68,6 +69,7 @@ SCTP_DBG_OBJCNT_ENTRY(bind_addr), SCTP_DBG_OBJCNT_ENTRY(addr), SCTP_DBG_OBJCNT_ENTRY(ssnmap), + SCTP_DBG_OBJCNT_ENTRY(datamsg), }; /* Callback from procfs to read out objcount information. diff -urN linux-2.5.69-bk3/net/sctp/output.c linux-2.5.69-bk4/net/sctp/output.c --- linux-2.5.69-bk3/net/sctp/output.c 2003-05-04 16:53:07.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/output.c 2003-05-09 04:41:39.000000000 -0700 @@ -114,7 +114,7 @@ struct sctp_chunk *chunk; while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) - sctp_free_chunk(chunk); + sctp_chunk_free(chunk); if (packet->malloced) kfree(packet); @@ -166,11 +166,11 @@ /* If sending DATA and haven't aleady bundled a SACK, try to * bundle one in to the packet. */ - if (sctp_chunk_is_data(chunk) && !pkt->has_sack && + if (sctp_chunk_is_data(chunk) && !pkt->has_sack && !pkt->has_cookie_echo) { struct sctp_association *asoc; asoc = pkt->transport->asoc; - + if (asoc->a_rwnd > asoc->rwnd) { struct sctp_chunk *sack; asoc->a_rwnd = asoc->rwnd; @@ -205,7 +205,7 @@ if (retval != SCTP_XMIT_OK) goto finish; - + pmtu = ((packet->transport->asoc) ? (packet->transport->asoc->pmtu) : (packet->transport->pmtu)); @@ -219,21 +219,16 @@ /* Both control chunks and data chunks with TSNs are * non-fragmentable. */ - int fragmentable = sctp_chunk_is_data(chunk) && - (!chunk->has_tsn); if (packet_empty) { - if (fragmentable) { - retval = SCTP_XMIT_MUST_FRAG; - goto finish; - } else { - /* The packet is too big but we can - * not fragment it--we have to just - * transmit and rely on IP - * fragmentation. - */ - packet->ipfragok = 1; - goto append; - } + + /* We no longer do refragmentation at all. + * Just fragment at the IP layer, if we + * actually hit this condition + */ + + packet->ipfragok = 1; + goto append; + } else { /* !packet_empty */ retval = SCTP_XMIT_PMTU_FULL; goto finish; @@ -259,7 +254,7 @@ goto finish; } else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) packet->has_cookie_echo = 1; - else if (SCTP_CID_SACK == chunk->chunk_hdr->type) + else if (SCTP_CID_SACK == chunk->chunk_hdr->type) packet->has_sack = 1; /* It is OK to send this chunk. */ @@ -276,8 +271,8 @@ */ int sctp_packet_transmit(struct sctp_packet *packet) { - struct sctp_transport *transport = packet->transport; - struct sctp_association *asoc = transport->asoc; + struct sctp_transport *tp = packet->transport; + struct sctp_association *asoc = tp->asoc; struct sctphdr *sh; __u32 crc32; struct sk_buff *nskb; @@ -311,6 +306,31 @@ */ skb_set_owner_w(nskb, sk); + /* Build the SCTP header. */ + sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); + sh->source = htons(packet->source_port); + sh->dest = htons(packet->destination_port); + + /* From 6.8 Adler-32 Checksum Calculation: + * After the packet is constructed (containing the SCTP common + * header and one or more control or DATA chunks), the + * transmitter shall: + * + * 1) Fill in the proper Verification Tag in the SCTP common + * header and initialize the checksum field to 0's. + */ + sh->vtag = htonl(packet->vtag); + sh->checksum = 0; + + /* 2) Calculate the Adler-32 checksum of the whole packet, + * including the SCTP common header and all the + * chunks. + * + * Note: Adler-32 is no longer applicable, as has been replaced + * by CRC32-C as described in . + */ + crc32 = sctp_start_cksum((__u8 *)sh, sizeof(struct sctphdr)); + /** * 6.10 Bundling * @@ -332,10 +352,12 @@ */ SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { - chunk->num_times_sent++; - chunk->sent_at = jiffies; + if (sctp_chunk_is_data(chunk)) { - sctp_chunk_assign_tsn(chunk); + + if (!chunk->has_tsn) { + sctp_chunk_assign_ssn(chunk); + sctp_chunk_assign_tsn(chunk); /* 6.3.1 C4) When data is in flight and when allowed * by rule C5, a new RTT measurement MUST be made each @@ -343,19 +365,27 @@ * SHOULD be made no more than once per round-trip * for a given destination transport address. */ - if ((1 == chunk->num_times_sent) && - (!transport->rto_pending)) { - chunk->rtt_in_progress = 1; - transport->rto_pending = 1; - } + + if (!tp->rto_pending) { + chunk->rtt_in_progress = 1; + tp->rto_pending = 1; + } + } else + chunk->resent = 1; + + chunk->sent_at = jiffies; has_data = 1; } - memcpy(skb_put(nskb, chunk->skb->len), - chunk->skb->data, chunk->skb->len); + padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len; - memset(skb_put(nskb, padding), 0, padding); - SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d, " - "%s %d\n", + if (padding) + memset(skb_put(chunk->skb, padding), 0, padding); + + crc32 = sctp_update_copy_cksum(skb_put(nskb, chunk->skb->len), + chunk->skb->data, + chunk->skb->len, crc32); + + SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d\n", "*** Chunk", chunk, sctp_cname(SCTP_ST_CHUNK( chunk->chunk_hdr->type)), @@ -364,7 +394,6 @@ ntohl(chunk->subh.data_hdr->tsn) : 0, "length", ntohs(chunk->chunk_hdr->length), "chunk->skb->len", chunk->skb->len, - "num_times_sent", chunk->num_times_sent, "rtt_in_progress", chunk->rtt_in_progress); /* @@ -373,33 +402,10 @@ * acknowledged or have failed. */ if (!sctp_chunk_is_data(chunk)) - sctp_free_chunk(chunk); + sctp_chunk_free(chunk); } - /* Build the SCTP header. */ - sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); - sh->source = htons(packet->source_port); - sh->dest = htons(packet->destination_port); - - /* From 6.8 Adler-32 Checksum Calculation: - * After the packet is constructed (containing the SCTP common - * header and one or more control or DATA chunks), the - * transmitter shall: - * - * 1) Fill in the proper Verification Tag in the SCTP common - * header and initialize the checksum field to 0's. - */ - sh->vtag = htonl(packet->vtag); - sh->checksum = 0; - - /* 2) Calculate the Adler-32 checksum of the whole packet, - * including the SCTP common header and all the - * chunks. - * - * Note: Adler-32 is no longer applicable, as has been replaced - * by CRC32-C as described in . - */ - crc32 = sctp_start_cksum((__u8 *)sh, nskb->len); + /* Perform final transformation on checksum. */ crc32 = sctp_end_cksum(crc32); /* 3) Put the resultant value into the checksum field in the @@ -413,17 +419,13 @@ * data sender to indicate that the end-points of the * transport protocol are ECN-capable." * - * If ECN capable && negotiated && it makes sense for - * this packet to support it (e.g. post ECN negotiation) - * then lets set the ECT bit + * Now setting the ECT bit all the time, as it should not cause + * any problems protocol-wise even if our peer ignores it. * - * FIXME: Need to do something else for IPv6 + * Note: The works for IPv6 layer checks this bit too later + * in transmission. See IP6_ECN_flow_xmit(). */ - if (packet->ecn_capable) { - INET_ECN_xmit(nskb->sk); - } else { - INET_ECN_dontxmit(nskb->sk); - } + INET_ECN_xmit(nskb->sk); /* Set up the IP options. */ /* BUG: not implemented @@ -431,22 +433,21 @@ */ /* Dump that on IP! */ - if (asoc && asoc->peer.last_sent_to != transport) { + if (asoc && asoc->peer.last_sent_to != tp) { /* Considering the multiple CPU scenario, this is a * "correcter" place for last_sent_to. --xguo */ - asoc->peer.last_sent_to = transport; + asoc->peer.last_sent_to = tp; } if (has_data) { struct timer_list *timer; unsigned long timeout; - transport->last_time_used = jiffies; + tp->last_time_used = jiffies; /* Restart the AUTOCLOSE timer when sending data. */ - if ((SCTP_STATE_ESTABLISHED == asoc->state) && - (asoc->autoclose)) { + if (sctp_state(asoc, ESTABLISHED) && asoc->autoclose) { timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; @@ -455,21 +456,21 @@ } } - dst = transport->dst; + dst = tp->dst; /* The 'obsolete' field of dst is set to 2 when a dst is freed. */ if (!dst || (dst->obsolete > 1)) { dst_release(dst); - sctp_transport_route(transport, NULL, sctp_sk(sk)); + sctp_transport_route(tp, NULL, sctp_sk(sk)); sctp_assoc_sync_pmtu(asoc); } - nskb->dst = dst_clone(transport->dst); + nskb->dst = dst_clone(tp->dst); if (!nskb->dst) goto no_route; SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", nskb->len); - (*transport->af_specific->sctp_xmit)(nskb, transport, packet->ipfragok); + (*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok); out: packet->size = SCTP_IP_OVERHEAD; return err; @@ -596,8 +597,8 @@ * if any previously transmitted data on the connection remains * unacknowledged. */ - if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size && - q->outstanding_bytes && SCTP_STATE_ESTABLISHED == asoc->state) { + if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size && + q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) { unsigned len = datasize + q->out_qlen; /* Check whether this chunk and all the rest of pending @@ -623,6 +624,8 @@ rwnd = 0; asoc->peer.rwnd = rwnd; + /* Has been accepted for transmission. */ + chunk->msg->can_expire = 0; finish: return retval; diff -urN linux-2.5.69-bk3/net/sctp/outqueue.c linux-2.5.69-bk4/net/sctp/outqueue.c --- linux-2.5.69-bk3/net/sctp/outqueue.c 2003-05-04 16:53:09.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/outqueue.c 2003-05-09 04:41:39.000000000 -0700 @@ -55,13 +55,19 @@ #include /* Declare internal functions here. */ -static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn); +static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn); static void sctp_check_transmitted(struct sctp_outq *q, struct list_head *transmitted_queue, struct sctp_transport *transport, - sctp_sackhdr_t *sack, + struct sctp_sackhdr *sack, __u32 highest_new_tsn); +static void sctp_mark_missing(struct sctp_outq *q, + struct list_head *transmitted_queue, + struct sctp_transport *transport, + __u32 highest_new_tsn, + int count_of_newacks); + /* Add data to the front of the queue. */ static inline void sctp_outq_head_data(struct sctp_outq *q, struct sctp_chunk *ch) @@ -94,13 +100,105 @@ struct sctp_chunk *ch, struct sctp_chunk *pos) { - __skb_insert((struct sk_buff *)ch, (struct sk_buff *)pos->prev, + __skb_insert((struct sk_buff *)ch, (struct sk_buff *)pos->prev, (struct sk_buff *)pos, pos->list); q->out_qlen += ch->skb->len; } +/* + * SFR-CACC algorithm: + * D) If count_of_newacks is greater than or equal to 2 + * and t was not sent to the current primary then the + * sender MUST NOT increment missing report count for t. + */ +static inline int sctp_cacc_skip_3_1_d(struct sctp_transport *primary, + struct sctp_transport *transport, + int count_of_newacks) +{ + if (count_of_newacks >=2 && transport != primary) + return 1; + return 0; +} + +/* + * SFR-CACC algorithm: + * F) If count_of_newacks is less than 2, let d be the + * destination to which t was sent. If cacc_saw_newack + * is 0 for destination d, then the sender MUST NOT + * increment missing report count for t. + */ +static inline int sctp_cacc_skip_3_1_f(struct sctp_transport *transport, + int count_of_newacks) +{ + if (count_of_newacks < 2 && !transport->cacc.cacc_saw_newack) + return 1; + return 0; +} + +/* + * SFR-CACC algorithm: + * 3.1) If CYCLING_CHANGEOVER is 0, the sender SHOULD + * execute steps C, D, F. + * + * C has been implemented in sctp_outq_sack + */ +static inline int sctp_cacc_skip_3_1(struct sctp_transport *primary, + struct sctp_transport *transport, + int count_of_newacks) +{ + if (!primary->cacc.cycling_changeover) { + if (sctp_cacc_skip_3_1_d(primary, transport, count_of_newacks)) + return 1; + if (sctp_cacc_skip_3_1_f(transport, count_of_newacks)); + return 1; + return 0; + } + return 0; +} + +/* + * SFR-CACC algorithm: + * 3.2) Else if CYCLING_CHANGEOVER is 1, and t is less + * than next_tsn_at_change of the current primary, then + * the sender MUST NOT increment missing report count + * for t. + */ +static inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn) +{ + if (primary->cacc.cycling_changeover && + TSN_lt(tsn, primary->cacc.next_tsn_at_change)) + return 1; + return 0; +} + +/* + * SFR-CACC algorithm: + * 3) If the missing report count for TSN t is to be + * incremented according to [RFC2960] and + * [SCTP_STEWART-2002], and CHANGEOVER_ACTIVE is set, + * then the sender MUST futher execute steps 3.1 and + * 3.2 to determine if the missing report count for + * TSN t SHOULD NOT be incremented. + * + * 3.3) If 3.1 and 3.2 do not dictate that the missing + * report count for t should not be incremented, then + * the sender SOULD increment missing report count for + * t (according to [RFC2960] and [SCTP_STEWART_2002]). + */ +static inline int sctp_cacc_skip(struct sctp_transport *primary, + struct sctp_transport *transport, + int count_of_newacks, + __u32 tsn) +{ + if (primary->cacc.changeover_active && + (sctp_cacc_skip_3_1(primary, transport, count_of_newacks) + || sctp_cacc_skip_3_2(primary, tsn))) + return 1; + return 0; +} + /* Generate a new outqueue. */ -struct sctp_outq *sctp_outq_new(sctp_association_t *asoc) +struct sctp_outq *sctp_outq_new(struct sctp_association *asoc) { struct sctp_outq *q; @@ -116,7 +214,7 @@ * You still need to define handlers if you really want to DO * something with this structure... */ -void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q) +void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) { q->asoc = asoc; skb_queue_head_init(&q->out); @@ -132,6 +230,7 @@ q->outstanding_bytes = 0; q->empty = 1; + q->cork = 0; q->malloced = 0; q->out_qlen = 0; @@ -143,59 +242,51 @@ { struct sctp_transport *transport; struct list_head *lchunk, *pos, *temp; - sctp_chunk_t *chunk; - struct sctp_ulpevent *ev; + struct sctp_chunk *chunk; /* Throw away unacknowledged chunks. */ list_for_each(pos, &q->asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); while ((lchunk = sctp_list_dequeue(&transport->transmitted))) { - chunk = list_entry(lchunk, sctp_chunk_t, + chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); - - /* Generate a SEND FAILED event. */ - ev = sctp_ulpevent_make_send_failed(q->asoc, - chunk, SCTP_DATA_SENT, - q->error, GFP_ATOMIC); - if (ev) - sctp_ulpq_tail_event(&q->asoc->ulpq, ev); - - sctp_free_chunk(chunk); + /* Mark as part of a failed message. */ + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } } /* Throw away chunks that have been gap ACKed. */ list_for_each_safe(lchunk, temp, &q->sacked) { list_del(lchunk); - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - sctp_free_chunk(chunk); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } /* Throw away any chunks in the retransmit queue. */ list_for_each_safe(lchunk, temp, &q->retransmit) { list_del(lchunk); - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - sctp_free_chunk(chunk); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } /* Throw away any leftover data chunks. */ while ((chunk = sctp_outq_dequeue_data(q))) { - /* Generate a SEND FAILED event. */ - ev = sctp_ulpevent_make_send_failed(q->asoc, - chunk, SCTP_DATA_UNSENT, - q->error, GFP_ATOMIC); - if (ev) - sctp_ulpq_tail_event(&q->asoc->ulpq, ev); - - sctp_free_chunk(chunk); + /* Mark as send failure. */ + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } q->error = 0; /* Throw away any leftover control chunks. */ - while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->control))) - sctp_free_chunk(chunk); + while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control))) + sctp_chunk_free(chunk); } /* Free the outqueue structure and any related pending chunks. */ @@ -210,7 +301,7 @@ } /* Put a new chunk in an sctp_outq. */ -int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) +int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk) { int error = 0; @@ -265,7 +356,8 @@ if (error < 0) return error; - error = sctp_outq_flush(q, 0); + if (!q->cork) + error = sctp_outq_flush(q, 0); return error; } @@ -276,15 +368,16 @@ void sctp_retransmit_insert(struct list_head *tlchunk, struct sctp_outq *q) { struct list_head *rlchunk; - sctp_chunk_t *tchunk, *rchunk; + struct sctp_chunk *tchunk, *rchunk; __u32 ttsn, rtsn; int done = 0; - tchunk = list_entry(tlchunk, sctp_chunk_t, transmitted_list); + tchunk = list_entry(tlchunk, struct sctp_chunk, transmitted_list); ttsn = ntohl(tchunk->subh.data_hdr->tsn); list_for_each(rlchunk, &q->retransmit) { - rchunk = list_entry(rlchunk, sctp_chunk_t, transmitted_list); + rchunk = list_entry(rlchunk, struct sctp_chunk, + transmitted_list); rtsn = ntohl(rchunk->subh.data_hdr->tsn); if (TSN_lt(ttsn, rtsn)) { list_add(tlchunk, rlchunk->prev); @@ -303,11 +396,12 @@ __u8 fast_retransmit) { struct list_head *lchunk, *ltemp; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; /* Walk through the specified transmitted queue. */ list_for_each_safe(lchunk, ltemp, &transport->transmitted) { - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); /* If we are doing retransmission due to a fast retransmit, * only the chunk's that are marked for fast retransmit @@ -416,8 +510,8 @@ struct list_head *lchunk; struct sctp_transport *transport = pkt->transport; sctp_xmit_t status; - sctp_chunk_t *chunk; - sctp_association_t *asoc; + struct sctp_chunk *chunk; + struct sctp_association *asoc; int error = 0; asoc = q->asoc; @@ -442,7 +536,8 @@ lchunk = sctp_list_dequeue(lqueue); while (lchunk) { - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); /* Make sure that Gap Acked TSNs are not retransmitted. A * simple approach is just to move such TSNs out of the @@ -504,215 +599,19 @@ return error; } -/* This routine either transmits the fragment or puts it on the output - * queue. 'pos' points to the next chunk in the output queue after the - * chunk that is currently in the process of fragmentation. - */ -void sctp_xmit_frag(struct sctp_outq *q, struct sctp_chunk *pos, - struct sctp_packet *packet, struct sctp_chunk *frag, __u32 tsn) +/* Cork the outqueue so queued chunks are really queued. */ +int sctp_outq_uncork(struct sctp_outq *q) { - struct sctp_transport *transport = packet->transport; - struct sk_buff_head *queue = &q->out; - sctp_xmit_t status; - int error; - - frag->subh.data_hdr->tsn = htonl(tsn); - frag->has_tsn = 1; - - /* An inner fragment may be smaller than the earlier one and may get - * in if we call q->build_output. This ensures that all the fragments - * are sent in order. - */ - if (!skb_queue_empty(queue)) { - SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. " - "adding 0x%x to outqueue\n", - ntohl(frag->subh.data_hdr->tsn)); - if (pos) - sctp_outq_insert_data(q, frag, pos); - else - sctp_outq_tail_data(q, frag); - return; - } - - /* Add the chunk fragment to the packet. */ - status = (*q->build_output)(packet, frag); - switch (status) { - case SCTP_XMIT_RWND_FULL: - /* RWND is full, so put the chunk in the output queue. */ - SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. " - "adding 0x%x to outqueue\n", - ntohl(frag->subh.data_hdr->tsn)); - if (pos) - sctp_outq_insert_data(q, frag, pos); - else - sctp_outq_tail_data(q, frag); - break; - - case SCTP_XMIT_OK: - error = (*q->force_output)(packet); - if (error < 0) { - /* Packet could not be transmitted, put the chunk in - * the output queue - */ - SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " - "failed. adding 0x%x to outqueue\n", - ntohl(frag->subh.data_hdr->tsn)); - if (pos) - sctp_outq_insert_data(q, frag, pos); - else - sctp_outq_tail_data(q, frag); - } else { - SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " - "success. 0x%x sent\n", - ntohl(frag->subh.data_hdr->tsn)); - list_add_tail(&frag->transmitted_list, - &transport->transmitted); - - sctp_transport_reset_timers(transport); - } - break; - - default: - BUG(); - }; -} - -/* This routine calls sctp_xmit_frag() for all the fragments of a message. - * The argument 'frag' point to the first fragment and it holds the list - * of all the other fragments in the 'frag_list' field. - */ -void sctp_xmit_fragmented_chunks(struct sctp_outq *q, struct sctp_packet *pkt, - sctp_chunk_t *frag) -{ - sctp_association_t *asoc = frag->asoc; - struct list_head *lfrag, *frag_list; - __u32 tsn; - int nfrags = 1; - struct sctp_chunk *pos; - - /* Count the number of fragments. */ - frag_list = &frag->frag_list; - list_for_each(lfrag, frag_list) { - nfrags++; - } - - /* Get a TSN block of nfrags TSNs. */ - tsn = sctp_association_get_tsn_block(asoc, nfrags); - - pos = (struct sctp_chunk *)skb_peek(&q->out); - /* Transmit the first fragment. */ - sctp_xmit_frag(q, pos, pkt, frag, tsn++); - - /* Transmit the rest of fragments. */ - frag_list = &frag->frag_list; - list_for_each(lfrag, frag_list) { - frag = list_entry(lfrag, sctp_chunk_t, frag_list); - sctp_xmit_frag(q, pos, pkt, frag, tsn++); - } -} - -/* This routine breaks the given chunk into 'max_frag_data_len' size - * fragments. It returns the first fragment with the frag_list field holding - * the remaining fragments. - */ -sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, - size_t max_frag_data_len) -{ - sctp_association_t *asoc = chunk->asoc; - void *data_ptr = chunk->subh.data_hdr; - struct sctp_sndrcvinfo *sinfo = &chunk->sinfo; - __u16 chunk_data_len = sctp_data_size(chunk); - __u16 ssn = ntohs(chunk->subh.data_hdr->ssn); - sctp_chunk_t *first_frag, *frag; - struct list_head *frag_list; - int nfrags; - __u8 old_flags, flags; - - /* nfrags = no. of max size fragments + any smaller last fragment. */ - nfrags = ((chunk_data_len / max_frag_data_len) + - ((chunk_data_len % max_frag_data_len) ? 1 : 0)); - - /* Start of the data in the chunk. */ - data_ptr += sizeof(sctp_datahdr_t); - - /* Are we fragmenting an already fragmented large message? */ - old_flags = chunk->chunk_hdr->flags; - if (old_flags & SCTP_DATA_FIRST_FRAG) - flags = SCTP_DATA_FIRST_FRAG; - else - flags = SCTP_DATA_MIDDLE_FRAG; - - /* Make the first fragment. */ - first_frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, - data_ptr, flags, ssn); - - if (!first_frag) - goto err; - first_frag->has_ssn = 1; - /* All the fragments are added to the frag_list of the first chunk. */ - frag_list = &first_frag->frag_list; - - chunk_data_len -= max_frag_data_len; - data_ptr += max_frag_data_len; - - /* Make the middle fragments. */ - while (chunk_data_len > max_frag_data_len) { - frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, - data_ptr, SCTP_DATA_MIDDLE_FRAG, - ssn); - if (!frag) - goto err; - frag->has_ssn = 1; - /* Add the middle fragment to the first fragment's - * frag_list. - */ - list_add_tail(&frag->frag_list, frag_list); - - chunk_data_len -= max_frag_data_len; - data_ptr += max_frag_data_len; - } - - if (old_flags & SCTP_DATA_LAST_FRAG) - flags = SCTP_DATA_LAST_FRAG; - else - flags = SCTP_DATA_MIDDLE_FRAG; - - /* Make the last fragment. */ - frag = sctp_make_datafrag(asoc, sinfo, chunk_data_len, data_ptr, - flags, ssn); - if (!frag) - goto err; - frag->has_ssn = 1; - - /* Add the last fragment to the first fragment's frag_list. */ - list_add_tail(&frag->frag_list, frag_list); - - /* Free the original chunk. */ - sctp_free_chunk(chunk); - - return first_frag; - -err: - /* Free any fragments that are created before the failure. */ - if (first_frag) { - struct list_head *flist, *lfrag; - - /* Free all the fragments off the first one. */ - flist = &first_frag->frag_list; - while (NULL != (lfrag = sctp_list_dequeue(flist))) { - frag = list_entry(lfrag, sctp_chunk_t, frag_list); - sctp_free_chunk(frag); - } - - /* Free the first fragment. */ - sctp_free_chunk(first_frag); + int error = 0; + if (q->cork) { + q->cork = 0; + error = sctp_outq_flush(q, 0); } - - return NULL; + return error; } /* - * sctp_outq_flush - Try to flush an outqueue. + * Try to flush an outqueue. * * Description: Send everything in q which we legally can, subject to * congestion limitations. @@ -724,7 +623,7 @@ { struct sctp_packet *packet; struct sctp_packet singleton; - sctp_association_t *asoc = q->asoc; + struct sctp_association *asoc = q->asoc; int ecn_capable = asoc->peer.ecn_capable; __u16 sport = asoc->base.bind_addr.port; __u16 dport = asoc->peer.port; @@ -735,7 +634,7 @@ struct sk_buff_head *queue; struct sctp_transport *transport = NULL; struct sctp_transport *new_transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; sctp_xmit_t status; int error = 0; int start_timer = 0; @@ -762,7 +661,7 @@ } queue = &q->control; - while ((chunk = (sctp_chunk_t *)skb_dequeue(queue))) { + while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) { /* Pick the right transport to use. */ new_transport = chunk->transport; @@ -902,32 +801,25 @@ */ if (chunk->sinfo.sinfo_stream >= asoc->c.sinit_num_ostreams) { - struct sctp_ulpevent *ev; - - /* Generate a SEND FAILED event. */ - ev = sctp_ulpevent_make_send_failed(asoc, - chunk, SCTP_DATA_UNSENT, - SCTP_ERROR_INV_STRM, GFP_ATOMIC); - if (ev) - sctp_ulpq_tail_event(&asoc->ulpq, ev); - /* Free the chunk. */ - sctp_free_chunk(chunk); + /* Mark as s failed send. */ + sctp_datamsg_fail(chunk, SCTP_ERROR_INV_STRM); + sctp_chunk_free(chunk); continue; } - /* Now do delayed assignment of SSN. This will - * probably change again when we start supporting - * large (> approximately 2^16) size messages. - */ - sctp_chunk_assign_ssn(chunk); + /* Has this chunk expired? */ + if (sctp_datamsg_expires(chunk)) { + sctp_datamsg_fail(chunk, 0); + sctp_chunk_free(chunk); + continue; + } /* If there is a specified transport, use it. * Otherwise, we want to use the active path. */ new_transport = chunk->transport; - if (new_transport == NULL || - !new_transport->active) + if (!new_transport || !new_transport->active) new_transport = asoc->peer.active_path; /* Change packets if necessary. */ @@ -979,26 +871,6 @@ goto sctp_flush_out; break; - case SCTP_XMIT_MUST_FRAG: { - sctp_chunk_t *frag; - - frag = sctp_fragment_chunk(chunk, - packet->transport->asoc->frag_point); - if (!frag) { - /* We could not fragment due to out of - * memory condition. Free the original - * chunk and return ENOMEM. - */ - sctp_free_chunk(chunk); - error = -ENOMEM; - return error; - } - - sctp_xmit_fragmented_chunks(q, packet, frag); - goto sctp_flush_out; - break; - } - case SCTP_XMIT_OK: break; @@ -1077,8 +949,8 @@ } /* Update unack_data based on the incoming SACK chunk */ -static void sctp_sack_update_unack_data(sctp_association_t *assoc, - sctp_sackhdr_t *sack) +static void sctp_sack_update_unack_data(struct sctp_association *assoc, + struct sctp_sackhdr *sack) { sctp_sack_variable_t *frags; __u16 unack_data; @@ -1096,12 +968,12 @@ } /* Return the highest new tsn that is acknowledged by the given SACK chunk. */ -static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack, - sctp_association_t *asoc) +static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack, + struct sctp_association *asoc) { struct list_head *ltransport, *lchunk; struct sctp_transport *transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; __u32 highest_new_tsn, tsn; struct list_head *transport_list = &asoc->peer.transport_addr_list; @@ -1111,7 +983,7 @@ transport = list_entry(ltransport, struct sctp_transport, transports); list_for_each(lchunk, &transport->transmitted) { - chunk = list_entry(lchunk, sctp_chunk_t, + chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); tsn = ntohl(chunk->subh.data_hdr->tsn); @@ -1130,26 +1002,64 @@ * Process the SACK against the outqueue. Mostly, this just frees * things off the transmitted queue. */ -int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack) +int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) { - sctp_association_t *asoc = q->asoc; + struct sctp_association *asoc = q->asoc; struct sctp_transport *transport; - sctp_chunk_t *tchunk; + struct sctp_chunk *tchunk; struct list_head *lchunk, *transport_list, *pos; sctp_sack_variable_t *frags = sack->variable; __u32 sack_ctsn, ctsn, tsn; __u32 highest_tsn, highest_new_tsn; __u32 sack_a_rwnd; int outstanding; + struct sctp_transport *primary = asoc->peer.primary_path; + int count_of_newacks = 0; /* Grab the association's destination address list. */ transport_list = &asoc->peer.transport_addr_list; sack_ctsn = ntohl(sack->cum_tsn_ack); + /* + * SFR-CACC algorithm: + * On receipt of a SACK the sender SHOULD execute the + * following statements. + * + * 1) If the cumulative ack in the SACK passes next tsn_at_change + * on the current primary, the CHANGEOVER_ACTIVE flag SHOULD be + * cleared. The CYCLING_CHANGEOVER flag SHOULD also be cleared for + * all destinations. + */ + if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) { + primary->cacc.changeover_active = 0; + list_for_each(pos, transport_list) { + transport = list_entry(pos, struct sctp_transport, + transports); + transport->cacc.cycling_changeover = 0; + } + } + + /* + * SFR-CACC algorithm: + * 2) If the SACK contains gap acks and the flag CHANGEOVER_ACTIVE + * is set the receiver of the SACK MUST take the following actions: + * + * A) Initialize the cacc_saw_newack to 0 for all destination + * addresses. + */ + if (sack->num_gap_ack_blocks > 0 && + primary->cacc.changeover_active) { + list_for_each(pos, transport_list) { + transport = list_entry(pos, struct sctp_transport, + transports); + transport->cacc.cacc_saw_newack = 0; + } + } + /* Get the highest TSN in the sack. */ highest_tsn = sack_ctsn + - ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end); + ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end); if (TSN_lt(asoc->highest_sacked, highest_tsn)) { highest_new_tsn = highest_tsn; @@ -1162,6 +1072,7 @@ * and free those chunks that we can. */ sctp_check_transmitted(q, &q->retransmit, NULL, sack, highest_new_tsn); + sctp_mark_missing(q, &q->retransmit, NULL, highest_new_tsn, 0); /* Run through the transmitted queue. * Credit bytes received and free those chunks which we can. @@ -1173,6 +1084,20 @@ transports); sctp_check_transmitted(q, &transport->transmitted, transport, sack, highest_new_tsn); + /* + * SFR-CACC algorithm: + * C) Let count_of_newacks be the number of + * destinations for which cacc_saw_newack is set. + */ + if (transport->cacc.cacc_saw_newack) + count_of_newacks ++; + } + + list_for_each(pos, transport_list) { + transport = list_entry(pos, struct sctp_transport, + transports); + sctp_mark_missing(q, &transport->transmitted, transport, + highest_new_tsn, count_of_newacks); } /* Move the Cumulative TSN Ack Point if appropriate. */ @@ -1191,11 +1116,12 @@ /* Throw away stuff rotting on the sack queue. */ list_for_each(lchunk, &q->sacked) { - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tchunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); tsn = ntohl(tchunk->subh.data_hdr->tsn); if (TSN_lte(tsn, ctsn)) { lchunk = lchunk->prev; - sctp_free_chunk(tchunk); + sctp_chunk_free(tchunk); } } @@ -1244,12 +1170,9 @@ * 2nd Level Abstractions ********************************************************************/ -/* Go through a transport's transmitted list or the assocication's retransmit +/* Go through a transport's transmitted list or the association's retransmit * list and move chunks that are acked by the Cumulative TSN Ack to q->sacked. - * The retransmit list will not have an associated transport. In case of a - * transmitted list with a transport, the transport's congestion, rto and fast - * retransmit parameters are also updated and if needed a fast retransmit - * process is started. + * The retransmit list will not have an associated transport. * * I added coherent debug information output. --xguo * @@ -1260,17 +1183,16 @@ static void sctp_check_transmitted(struct sctp_outq *q, struct list_head *transmitted_queue, struct sctp_transport *transport, - sctp_sackhdr_t *sack, + struct sctp_sackhdr *sack, __u32 highest_new_tsn_in_sack) { struct list_head *lchunk; - sctp_chunk_t *tchunk; + struct sctp_chunk *tchunk; struct list_head tlist; __u32 tsn; __u32 sack_ctsn; __u32 rtt; __u8 restart_timer = 0; - __u8 do_fast_retransmit = 0; int bytes_acked = 0; /* These state variables are for coherent debug output. --xguo */ @@ -1294,7 +1216,8 @@ /* The while loop will skip empty transmitted queues. */ while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) { - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tchunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); tsn = ntohl(tchunk->subh.data_hdr->tsn); if (sctp_acked(sack, tsn)) { @@ -1315,9 +1238,9 @@ * first instance of the packet or a later * instance). */ - if ((!tchunk->tsn_gap_acked) && - (1 == tchunk->num_times_sent) && - (tchunk->rtt_in_progress)) { + if (!tchunk->tsn_gap_acked && + !tchunk->resent && + tchunk->rtt_in_progress) { rtt = jiffies - tchunk->sent_at; sctp_transport_update_rto(transport, rtt); @@ -1338,6 +1261,25 @@ if (!tchunk->tsn_gap_acked) { tchunk->tsn_gap_acked = 1; bytes_acked += sctp_data_size(tchunk); + /* + * SFR-CACC algorithm: + * 2) If the SACK contains gap acks + * and the flag CHANGEOVER_ACTIVE is + * set the receiver of the SACK MUST + * take the following action: + * + * B) For each TSN t being acked that + * has not been acked in any SACK so + * far, set cacc_saw_newack to 1 for + * the destination that the TSN was + * sent to. + */ + if (transport && + sack->num_gap_ack_blocks && + q->asoc->peer.primary_path->cacc. + changeover_active) + transport->cacc.cacc_saw_newack + = 1; } list_add_tail(&tchunk->transmitted_list, @@ -1524,8 +1466,8 @@ * receiver's advertised window is zero, and there is * only one data chunk in flight to the receiver. */ - if ((0 == q->asoc->peer.rwnd) && - (!list_empty(&tlist)) && + if (!q->asoc->peer.rwnd && + !list_empty(&tlist) && (sack_ctsn+2 == q->asoc->next_tsn)) { SCTP_DEBUG_PRINTK("%s: SACK received for zero " "window probe: %u\n", @@ -1553,12 +1495,26 @@ } } - /* Reconstruct the transmitted list with chunks that are not yet - * acked by the Cumulative TSN Ack. - */ - while (NULL != (lchunk = sctp_list_dequeue(&tlist))) { - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - tsn = ntohl(tchunk->subh.data_hdr->tsn); + list_splice(&tlist, transmitted_queue); +} + +/* Mark chunks as missing and consequently may get retransmitted. */ +static void sctp_mark_missing(struct sctp_outq *q, + struct list_head *transmitted_queue, + struct sctp_transport *transport, + __u32 highest_new_tsn_in_sack, + int count_of_newacks) +{ + struct sctp_chunk *chunk; + struct list_head *pos; + __u32 tsn; + char do_fast_retransmit = 0; + struct sctp_transport *primary = q->asoc->peer.primary_path; + + list_for_each(pos, transmitted_queue) { + + chunk = list_entry(pos, struct sctp_chunk, transmitted_list); + tsn = ntohl(chunk->subh.data_hdr->tsn); /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all * 'Unacknowledged TSN's', if the TSN number of an @@ -1566,26 +1522,35 @@ * value, increment the 'TSN.Missing.Report' count on that * chunk if it has NOT been fast retransmitted or marked for * fast retransmit already. - * + */ + if (!chunk->fast_retransmit && + !chunk->tsn_gap_acked && + TSN_lt(tsn, highest_new_tsn_in_sack)) { + + /* SFR-CACC may require us to skip marking + * this chunk as missing. + */ + if (!transport || !sctp_cacc_skip(primary, transport, + count_of_newacks, tsn)) { + chunk->tsn_missing_report++; + + SCTP_DEBUG_PRINTK( + "%s: TSN 0x%x missing counter: %d\n", + __FUNCTION__, tsn, + chunk->tsn_missing_report); + } + } + /* * M4) If any DATA chunk is found to have a * 'TSN.Missing.Report' * value larger than or equal to 4, mark that chunk for * retransmission and start the fast retransmit procedure. */ - if ((!tchunk->fast_retransmit) && - (!tchunk->tsn_gap_acked) && - (TSN_lt(tsn, highest_new_tsn_in_sack))) { - tchunk->tsn_missing_report++; - SCTP_DEBUG_PRINTK("%s: TSN 0x%x missing counter: %d\n", - __FUNCTION__, tsn, - tchunk->tsn_missing_report); - } - if (tchunk->tsn_missing_report >= 4) { - tchunk->fast_retransmit = 1; + + if (chunk->tsn_missing_report >= 4) { + chunk->fast_retransmit = 1; do_fast_retransmit = 1; } - - list_add_tail(lchunk, transmitted_queue); } if (transport) { @@ -1601,7 +1566,7 @@ } /* Is the given TSN acked by this packet? */ -static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn) +static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn) { int i; sctp_sack_variable_t *frags; diff -urN linux-2.5.69-bk3/net/sctp/primitive.c linux-2.5.69-bk4/net/sctp/primitive.c --- linux-2.5.69-bk3/net/sctp/primitive.c 2003-05-04 16:53:57.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/primitive.c 2003-05-09 04:41:39.000000000 -0700 @@ -55,12 +55,12 @@ #define DECLARE_PRIMITIVE(name) \ /* This is called in the code as sctp_primitive_ ## name. */ \ -int sctp_primitive_ ## name(sctp_association_t *asoc, \ +int sctp_primitive_ ## name(struct sctp_association *asoc, \ void *arg) { \ int error = 0; \ sctp_event_t event_type; sctp_subtype_t subtype; \ sctp_state_t state; \ - sctp_endpoint_t *ep; \ + struct sctp_endpoint *ep; \ \ event_type = SCTP_EVENT_T_PRIMITIVE; \ subtype = SCTP_ST_PRIMITIVE(SCTP_PRIMITIVE_ ## name); \ diff -urN linux-2.5.69-bk3/net/sctp/protocol.c linux-2.5.69-bk4/net/sctp/protocol.c --- linux-2.5.69-bk3/net/sctp/protocol.c 2003-05-04 16:53:32.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/protocol.c 2003-05-09 04:41:39.000000000 -0700 @@ -56,6 +56,7 @@ #include #include #include +#include /* Global data structures. */ struct sctp_protocol sctp_proto; @@ -203,7 +204,7 @@ /* Copy the local addresses which are valid for 'scope' into 'bp'. */ int sctp_copy_local_addr_list(struct sctp_protocol *proto, struct sctp_bind_addr *bp, sctp_scope_t scope, - int priority, int copy_flags) + int gfp, int copy_flags) { struct sockaddr_storage_list *addr; int error = 0; @@ -223,8 +224,8 @@ (((AF_INET6 == addr->a.sa.sa_family) && (copy_flags & SCTP_ADDR6_ALLOWED) && (copy_flags & SCTP_ADDR6_PEERSUPP)))) { - error = sctp_add_bind_addr(bp, &addr->a, - priority); + error = sctp_add_bind_addr(bp, &addr->a, + GFP_ATOMIC); if (error) goto end_copy; } @@ -267,11 +268,16 @@ } /* Initialize sk->rcv_saddr from sctp_addr. */ -static void sctp_v4_to_sk(union sctp_addr *addr, struct sock *sk) +static void sctp_v4_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { inet_sk(sk)->rcv_saddr = addr->v4.sin_addr.s_addr; } +/* Initialize sk->daddr from sctp_addr. */ +static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk) +{ + inet_sk(sk)->daddr = addr->v4.sin_addr.s_addr; +} /* Initialize a sctp_addr from a dst_entry. */ static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst, @@ -388,7 +394,7 @@ { struct rtable *rt; struct flowi fl; - sctp_bind_addr_t *bp; + struct sctp_bind_addr *bp; rwlock_t *addr_lock; struct sockaddr_storage_list *laddr; struct list_head *pos; @@ -471,21 +477,33 @@ /* For v4, the source address is cached in the route entry(dst). So no need * to cache it separately and hence this is an empty routine. */ -void sctp_v4_get_saddr(sctp_association_t *asoc, +void sctp_v4_get_saddr(struct sctp_association *asoc, struct dst_entry *dst, union sctp_addr *daddr, union sctp_addr *saddr) { + struct rtable *rt = (struct rtable *)dst; + if (rt) { + saddr->v4.sin_family = AF_INET; + saddr->v4.sin_port = asoc->base.bind_addr.port; + saddr->v4.sin_addr.s_addr = rt->rt_src; + } } /* What interface did this skb arrive on? */ -int sctp_v4_skb_iif(const struct sk_buff *skb) +static int sctp_v4_skb_iif(const struct sk_buff *skb) +{ + return ((struct rtable *)skb->dst)->rt_iif; +} + +/* Was this packet marked by Explicit Congestion Notification? */ +static int sctp_v4_is_ce(const struct sk_buff *skb) { - return ((struct rtable *)skb->dst)->rt_iif; + return INET_ECN_is_ce(skb->nh.iph->tos); } -/* Create and initialize a new sk for the socket returned by accept(). */ +/* Create and initialize a new sk for the socket returned by accept(). */ struct sock *sctp_v4_create_accept_sk(struct sock *sk, struct sctp_association *asoc) { @@ -506,22 +524,27 @@ newsk->prot = sk->prot; newsk->no_check = sk->no_check; newsk->reuse = sk->reuse; + newsk->shutdown = sk->shutdown; newsk->destruct = inet_sock_destruct; newsk->zapped = 0; newsk->family = PF_INET; newsk->protocol = IPPROTO_SCTP; newsk->backlog_rcv = sk->prot->backlog_rcv; - + newinet = inet_sk(newsk); + + /* Initialize sk's sport, dport, rcv_saddr and daddr for + * getsockname() and getpeername() + */ newinet->sport = inet->sport; newinet->saddr = inet->saddr; - newinet->rcv_saddr = inet->saddr; - newinet->dport = asoc->peer.port; + newinet->rcv_saddr = inet->rcv_saddr; + newinet->dport = htons(asoc->peer.port); newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; newinet->pmtudisc = inet->pmtudisc; newinet->id = 0; - + newinet->ttl = sysctl_ip_default_ttl; newinet->mc_loop = 1; newinet->mc_ttl = 1; @@ -568,7 +591,7 @@ if (sctp_get_pf_specific(PF_INET6)) family = PF_INET6; - else + else family = PF_INET; err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP, @@ -695,7 +718,7 @@ return sctp_v4_available(addr); } -/* Verify that sockaddr looks sendable. Common verification has already +/* Verify that sockaddr looks sendable. Common verification has already * been taken care of. */ static int sctp_inet_send_verify(struct sctp_opt *opt, union sctp_addr *addr) @@ -706,7 +729,7 @@ /* Fill in Supported Address Type information for INIT and INIT-ACK * chunks. Returns number of addresses supported. */ -static int sctp_inet_supported_addrs(const struct sctp_opt *opt, +static int sctp_inet_supported_addrs(const struct sctp_opt *opt, __u16 *types) { types[0] = SCTP_PARAM_IPV4_ADDRESS; @@ -805,7 +828,8 @@ .copy_addrlist = sctp_v4_copy_addrlist, .from_skb = sctp_v4_from_skb, .from_sk = sctp_v4_from_sk, - .to_sk = sctp_v4_to_sk, + .to_sk_saddr = sctp_v4_to_sk_saddr, + .to_sk_daddr = sctp_v4_to_sk_daddr, .dst_saddr = sctp_v4_dst_saddr, .cmp_addr = sctp_v4_cmp_addr, .addr_valid = sctp_v4_addr_valid, @@ -814,6 +838,7 @@ .available = sctp_v4_available, .scope = sctp_v4_scope, .skb_iif = sctp_v4_skb_iif, + .is_ce = sctp_v4_is_ce, .net_header_len = sizeof(struct iphdr), .sockaddr_len = sizeof(struct sockaddr_in), .sa_family = AF_INET, diff -urN linux-2.5.69-bk3/net/sctp/sm_make_chunk.c linux-2.5.69-bk4/net/sctp/sm_make_chunk.c --- linux-2.5.69-bk3/net/sctp/sm_make_chunk.c 2003-05-04 16:53:02.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/sm_make_chunk.c 2003-05-09 04:41:39.000000000 -0700 @@ -59,6 +59,8 @@ #include #include #include +#include +#include #include #include @@ -95,7 +97,7 @@ * provided chunk, as most cause codes will be embedded inside an * abort chunk. */ -void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code, +void sctp_init_cause(struct sctp_chunk *chunk, __u16 cause_code, const void *payload, size_t paylen) { sctp_errhdr_t err; @@ -156,14 +158,14 @@ * Host Name Address (Note 3) Optional 11 * Supported Address Types (Note 4) Optional 12 */ -sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, - const sctp_bind_addr_t *bp, +struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, + const struct sctp_bind_addr *bp, int gfp, int vparam_len) { sctp_inithdr_t init; union sctp_params addrs; size_t chunksize; - sctp_chunk_t *retval = NULL; + struct sctp_chunk *retval = NULL; int num_types, addrs_len = 0; struct sctp_opt *sp; sctp_supported_addrs_param_t sat; @@ -175,12 +177,9 @@ * can be IPv4 and/or IPv6 in any combination. */ retval = NULL; - addrs.v = NULL; - /* Convert the provided bind address list to raw format */ + /* Convert the provided bind address list to raw format. */ addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, gfp); - if (!addrs.v) - goto nodata; init.init_tag = htonl(asoc->c.my_vtag); init.a_rwnd = htonl(asoc->rwnd); @@ -236,12 +235,12 @@ return retval; } -sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, int gfp, int unkparam_len) { sctp_inithdr_t initack; - sctp_chunk_t *retval; + struct sctp_chunk *retval; union sctp_params addrs; int addrs_len; sctp_cookie_param_t *cookie; @@ -250,9 +249,8 @@ retval = NULL; + /* Note: there may be no addresses to embed. */ addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, gfp); - if (!addrs.v) - goto nomem_rawaddr; initack.init_tag = htonl(asoc->c.my_vtag); initack.a_rwnd = htonl(asoc->rwnd); @@ -294,7 +292,7 @@ sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); /* We need to remove the const qualifier at this point. */ - retval->asoc = (sctp_association_t *) asoc; + retval->asoc = (struct sctp_association *) asoc; /* RFC 2960 6.4 Multi-homed SCTP Endpoints * @@ -311,8 +309,8 @@ nomem_chunk: kfree(cookie); nomem_cookie: - kfree(addrs.v); -nomem_rawaddr: + if (addrs.v) + kfree(addrs.v); return retval; } @@ -350,10 +348,10 @@ * An implementation SHOULD make the cookie as small as possible * to insure interoperability. */ -sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; void *cookie; int cookie_len; @@ -401,10 +399,10 @@ * * Set to zero on transmit and ignored on receipt. */ -sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0); @@ -446,11 +444,11 @@ * * Note: The CWR is considered a Control chunk. */ -sctp_chunk_t *sctp_make_cwr(const sctp_association_t *asoc, +struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc, const __u32 lowest_tsn, - const sctp_chunk_t *chunk) + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_cwrhdr_t cwr; cwr.lowest_tsn = htonl(lowest_tsn); @@ -481,10 +479,10 @@ } /* Make an ECNE chunk. This is a congestion experienced report. */ -sctp_chunk_t *sctp_make_ecne(const sctp_association_t *asoc, +struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc, const __u32 lowest_tsn) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_ecnehdr_t ecne; ecne.lowest_tsn = htonl(lowest_tsn); @@ -502,25 +500,27 @@ /* Make a DATA chunk for the given association from the provided * parameters. However, do not populate the data payload. */ -sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc, +struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, __u8 flags, __u16 ssn) { - sctp_chunk_t *retval; - sctp_datahdr_t dp; + struct sctp_chunk *retval; + struct sctp_datahdr dp; int chunk_len; /* We assign the TSN as LATE as possible, not here when * creating the chunk. */ - dp.tsn= 1000000; /* This marker is a debugging aid. */ + dp.tsn = 0; dp.stream = htons(sinfo->sinfo_stream); dp.ppid = htonl(sinfo->sinfo_ppid); - dp.ssn = htons(ssn); /* Set the flags for an unordered send. */ - if (sinfo->sinfo_flags & MSG_UNORDERED) + if (sinfo->sinfo_flags & MSG_UNORDERED) { flags |= SCTP_DATA_UNORDERED; + dp.ssn = 0; + } else + dp.ssn = htons(ssn); chunk_len = sizeof(dp) + data_len; retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len); @@ -537,12 +537,12 @@ /* Make a DATA chunk for the given association. Populate the data * payload. */ -sctp_chunk_t *sctp_make_datafrag(sctp_association_t *asoc, +struct sctp_chunk *sctp_make_datafrag(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, const __u8 *data, __u8 flags, __u16 ssn) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); if (retval) @@ -554,11 +554,11 @@ /* Make a DATA chunk for the given association to ride on stream id * 'stream', with a payload id of 'payload', and a body of 'data'. */ -sctp_chunk_t *sctp_make_data(sctp_association_t *asoc, +struct sctp_chunk *sctp_make_data(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, const __u8 *data) { - sctp_chunk_t *retval = NULL; + struct sctp_chunk *retval = NULL; retval = sctp_make_data_empty(asoc, sinfo, data_len); if (retval) @@ -571,7 +571,7 @@ * hold 'data_len' octets of data. We use this version when we need * to build the message AFTER allocating memory. */ -sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc, +struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len) { @@ -584,9 +584,9 @@ * association. This reports on which TSN's we've seen to date, * including duplicates and gaps. */ -sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) +struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_sackhdr_t sack; sctp_gap_ack_block_t gab; int length; @@ -599,11 +599,13 @@ SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn); /* Count the number of Gap Ack Blocks. */ - sctp_tsnmap_iter_init(map, &iter); - for (num_gabs = 0; - sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end); - num_gabs++) { - /* Do nothing. */ + num_gabs = 0; + + if (sctp_tsnmap_has_gap(map)) { + sctp_tsnmap_iter_init(map, &iter); + while (sctp_tsnmap_next_gap_ack(map, &iter, + &gab.start, &gab.end)) + num_gabs++; } num_dup_tsns = sctp_tsnmap_num_dups(map); @@ -659,11 +661,15 @@ sctp_addto_chunk(retval, sizeof(sack), &sack); /* Put the Gap Ack Blocks into the chunk. */ - sctp_tsnmap_iter_init(map, &iter); - while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) { - gab.start = htons(gab.start); - gab.end = htons(gab.end); - sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), &gab); + if (num_gabs) { + sctp_tsnmap_iter_init(map, &iter); + while(sctp_tsnmap_next_gap_ack(map, &iter, + &gab.start, &gab.end)) { + gab.start = htons(gab.start); + gab.end = htons(gab.end); + sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), + &gab); + } } /* Register the duplicates. */ @@ -675,9 +681,9 @@ } /* Make a SHUTDOWN chunk. */ -sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc) +struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_shutdownhdr_t shut; __u32 ctsn; @@ -695,10 +701,10 @@ return retval; } -sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); @@ -717,10 +723,11 @@ return retval; } -sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_shutdown_complete( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; __u8 flags = 0; /* Maybe set the T-bit if we have no association. */ @@ -747,11 +754,11 @@ /* Create an ABORT. Note that we set the T bit if we have no * association. */ -sctp_chunk_t *sctp_make_abort(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, const size_t hint) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; __u8 flags = 0; /* Maybe set the T-bit if we have no association. */ @@ -775,10 +782,11 @@ } /* Helper to create ABORT with a NO_USER_DATA error. */ -sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, __u32 tsn) +struct sctp_chunk *sctp_make_abort_no_data( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, __u32 tsn) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; __u32 payload; retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) @@ -809,17 +817,22 @@ } /* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error. */ -sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, const struct msghdr *msg) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; void *payload = NULL, *payoff; - size_t paylen; - struct iovec *iov = msg->msg_iov; - int iovlen = msg->msg_iovlen; + size_t paylen = 0; + struct iovec *iov = NULL; + int iovlen = 0; + + if (msg) { + iov = msg->msg_iov; + iovlen = msg->msg_iovlen; + paylen = get_user_iov_size(iov, iovlen); + } - paylen = get_user_iov_size(iov, iovlen); retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen); if (!retval) goto err_chunk; @@ -832,7 +845,7 @@ payoff = payload; for (; iovlen > 0; --iovlen) { - if (copy_from_user(payoff, iov->iov_base, iov->iov_len)) + if (copy_from_user(payoff, iov->iov_base,iov->iov_len)) goto err_copy; payoff += iov->iov_len; iov++; @@ -849,18 +862,18 @@ err_copy: kfree(payload); err_payload: - sctp_free_chunk(retval); + sctp_chunk_free(retval); retval = NULL; err_chunk: return retval; } /* Make a HEARTBEAT chunk. */ -sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc, +struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, const struct sctp_transport *transport, const void *payload, const size_t paylen) { - sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, + struct sctp_chunk *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, 0, paylen); if (!retval) @@ -876,15 +889,16 @@ return retval; } -sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, const void *payload, const size_t paylen) { - sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, - 0, paylen); + struct sctp_chunk *retval; + retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); if (!retval) goto nodata; + retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); /* RFC 2960 6.4 Multi-homed SCTP Endpoints @@ -906,11 +920,12 @@ /* Create an Operation Error chunk with the specified space reserved. * This routine can be used for containing multiple causes in the chunk. */ -sctp_chunk_t *sctp_make_op_error_space(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, - size_t size) +struct sctp_chunk *sctp_make_op_error_space( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, + size_t size) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, sizeof(sctp_errhdr_t) + size); @@ -933,13 +948,14 @@ } /* Create an Operation Error chunk. */ -sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, __u16 cause_code, const void *payload, size_t paylen) { - sctp_chunk_t *retval = sctp_make_op_error_space(asoc, chunk, paylen); + struct sctp_chunk *retval; + retval = sctp_make_op_error_space(asoc, chunk, paylen); if (!retval) goto nodata; @@ -956,26 +972,27 @@ /* Turn an skb into a chunk. * FIXME: Eventually move the structure directly inside the skb->cb[]. */ -sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, +struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, + const struct sctp_association *asoc, struct sock *sk) { - sctp_chunk_t *retval = t_new(sctp_chunk_t, GFP_ATOMIC); + struct sctp_chunk *retval = t_new(struct sctp_chunk, GFP_ATOMIC); if (!retval) goto nodata; - memset(retval, 0, sizeof(sctp_chunk_t)); + memset(retval, 0, sizeof(struct sctp_chunk)); if (!sk) { SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb); } retval->skb = skb; - retval->asoc = (sctp_association_t *) asoc; - retval->num_times_sent = 0; + retval->asoc = (struct sctp_association *)asoc; + retval->resent = 0; retval->has_tsn = 0; retval->has_ssn = 0; retval->rtt_in_progress = 0; - retval->sent_at = jiffies; + retval->sent_at = 0; retval->singleton = 1; retval->end_of_packet = 0; retval->ecn_ce_done = 0; @@ -991,17 +1008,24 @@ retval->tsn_gap_acked = 0; retval->fast_retransmit = 0; + /* If this is a fragmented message, track all fragments + * of the message (for SEND_FAILED). + */ + retval->msg = NULL; + /* Polish the bead hole. */ INIT_LIST_HEAD(&retval->transmitted_list); INIT_LIST_HEAD(&retval->frag_list); SCTP_DBG_OBJCNT_INC(chunk); + atomic_set(&retval->refcnt, 1); + nodata: return retval; } /* Set chunk->source and dest based on the IP header in chunk->skb. */ -void sctp_init_addrs(sctp_chunk_t *chunk, union sctp_addr *src, +void sctp_init_addrs(struct sctp_chunk *chunk, union sctp_addr *src, union sctp_addr *dest) { memcpy(&chunk->source, src, sizeof(union sctp_addr)); @@ -1009,7 +1033,7 @@ } /* Extract the source address from a chunk. */ -const union sctp_addr *sctp_source(const sctp_chunk_t *chunk) +const union sctp_addr *sctp_source(const struct sctp_chunk *chunk) { /* If we have a known transport, use that. */ if (chunk->transport) { @@ -1023,16 +1047,16 @@ /* Create a new chunk, setting the type and flags headers from the * arguments, reserving enough space for a 'paylen' byte payload. */ -sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc, +struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, __u8 type, __u8 flags, int paylen) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_chunkhdr_t *chunk_hdr; struct sk_buff *skb; struct sock *sk; /* No need to allocate LL here, as this is only a chunk. */ - skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), + skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), GFP_ATOMIC); if (!skb) goto nodata; @@ -1046,7 +1070,7 @@ sk = asoc ? asoc->base.sk : NULL; retval = sctp_chunkify(skb, asoc, sk); if (!retval) { - dev_kfree_skb(skb); + kfree_skb(skb); goto nodata; } @@ -1062,12 +1086,10 @@ return NULL; } + /* Release the memory occupied by a chunk. */ -void sctp_free_chunk(sctp_chunk_t *chunk) +static void sctp_chunk_destroy(struct sctp_chunk *chunk) { - /* Make sure that we are not on any list. */ - skb_unlink((struct sk_buff *) chunk); - list_del(&chunk->transmitted_list); /* Free the chunk skb data and the SCTP_chunk stub itself. */ dev_kfree_skb(chunk->skb); @@ -1076,11 +1098,37 @@ SCTP_DBG_OBJCNT_DEC(chunk); } +/* Possibly, free the chunk. */ +void sctp_chunk_free(struct sctp_chunk *chunk) +{ + /* Make sure that we are not on any list. */ + skb_unlink((struct sk_buff *) chunk); + list_del(&chunk->transmitted_list); + + /* Release our reference on the message tracker. */ + if (chunk->msg) + sctp_datamsg_put(chunk->msg); + + sctp_chunk_put(chunk); +} + +/* Grab a reference to the chunk. */ +void sctp_chunk_hold(struct sctp_chunk *ch) +{ + atomic_inc(&ch->refcnt); +} + +/* Release a reference to the chunk. */ +void sctp_chunk_put(struct sctp_chunk *ch) +{ + if (atomic_dec_and_test(&ch->refcnt)) + sctp_chunk_destroy(ch); +} /* Append bytes to the end of a chunk. Will panic if chunk is not big * enough. */ -void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data) +void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) { void *target; void *padding; @@ -1104,8 +1152,8 @@ * chunk is not big enough. * Returns a kernel err value. */ -static int sctp_user_addto_chunk(sctp_chunk_t *chunk, int off, int len, - struct iovec *data) +int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len, + struct iovec *data) { __u8 *target; int err = 0; @@ -1126,132 +1174,10 @@ return err; } -/* A data chunk can have a maximum payload of (2^16 - 20). Break - * down any such message into smaller chunks. Opportunistically, fragment - * the chunks down to the current MTU constraints. We may get refragmented - * later if the PMTU changes, but it is _much better_ to fragment immediately - * with a reasonable guess than always doing our fragmentation on the - * soft-interrupt. - */ - - -int sctp_datachunks_from_user(sctp_association_t *asoc, - const struct sctp_sndrcvinfo *sinfo, - struct msghdr *msg, int msg_len, - struct sk_buff_head *chunks) -{ - int max, whole, i, offset, over, err; - int len, first_len; - sctp_chunk_t *chunk; - __u8 frag; - - /* What is a reasonable fragmentation point right now? */ - max = asoc->pmtu; - if (max < SCTP_MIN_PMTU) - max = SCTP_MIN_PMTU; - max -= SCTP_IP_OVERHEAD; - - /* Make sure not beyond maximum chunk size. */ - if (max > SCTP_MAX_CHUNK_LEN) - max = SCTP_MAX_CHUNK_LEN; - - /* Subtract out the overhead of a data chunk header. */ - max -= sizeof(struct sctp_data_chunk); - - whole = 0; - first_len = max; - - /* Encourage Cookie-ECHO bundling. */ - if (asoc->state < SCTP_STATE_COOKIE_ECHOED) { - whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN); - - /* Account for the DATA to be bundled with the COOKIE-ECHO. */ - if (whole) { - first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN; - msg_len -= first_len; - whole = 1; - } - } - - /* How many full sized? How many bytes leftover? */ - whole += msg_len / max; - over = msg_len % max; - offset = 0; - - if (whole && over) - SCTP_INC_STATS_USER(SctpFragUsrMsgs); - - /* Create chunks for all the full sized DATA chunks. */ - for (i=0, len=first_len; i < whole; i++) { - frag = SCTP_DATA_MIDDLE_FRAG; - - if (0 == i) - frag |= SCTP_DATA_FIRST_FRAG; - - if ((i == (whole - 1)) && !over) - frag |= SCTP_DATA_LAST_FRAG; - - chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); - - if (!chunk) - goto nomem; - err = sctp_user_addto_chunk(chunk, offset, len, msg->msg_iov); - if (err < 0) - goto errout; - - offset += len; - - /* Put the chunk->skb back into the form expected by send. */ - __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr - - (__u8 *)chunk->skb->data); - - __skb_queue_tail(chunks, (struct sk_buff *)chunk); - - /* The first chunk, the first chunk was likely short - * to allow bundling, so reset to full size. - */ - if (0 == i) - len = max; - } - - /* .. now the leftover bytes. */ - if (over) { - if (!whole) - frag = SCTP_DATA_NOT_FRAG; - else - frag = SCTP_DATA_LAST_FRAG; - - chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); - - if (!chunk) - goto nomem; - - err = sctp_user_addto_chunk(chunk, offset, over, msg->msg_iov); - - /* Put the chunk->skb back into the form expected by send. */ - __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr - - (__u8 *)chunk->skb->data); - if (err < 0) - goto errout; - - __skb_queue_tail(chunks, (struct sk_buff *)chunk); - } - err = 0; - goto out; - -nomem: - err = -ENOMEM; -errout: - while ((chunk = (sctp_chunk_t *)__skb_dequeue(chunks))) - sctp_free_chunk(chunk); -out: - return err; -} - /* Helper function to assign a TSN if needed. This assumes that both * the data_hdr and association have already been assigned. */ -void sctp_chunk_assign_ssn(sctp_chunk_t *chunk) +void sctp_chunk_assign_ssn(struct sctp_chunk *chunk) { __u16 ssn; __u16 sid; @@ -1278,7 +1204,7 @@ /* Helper function to assign a TSN if needed. This assumes that both * the data_hdr and association have already been assigned. */ -void sctp_chunk_assign_tsn(sctp_chunk_t *chunk) +void sctp_chunk_assign_tsn(struct sctp_chunk *chunk) { if (!chunk->has_tsn) { /* This is the last possible instant to @@ -1291,10 +1217,10 @@ } /* Create a CLOSED association to use with an incoming packet. */ -sctp_association_t *sctp_make_temp_asoc(const struct sctp_endpoint *ep, +struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep, struct sctp_chunk *chunk, int gfp) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct sk_buff *skb; sctp_scope_t scope; @@ -1303,6 +1229,7 @@ asoc = sctp_association_new(ep, ep->base.sk, scope, gfp); if (!asoc) goto nodata; + asoc->temp = 1; skb = chunk->skb; /* Create an entry for the source address of the packet. */ /* FIXME: Use the af specific helpers. */ @@ -1339,15 +1266,18 @@ /* Build a cookie representing asoc. * This INCLUDES the param header needed to put the cookie in the INIT ACK. */ -sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_chunk_t *init_chunk, +sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const struct sctp_chunk *init_chunk, int *cookie_len, const __u8 *raw_addrs, int addrs_len) { sctp_cookie_param_t *retval; sctp_signed_cookie_t *cookie; + struct scatterlist sg; int headersize, bodysize; + unsigned int keylen; + char *key; headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; bodysize = sizeof(sctp_cookie_t) @@ -1361,8 +1291,8 @@ - (bodysize % SCTP_COOKIE_MULTIPLE); *cookie_len = headersize + bodysize; - retval = (sctp_cookie_param_t *) - kmalloc(*cookie_len, GFP_ATOMIC); + retval = (sctp_cookie_param_t *)kmalloc(*cookie_len, GFP_ATOMIC); + if (!retval) { *cookie_len = 0; goto nodata; @@ -1393,30 +1323,39 @@ /* Copy the raw local address list of the association. */ memcpy((__u8 *)&cookie->c.peer_init[0] + - ntohs(init_chunk->chunk_hdr->length), raw_addrs, - addrs_len); + ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len); - /* Sign the message. */ - sctp_hash_digest(ep->secret_key[ep->current_key], SCTP_SECRET_SIZE, - (__u8 *) &cookie->c, bodysize, cookie->signature); + if (sctp_sk(ep->base.sk)->hmac) { + /* Sign the message. */ + sg.page = virt_to_page(&cookie->c); + sg.offset = (unsigned long)(&cookie->c) % PAGE_SIZE; + sg.length = bodysize; + keylen = SCTP_SECRET_SIZE; + key = (char *)ep->secret_key[ep->current_key]; + + sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, + &sg, 1, cookie->signature); + } nodata: return retval; } /* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */ -sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, int gfp, - int *error, sctp_chunk_t **err_chk_p) +struct sctp_association *sctp_unpack_cookie( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, int gfp, + int *error, struct sctp_chunk **errp) { - sctp_association_t *retval = NULL; + struct sctp_association *retval = NULL; sctp_signed_cookie_t *cookie; sctp_cookie_t *bear_cookie; - int headersize, bodysize; - int fixed_size; - __u8 digest_buf[SCTP_SIGNATURE_SIZE]; - int secret; + int headersize, bodysize, fixed_size; + __u8 digest[SCTP_SIGNATURE_SIZE]; + struct scatterlist sg; + unsigned int keylen; + char *key; sctp_scope_t scope; struct sk_buff *skb = chunk->skb; @@ -1440,23 +1379,35 @@ cookie = chunk->subh.cookie_hdr; bear_cookie = &cookie->c; + if (!sctp_sk(ep->base.sk)->hmac) + goto no_hmac; + /* Check the signature. */ - secret = ep->current_key; - sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, - (__u8 *) bear_cookie, bodysize, - digest_buf); - if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { + keylen = SCTP_SECRET_SIZE; + sg.page = virt_to_page(bear_cookie); + sg.offset = (unsigned long)(bear_cookie) % PAGE_SIZE; + sg.length = bodysize; + key = (char *)ep->secret_key[ep->current_key]; + + memset(digest, 0x00, sizeof(digest)); + sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, + 1, digest); + + if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { /* Try the previous key. */ - secret = ep->last_key; - sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, - (__u8 *) bear_cookie, bodysize, digest_buf); - if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { + key = (char *)ep->secret_key[ep->last_key]; + memset(digest, 0x00, sizeof(digest)); + sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, + &sg, 1, digest); + + if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { /* Yikes! Still bad signature! */ *error = -SCTP_IERROR_BAD_SIG; goto fail; } } +no_hmac: /* Check to see if the cookie is stale. If there is already * an association, there is no need to check cookie's expiration * for init collision case of lost COOKIE ACK. @@ -1472,15 +1423,15 @@ * Cookie that has expired. */ len = ntohs(chunk->chunk_hdr->length); - *err_chk_p = sctp_make_op_error_space(asoc, chunk, len); - if (*err_chk_p) { + *errp = sctp_make_op_error_space(asoc, chunk, len); + if (*errp) { suseconds_t usecs = (skb->stamp.tv_sec - bear_cookie->expiration.tv_sec) * 1000000L + skb->stamp.tv_usec - bear_cookie->expiration.tv_usec; usecs = htonl(usecs); - sctp_init_cause(*err_chk_p, SCTP_ERROR_STALE_COOKIE, + sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE, &usecs, sizeof(usecs)); *error = -SCTP_IERROR_STALE_COOKIE; } else @@ -1509,6 +1460,12 @@ goto fail; } + /* Also, add the destination address. */ + if (list_empty(&retval->base.bind_addr.address_list)) { + sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, + GFP_ATOMIC); + } + retval->next_tsn = retval->c.initial_tsn; retval->ctsn_ack_point = retval->next_tsn - 1; @@ -1541,10 +1498,10 @@ /* * Report a missing mandatory parameter. */ -static int sctp_process_missing_param(const sctp_association_t *asoc, +static int sctp_process_missing_param(const struct sctp_association *asoc, sctp_param_t paramtype, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { struct __sctp_missing report; __u16 len; @@ -1554,13 +1511,13 @@ /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ - if (!*err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, len); + if (!*errp) + *errp = sctp_make_op_error_space(asoc, chunk, len); - if (*err_chk_p) { + if (*errp) { report.num_missing = htonl(1); report.type = paramtype; - sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM, + sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, &report, sizeof(report)); } @@ -1569,17 +1526,17 @@ } /* Report an Invalid Mandatory Parameter. */ -static int sctp_process_inv_mandatory(const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) +static int sctp_process_inv_mandatory(const struct sctp_association *asoc, + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { /* Invalid Mandatory Parameter Error has no payload. */ - if (!*err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, 0); + if (!*errp) + *errp = sctp_make_op_error_space(asoc, chunk, 0); - if (*err_chk_p) - sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM, NULL, 0); + if (*errp) + sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, NULL, 0); /* Stop processing this chunk. */ return 0; @@ -1588,19 +1545,19 @@ /* Do not attempt to handle the HOST_NAME parm. However, do * send back an indicator to the peer. */ -static int sctp_process_hn_param(const sctp_association_t *asoc, +static int sctp_process_hn_param(const struct sctp_association *asoc, union sctp_params param, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { __u16 len = ntohs(param.p->length); /* Make an ERROR chunk. */ - if (!*err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, len); + if (!*errp) + *errp = sctp_make_op_error_space(asoc, chunk, len); - if (*err_chk_p) - sctp_init_cause(*err_chk_p, SCTP_ERROR_DNS_FAILED, + if (*errp) + sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, param.v, len); /* Stop processing this chunk. */ @@ -1633,10 +1590,10 @@ * 0 - discard the chunk * 1 - continue with the chunk */ -static int sctp_process_unk_param(const sctp_association_t *asoc, +static int sctp_process_unk_param(const struct sctp_association *asoc, union sctp_params param, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { int retval = 1; @@ -1649,12 +1606,12 @@ /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ - if (NULL == *err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, + if (NULL == *errp) + *errp = sctp_make_op_error_space(asoc, chunk, ntohs(chunk->chunk_hdr->length)); - if (*err_chk_p) - sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, + if (*errp) + sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, param.v, WORD_ROUND(ntohs(param.p->length))); @@ -1665,12 +1622,12 @@ /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ - if (NULL == *err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, + if (NULL == *errp) + *errp = sctp_make_op_error_space(asoc, chunk, ntohs(chunk->chunk_hdr->length)); - if (*err_chk_p) { - sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, + if (*errp) { + sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, param.v, WORD_ROUND(ntohs(param.p->length))); } else { @@ -1695,11 +1652,11 @@ * 0 - discard the chunk * 1 - continue with the chunk */ -static int sctp_verify_param(const sctp_association_t *asoc, +static int sctp_verify_param(const struct sctp_association *asoc, union sctp_params param, sctp_cid_t cid, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chunk) + struct sctp_chunk *chunk, + struct sctp_chunk **err_chunk) { int retval = 1; @@ -1733,11 +1690,11 @@ } /* Verify the INIT packet before we process it. */ -int sctp_verify_init(const sctp_association_t *asoc, +int sctp_verify_init(const struct sctp_association *asoc, sctp_cid_t cid, sctp_init_chunk_t *peer_init, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { union sctp_params param; int has_cookie = 0; @@ -1746,7 +1703,7 @@ if ((0 == peer_init->init_hdr.num_outbound_streams) || (0 == peer_init->init_hdr.num_inbound_streams)) { - sctp_process_inv_mandatory(asoc, chunk, err_chk_p); + sctp_process_inv_mandatory(asoc, chunk, errp); return 0; } @@ -1762,9 +1719,8 @@ * the state cookie for an INIT-ACK chunk. */ if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) { - sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE, - chunk, err_chk_p); + chunk, errp); return 0; } @@ -1772,7 +1728,7 @@ sctp_walk_params(param, peer_init, init_hdr.params) { - if (!sctp_verify_param(asoc, param, cid, chunk, err_chk_p)) + if (!sctp_verify_param(asoc, param, cid, chunk, errp)) return 0; } /* for (loop through all parameters) */ @@ -1784,7 +1740,7 @@ * Returns 0 on failure, else success. * FIXME: This is an association method. */ -int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, +int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, const union sctp_addr *peer_addr, sctp_init_chunk_t *peer_init, int gfp) { @@ -1923,7 +1879,7 @@ * work we do. In particular, we should not build transport * structures for the addresses. */ -int sctp_process_param(sctp_association_t *asoc, union sctp_params param, +int sctp_process_param(struct sctp_association *asoc, union sctp_params param, const union sctp_addr *peer_addr, int gfp) { union sctp_addr addr; @@ -2032,7 +1988,7 @@ } /* Select a new verification tag. */ -__u32 sctp_generate_tag(const sctp_endpoint_t *ep) +__u32 sctp_generate_tag(const struct sctp_endpoint *ep) { /* I believe that this random number generator complies with RFC1750. * A tag of 0 is reserved for special cases (e.g. INIT). @@ -2047,7 +2003,7 @@ } /* Select an initial TSN to send during startup. */ -__u32 sctp_generate_tsn(const sctp_endpoint_t *ep) +__u32 sctp_generate_tsn(const struct sctp_endpoint *ep) { __u32 retval; diff -urN linux-2.5.69-bk3/net/sctp/sm_sideeffect.c linux-2.5.69-bk4/net/sctp/sm_sideeffect.c --- linux-2.5.69-bk3/net/sctp/sm_sideeffect.c 2003-05-04 16:53:33.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/sm_sideeffect.c 2003-05-09 04:41:39.000000000 -0700 @@ -60,7 +60,8 @@ ********************************************************************/ /* A helper function for delayed processing of INET ECN CE bit. */ -static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn) +static void sctp_do_ecn_ce_work(struct sctp_association *asoc, + __u32 lowest_tsn) { /* Save the TSN away for comparison when we receive CWR */ @@ -80,11 +81,11 @@ * This element represents the lowest TSN number in the datagram * that was originally marked with the CE bit. */ -static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, +static struct sctp_chunk *sctp_do_ecn_ecne_work(struct sctp_association *asoc, __u32 lowest_tsn, - sctp_chunk_t *chunk) + struct sctp_chunk *chunk) { - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* Our previously transmitted packet ran into some congestion * so we should take action by reducing cwnd and ssthresh @@ -123,7 +124,7 @@ } /* Helper function to do delayed processing of ECN CWR chunk. */ -static void sctp_do_ecn_cwr_work(sctp_association_t *asoc, +static void sctp_do_ecn_cwr_work(struct sctp_association *asoc, __u32 lowest_tsn) { /* Turn off ECNE getting auto-prepended to every outgoing @@ -200,7 +201,7 @@ { int error; struct sctp_transport *transport = (struct sctp_transport *) peer; - sctp_association_t *asoc = transport->asoc; + struct sctp_association *asoc = transport->asoc; /* Check whether a task is in the sock. */ @@ -238,7 +239,7 @@ /* This is a sa interface for producing timeout events. It works * for timeouts which use the association as their parameter. */ -static void sctp_generate_timeout_event(sctp_association_t *asoc, +static void sctp_generate_timeout_event(struct sctp_association *asoc, sctp_event_timeout_t timeout_type) { int error = 0; @@ -265,8 +266,7 @@ error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, SCTP_ST_TIMEOUT(timeout_type), asoc->state, asoc->ep, asoc, - (void *)timeout_type, - GFP_ATOMIC); + (void *)timeout_type, GFP_ATOMIC); if (error) asoc->base.sk->err = -error; @@ -278,25 +278,25 @@ void sctp_generate_t1_cookie_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *) data; + struct sctp_association *asoc = (struct sctp_association *) data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE); } void sctp_generate_t1_init_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *) data; + struct sctp_association *asoc = (struct sctp_association *) data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT); } void sctp_generate_t2_shutdown_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *) data; + struct sctp_association *asoc = (struct sctp_association *) data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN); } void sctp_generate_t5_shutdown_guard_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *)data; + struct sctp_association *asoc = (struct sctp_association *)data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD); @@ -304,7 +304,7 @@ void sctp_generate_autoclose_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *) data; + struct sctp_association *asoc = (struct sctp_association *) data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE); } @@ -315,7 +315,7 @@ { int error = 0; struct sctp_transport *transport = (struct sctp_transport *) data; - sctp_association_t *asoc = transport->asoc; + struct sctp_association *asoc = transport->asoc; sctp_bh_lock_sock(asoc->base.sk); if (sock_owned_by_user(asoc->base.sk)) { @@ -335,8 +335,7 @@ error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT), - asoc->state, - asoc->ep, asoc, + asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC); if (error) @@ -350,7 +349,7 @@ /* Inject a SACK Timeout event into the state machine. */ void sctp_generate_sack_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *) data; + struct sctp_association *asoc = (struct sctp_association *) data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK); } @@ -382,7 +381,7 @@ * notification SHOULD be sent to the upper layer. * */ -static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, +static void sctp_do_8_2_transport_strike(struct sctp_association *asoc, struct sctp_transport *transport) { /* The check for association's overall error counter exceeding the @@ -410,7 +409,7 @@ /* Worker routine to handle INIT command failure. */ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, - sctp_association_t *asoc, + struct sctp_association *asoc, unsigned error) { struct sctp_ulpevent *event; @@ -483,7 +482,7 @@ /* Helper function to break out starting up of heartbeat timers. */ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc) + struct sctp_association *asoc) { struct sctp_transport *t; struct list_head *pos; @@ -501,7 +500,7 @@ } static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc) + struct sctp_association *asoc) { struct sctp_transport *t; struct list_head *pos; @@ -517,7 +516,7 @@ /* Helper function to update the heartbeat timer. */ static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc, + struct sctp_association *asoc, struct sctp_transport *t) { /* Update the heartbeat timer. */ @@ -527,9 +526,9 @@ /* Helper function to handle the reception of an HEARTBEAT ACK. */ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc, + struct sctp_association *asoc, struct sctp_transport *t, - sctp_chunk_t *chunk) + struct sctp_chunk *chunk) { sctp_sender_hb_info_t *hbinfo; @@ -560,7 +559,7 @@ * timer. */ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc, + struct sctp_association *asoc, struct sctp_transport *t) { sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE); @@ -571,7 +570,7 @@ /* Helper function to process the process SACK command. */ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc, + struct sctp_association *asoc, sctp_sackhdr_t *sackh) { int err; @@ -595,8 +594,9 @@ /* Helper function to set the timeout value for T2-SHUTDOWN timer and to set * the transport for a shutdown chunk. */ -static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, - sctp_chunk_t *chunk) +static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, + struct sctp_association *asoc, + struct sctp_chunk *chunk) { struct sctp_transport *t; @@ -607,18 +607,30 @@ } /* Helper function to change the state of an association. */ -static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, +static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, struct sctp_association *asoc, sctp_state_t state) { - struct sock *sk = asoc->base.sk; - struct sctp_opt *sp = sctp_sk(sk); asoc->state = state; asoc->state_timestamp = jiffies; - if ((SCTP_STATE_ESTABLISHED == asoc->state) || - (SCTP_STATE_CLOSED == asoc->state)) { + if (sctp_style(sk, TCP)) { + /* Change the sk->state of a TCP-style socket that has + * sucessfully completed a connect() call. + */ + if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED)) + sk->state = SCTP_SS_ESTABLISHED; + + /* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */ + if (sctp_state(asoc, SHUTDOWN_RECEIVED) && + sctp_sstate(sk, ESTABLISHED)) + sk->shutdown |= RCV_SHUTDOWN; + } + + if (sctp_state(asoc, ESTABLISHED) || + sctp_state(asoc, CLOSED) || + sctp_state(asoc, SHUTDOWN_RECEIVED)) { /* Wake up any processes waiting in the asoc's wait queue in * sctp_wait_for_connect() or sctp_wait_for_sndbuf(). */ @@ -631,16 +643,26 @@ * For a UDP-style socket, the waiters are woken up by the * notifications. */ - if (SCTP_SOCKET_UDP != sp->type) + if (!sctp_style(sk, UDP)) sk->state_change(sk); } +} - /* Change the sk->state of a TCP-style socket that has successfully - * completed a connect() call. - */ - if ((SCTP_STATE_ESTABLISHED == asoc->state) && - (SCTP_SOCKET_TCP == sp->type) && (SCTP_SS_CLOSED == sk->state)) - sk->state = SCTP_SS_ESTABLISHED; +/* Helper function to delete an association. */ +static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds, + struct sctp_association *asoc) +{ + struct sock *sk = asoc->base.sk; + + /* If it is a non-temporary association belonging to a TCP-style + * listening socket, do not free it so that accept() can pick it + * up later. + */ + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) && (!asoc->temp)) + return; + + sctp_unhash_established(asoc); + sctp_association_free(asoc); } /* These three macros allow us to pull the debugging code out of the @@ -673,10 +695,10 @@ */ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, sctp_state_t state, - sctp_endpoint_t *ep, - sctp_association_t *asoc, + struct sctp_endpoint *ep, + struct sctp_association *asoc, void *event_arg, - int priority) + int gfp) { sctp_cmd_seq_t commands; sctp_sm_table_entry_t *state_fn; @@ -701,9 +723,8 @@ DEBUG_POST; error = sctp_side_effects(event_type, subtype, state, - ep, asoc, event_arg, - status, &commands, - priority); + ep, asoc, event_arg, status, + &commands, gfp); DEBUG_POST_SFX; return error; @@ -717,12 +738,12 @@ *****************************************************************/ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, sctp_state_t state, - sctp_endpoint_t *ep, - sctp_association_t *asoc, + struct sctp_endpoint *ep, + struct sctp_association *asoc, void *event_arg, sctp_disposition_t status, sctp_cmd_seq_t *commands, - int priority) + int gfp) { int error; @@ -735,7 +756,7 @@ if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state, ep, asoc, event_arg, status, - commands, priority))) + commands, gfp))) goto bail; switch (status) { @@ -803,25 +824,26 @@ /* This is the side-effect interpreter. */ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, - sctp_state_t state, sctp_endpoint_t *ep, - sctp_association_t *asoc, void *event_arg, + sctp_state_t state, struct sctp_endpoint *ep, + struct sctp_association *asoc, void *event_arg, sctp_disposition_t status, sctp_cmd_seq_t *commands, - int priority) + int gfp) { int error = 0; int force; sctp_cmd_t *cmd; - sctp_chunk_t *new_obj; - sctp_chunk_t *chunk = NULL; + struct sctp_chunk *new_obj; + struct sctp_chunk *chunk = NULL; struct sctp_packet *packet; struct list_head *pos; struct timer_list *timer; unsigned long timeout; struct sctp_transport *t; sctp_sackhdr_t sackh; + int local_cork = 0; - if(SCTP_EVENT_T_TIMEOUT != event_type) - chunk = (sctp_chunk_t *) event_arg; + if (SCTP_EVENT_T_TIMEOUT != event_type) + chunk = (struct sctp_chunk *) event_arg; /* Note: This whole file is a huge candidate for rework. * For example, each command could either have its own handler, so @@ -838,6 +860,10 @@ case SCTP_CMD_NEW_ASOC: /* Register a new association. */ + if (local_cork) { + sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; + } asoc = cmd->obj.ptr; /* Register with the endpoint. */ sctp_endpoint_add_asoc(ep, asoc); @@ -852,10 +878,13 @@ sctp_outq_teardown(&asoc->outqueue); break; - case SCTP_CMD_DELETE_TCB: + case SCTP_CMD_DELETE_TCB: + if (local_cork) { + sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; + } /* Delete the current association. */ - sctp_unhash_established(asoc); - sctp_association_free(asoc); + sctp_cmd_delete_tcb(commands, asoc); asoc = NULL; break; @@ -903,7 +932,7 @@ * layer which will bail. */ error = sctp_cmd_process_init(commands, asoc, chunk, - cmd->obj.ptr, priority); + cmd->obj.ptr, gfp); break; case SCTP_CMD_GEN_COOKIE_ECHO: @@ -911,7 +940,7 @@ new_obj = sctp_make_cookie_echo(asoc, chunk); if (!new_obj) { if (cmd->obj.ptr) - sctp_free_chunk(cmd->obj.ptr); + sctp_chunk_free(cmd->obj.ptr); goto nomem; } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, @@ -957,9 +986,13 @@ break; case SCTP_CMD_REPLY: + /* If an caller has not already corked, do cork. */ + if (!asoc->outqueue.cork) { + sctp_outq_cork(&asoc->outqueue); + local_cork = 1; + } /* Send a chunk to our peer. */ - error = sctp_outq_tail(&asoc->outqueue, - cmd->obj.ptr); + error = sctp_outq_tail(&asoc->outqueue, cmd->obj.ptr); break; case SCTP_CMD_SEND_PKT: @@ -977,7 +1010,8 @@ case SCTP_CMD_TRANSMIT: /* Kick start transmission. */ - error = sctp_outq_flush(&asoc->outqueue, 0); + error = sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; break; case SCTP_CMD_ECN_CE: @@ -1148,13 +1182,15 @@ break; }; if (error) - return error; + break; } +out: + if (local_cork) + sctp_outq_uncork(&asoc->outqueue); return error; - nomem: error = -ENOMEM; - return error; + goto out; } diff -urN linux-2.5.69-bk3/net/sctp/sm_statefuns.c linux-2.5.69-bk4/net/sctp/sm_statefuns.c --- linux-2.5.69-bk3/net/sctp/sm_statefuns.c 2003-05-04 16:53:01.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/sm_statefuns.c 2003-05-09 04:41:39.000000000 -0700 @@ -95,13 +95,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; struct sctp_ulpevent *ev; /* RFC 2960 6.10 Bundling @@ -179,16 +179,16 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; - sctp_chunk_t *repl; - sctp_association_t *new_asoc; - sctp_chunk_t *err_chunk; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *repl; + struct sctp_association *new_asoc; + struct sctp_chunk *err_chunk; struct sctp_packet *packet; sctp_unrecognized_param_t *unk_param; struct sock *sk; @@ -212,9 +212,8 @@ * on the TCP-style socket exceed the max backlog, respond with an * ABORT. */ - if ((SCTP_SS_LISTENING != sk->state) || - ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && - (sk->ack_backlog >= sk->max_ack_backlog))) + if (!sctp_sstate(sk, LISTENING) || + (sctp_style(sk, TCP) && (sk->ack_backlog >= sk->max_ack_backlog))) return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); /* Verify the INIT chunk before processing it. */ @@ -232,7 +231,7 @@ ntohs(err_chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); if (packet) { sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, @@ -260,8 +259,8 @@ /* The call, sctp_process_init(), can fail on memory allocation. */ if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), - (sctp_init_chunk_t *)chunk->chunk_hdr, + sctp_source(chunk), + (sctp_init_chunk_t *)chunk->chunk_hdr, GFP_ATOMIC)) goto nomem_init; @@ -303,7 +302,7 @@ * parameter type. */ sctp_addto_chunk(repl, len, unk_param); - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); @@ -320,7 +319,7 @@ nomem_ack: if (err_chunk) - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); nomem_init: sctp_association_free(new_asoc); nomem: @@ -355,16 +354,16 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_init_chunk_t *initchunk; __u32 init_tag; - sctp_chunk_t *err_chunk; + struct sctp_chunk *err_chunk; struct sctp_packet *packet; sctp_disposition_t ret; @@ -386,7 +385,7 @@ * error and close the association by transmitting an ABORT. */ if (!init_tag) { - sctp_chunk_t *reply = sctp_make_abort(asoc, chunk, 0); + struct sctp_chunk *reply = sctp_make_abort(asoc, chunk, 0); if (!reply) goto nomem; @@ -416,7 +415,7 @@ ntohs(err_chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); if (packet) { sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, @@ -514,18 +513,18 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; - sctp_association_t *new_asoc; + struct sctp_chunk *chunk = arg; + struct sctp_association *new_asoc; sctp_init_chunk_t *peer_init; - sctp_chunk_t *repl; + struct sctp_chunk *repl; struct sctp_ulpevent *ev; int error = 0; - sctp_chunk_t *err_chk_p; + struct sctp_chunk *err_chk_p; /* If the packet is an OOTB packet which is temporarily on the * control endpoint, respond with an ABORT. @@ -623,7 +622,7 @@ return SCTP_DISPOSITION_CONSUME; nomem_ev: - sctp_free_chunk(repl); + sctp_chunk_free(repl); nomem_repl: nomem_init: sctp_association_free(new_asoc); @@ -652,8 +651,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { @@ -697,14 +696,14 @@ } /* Generate and sendout a heartbeat packet. */ -sctp_disposition_t sctp_sf_heartbeat(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { struct sctp_transport *transport = (struct sctp_transport *) arg; - sctp_chunk_t *reply; + struct sctp_chunk *reply; sctp_sender_hb_info_t hbinfo; size_t paylen = 0; @@ -730,8 +729,8 @@ } /* Generate a HEARTBEAT packet on the given transport. */ -sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -740,7 +739,7 @@ if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_INC_STATS(SctpAborteds); SCTP_DEC_STATS(SctpCurrEstab); @@ -795,14 +794,14 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_beat_8_3(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *reply; size_t paylen = 0; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure @@ -862,13 +861,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; union sctp_addr from_addr; struct sctp_transport *link; sctp_sender_hb_info_t *hbinfo; @@ -919,14 +918,14 @@ * condition. */ static int sctp_sf_send_restart_abort(union sctp_addr *ssa, - sctp_chunk_t *init, + struct sctp_chunk *init, sctp_cmd_seq_t *commands) { int len; struct sctp_packet *pkt; sctp_addr_param_t *addrparm; sctp_errhdr_t *errhdr; - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)]; /* Build the error on the stack. We are way to malloc crazy @@ -969,9 +968,9 @@ /* A restart is occurring, check to make sure no new addresses * are being added as we may be under a takeover attack. */ -static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc, - const sctp_association_t *asoc, - sctp_chunk_t *init, +static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc, + const struct sctp_association *asoc, + struct sctp_chunk *init, sctp_cmd_seq_t *commands) { struct sctp_transport *new_addr, *addr; @@ -1022,8 +1021,8 @@ * * Note: Do not use in CLOSED or SHUTDOWN-ACK-SENT state. */ -static void sctp_tietags_populate(sctp_association_t *new_asoc, - const sctp_association_t *asoc) +static void sctp_tietags_populate(struct sctp_association *new_asoc, + const struct sctp_association *asoc) { switch (asoc->state) { @@ -1069,8 +1068,8 @@ * Returns value representing action to be taken. These action values * correspond to Action/Description values in RFC 2960, Table 2. */ -static char sctp_tietags_compare(sctp_association_t *new_asoc, - const sctp_association_t *asoc) +static char sctp_tietags_compare(struct sctp_association *new_asoc, + const struct sctp_association *asoc) { /* In this case, the peer may have restarted. */ if ((asoc->c.my_vtag != new_asoc->c.my_vtag) && @@ -1106,16 +1105,16 @@ * chunk handling. */ static sctp_disposition_t sctp_sf_do_unexpected_init( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { sctp_disposition_t retval; - sctp_chunk_t *chunk = arg; - sctp_chunk_t *repl; - sctp_association_t *new_asoc; - sctp_chunk_t *err_chunk; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *repl; + struct sctp_association *new_asoc; + struct sctp_chunk *err_chunk; struct sctp_packet *packet; sctp_unrecognized_param_t *unk_param; int len; @@ -1191,7 +1190,7 @@ * since there are no peer addresses to check against. * Upon return an ABORT will have been sent if needed. */ - if (asoc->state != SCTP_STATE_COOKIE_WAIT) { + if (!sctp_state(asoc, COOKIE_WAIT)) { if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) { retval = SCTP_DISPOSITION_CONSUME; @@ -1238,7 +1237,7 @@ * parameter type. */ sctp_addto_chunk(repl, len, unk_param); - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); } sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); @@ -1254,7 +1253,7 @@ cleanup: if (err_chunk) - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); return retval; nomem: retval = SCTP_DISPOSITION_NOMEM; @@ -1303,11 +1302,11 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_2_1_siminit(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { /* Call helper to do the real work for both simulataneous and * duplicate INIT chunk handling. @@ -1356,11 +1355,11 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { /* Call helper to do the real work for both simulataneous and * duplicate INIT chunk handling. @@ -1375,15 +1374,15 @@ * Section 5.2.4 * A) In this case, the peer may have restarted. */ -static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands, + struct sctp_association *new_asoc) { sctp_init_chunk_t *peer_init; struct sctp_ulpevent *ev; - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* new_asoc is a brand-new association, so these are not yet * side effects--it is safe to run them here. @@ -1391,7 +1390,7 @@ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, + sctp_source(chunk), peer_init, GFP_ATOMIC)) goto nomem; @@ -1429,7 +1428,7 @@ return SCTP_DISPOSITION_CONSUME; nomem_ev: - sctp_free_chunk(repl); + sctp_chunk_free(repl); nomem: return SCTP_DISPOSITION_NOMEM; } @@ -1442,22 +1441,22 @@ * after responding to the local endpoint's INIT */ /* This case represents an initialization collision. */ -static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands, + struct sctp_association *new_asoc) { sctp_init_chunk_t *peer_init; struct sctp_ulpevent *ev; - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* new_asoc is a brand-new association, so these are not yet * side effects--it is safe to run them here. */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, + sctp_source(chunk), peer_init, GFP_ATOMIC)) goto nomem; @@ -1492,7 +1491,7 @@ return SCTP_DISPOSITION_CONSUME; nomem_ev: - sctp_free_chunk(repl); + sctp_chunk_free(repl); nomem: return SCTP_DISPOSITION_NOMEM; } @@ -1506,11 +1505,11 @@ * but a new tag of its own. */ /* This case represents an initialization collision. */ -static sctp_disposition_t sctp_sf_do_dupcook_c(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_c(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands, + struct sctp_association *new_asoc) { /* The cookie should be silently discarded. * The endpoint SHOULD NOT change states and should leave @@ -1527,14 +1526,14 @@ * enter the ESTABLISHED state, if it has not already done so. */ /* This case represents an initialization collision. */ -static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands, + struct sctp_association *new_asoc) { struct sctp_ulpevent *ev = NULL; - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* Clarification from Implementor's Guide: * D) When both local and remote tags match the endpoint should @@ -1603,18 +1602,18 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { sctp_disposition_t retval; - sctp_chunk_t *chunk = arg; - sctp_association_t *new_asoc; + struct sctp_chunk *chunk = arg; + struct sctp_association *new_asoc; int error = 0; char action; - sctp_chunk_t *err_chk_p; + struct sctp_chunk *err_chk_p; /* "Decode" the chunk. We have no optional parameters so we * are in good shape. @@ -1701,13 +1700,14 @@ * * See sctp_sf_do_9_1_abort(). */ -sctp_disposition_t sctp_sf_shutdown_pending_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_shutdown_pending_abort( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; if (!sctp_vtag_verify_either(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -1724,13 +1724,13 @@ * * See sctp_sf_do_9_1_abort(). */ -sctp_disposition_t sctp_sf_shutdown_sent_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; if (!sctp_vtag_verify_either(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -1751,11 +1751,12 @@ * * See sctp_sf_do_9_1_abort(). */ -sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_shutdown_ack_sent_abort( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { /* The same T2 timer, so we should be able to use * common function with the SHUTDOWN-SENT state. @@ -1777,13 +1778,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_errhdr_t *err; err = (sctp_errhdr_t *)(chunk->skb->data); @@ -1792,7 +1793,7 @@ if (1 + asoc->counters[SCTP_COUNTER_INIT_ERROR] > asoc->max_init_attempts) { /* INIT_FAILED will issue an ulpevent. */ - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(err->cause)); return SCTP_DISPOSITION_DELETE_TCB; } @@ -1831,26 +1832,26 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; time_t stale; sctp_cookie_preserve_param_t bht; sctp_errhdr_t *err; struct list_head *pos; struct sctp_transport *t; - sctp_chunk_t *reply; - sctp_bind_addr_t *bp; + struct sctp_chunk *reply; + struct sctp_bind_addr *bp; int attempts; attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1; if (attempts >= asoc->max_init_attempts) { - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_STALE_COOKIE)); return SCTP_DISPOSITION_DELETE_TCB; } @@ -1879,7 +1880,7 @@ bht.lifespan_increment = htonl(stale); /* Build that new INIT chunk. */ - bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; + bp = (struct sctp_bind_addr *) &asoc->base.bind_addr; reply = sctp_make_init(asoc, bp, GFP_ATOMIC, sizeof(bht)); if (!reply) goto nomem; @@ -1946,20 +1947,20 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; __u16 error = SCTP_ERROR_NO_ERROR; if (!sctp_vtag_verify_either(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); if (chunk && (ntohs(chunk->chunk_hdr->length) >= - (sizeof(struct sctp_chunkhdr) + + (sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)))) error = ((sctp_errhdr_t *)chunk->skb->data)->cause; @@ -1977,13 +1978,13 @@ * * See sctp_sf_do_9_1_abort() above. */ -sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; __u16 error = SCTP_ERROR_NO_ERROR; if (!sctp_vtag_verify_either(chunk, asoc)) @@ -1996,7 +1997,7 @@ SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); if (chunk && (ntohs(chunk->chunk_hdr->length) >= - (sizeof(struct sctp_chunkhdr) + + (sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)))) error = ((sctp_errhdr_t *)chunk->skb->data)->cause; @@ -2011,8 +2012,8 @@ * * See sctp_sf_do_9_1_abort() above. */ -sctp_disposition_t sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -2056,13 +2057,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_shutdownhdr_t *sdh; sctp_disposition_t disposition; @@ -2111,14 +2112,14 @@ * that belong to this association, it should discard the INIT chunk and * retransmit the SHUTDOWN ACK chunk. */ -sctp_disposition_t sctp_sf_do_9_2_reshutack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_9_2_reshutack(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = (sctp_chunk_t *) arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = (struct sctp_chunk *) arg; + struct sctp_chunk *reply; reply = sctp_make_shutdown_ack(asoc, chunk); if (NULL == reply) @@ -2165,14 +2166,14 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_ecn_cwr(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { sctp_cwrhdr_t *cwr; - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure * that the value in the Verification Tag field of the @@ -2221,14 +2222,14 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_ecne(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { sctp_ecnehdr_t *ecne; - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure * that the value in the Verification Tag field of the @@ -2279,15 +2280,15 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_datahdr_t *data_hdr; - sctp_chunk_t *err; + struct sctp_chunk *err; size_t datalen; sctp_verb_t deliver; int tmp; @@ -2309,9 +2310,7 @@ skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); tsn = ntohl(data_hdr->tsn); - SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); - SCTP_DEBUG_PRINTK("eat_data: skb->head %p.\n", chunk->skb->head); /* ASSERT: Now skb->data is really the user data. */ @@ -2326,11 +2325,15 @@ */ if (!chunk->ecn_ce_done) { + struct sctp_af *af; chunk->ecn_ce_done = 1; - if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) && - asoc->peer.ecn_capable) { + + af = sctp_get_af_specific( + ipver2af(chunk->skb->nh.iph->version)); + + if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { /* Do real work as sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, SCTP_U32(tsn)); } } @@ -2371,7 +2374,8 @@ * PMTU. In cases, such as loopback, this might be a rather * large spill over. */ - if (asoc->rwnd_over || (datalen > asoc->rwnd + asoc->frag_point)) { + if (!asoc->rwnd || asoc->rwnd_over || + (datalen > asoc->rwnd + asoc->frag_point)) { /* If this is the next TSN, consider reneging to make * room. Note: Playing nice with a confused sender. A @@ -2409,7 +2413,7 @@ * processing the rest of the chunks in the packet. */ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_DATA)); SCTP_INC_STATS(SctpAborteds); SCTP_DEC_STATS(SctpCurrEstab); @@ -2537,15 +2541,15 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_datahdr_t *data_hdr; - sctp_chunk_t *err; + struct sctp_chunk *err; size_t datalen; int tmp; __u32 tsn; @@ -2581,11 +2585,15 @@ * chunk later. */ if (!chunk->ecn_ce_done) { + struct sctp_af *af; chunk->ecn_ce_done = 1; - if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) && - asoc->peer.ecn_capable) { + + af = sctp_get_af_specific( + ipver2af(chunk->skb->nh.iph->version)); + + if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { /* Do real work as sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, SCTP_U32(tsn)); } } @@ -2625,7 +2633,7 @@ * processing the rest of the chunks in the packet. */ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_DATA)); SCTP_INC_STATS(SctpAborteds); SCTP_DEC_STATS(SctpCurrEstab); @@ -2712,13 +2720,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_sackhdr_t *sackh; __u32 ctsn; @@ -2773,15 +2781,15 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { struct sctp_packet *packet = NULL; - sctp_chunk_t *chunk = arg; - sctp_chunk_t *abort; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *abort; packet = sctp_ootb_pkt_new(asoc, chunk); @@ -2819,13 +2827,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; struct sctp_ulpevent *ev; while (chunk->chunk_end > chunk->skb->data) { @@ -2856,14 +2864,14 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *reply; struct sctp_ulpevent *ev; /* 10.2 H) SHUTDOWN COMPLETE notification @@ -2924,13 +2932,13 @@ * TCB was found. After sending this ABORT, the receiver of the OOTB * packet shall discard the OOTB packet and take no further action. */ -sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; struct sk_buff *skb = chunk->skb; sctp_chunkhdr_t *ch; __u8 *ch_end; @@ -2975,15 +2983,15 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { struct sctp_packet *packet = NULL; - sctp_chunk_t *chunk = arg; - sctp_chunk_t *shut; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *shut; packet = sctp_ootb_pkt_new(asoc, chunk); @@ -3024,8 +3032,8 @@ * chunks. --piggy ] * */ -sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3061,14 +3069,14 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_unk_chunk(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *unk_chunk = arg; - sctp_chunk_t *err_chunk; + struct sctp_chunk *unk_chunk = arg; + struct sctp_chunk *err_chunk; sctp_chunkhdr_t *hdr; SCTP_DEBUG_PRINTK("Processing the unknown chunk id %d.\n", type.chunk); @@ -3140,8 +3148,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3169,8 +3177,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_pdiscard(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_pdiscard(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3198,13 +3206,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t lucky(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t lucky(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure * that the value in the Verification Tag field of the @@ -3235,13 +3243,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t other_stupid(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t other_stupid(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure * that the value in the Verification Tag field of the @@ -3271,8 +3279,8 @@ * We simply tag the chunk as a violation. The state machine will log * the violation and continue. */ -sctp_disposition_t sctp_sf_violation(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3309,7 +3317,7 @@ * will be returned on successful establishment of the association. If * SCTP is not able to open an SCTP association with the peer endpoint, * an error is returned. - * [In the kernel implementation, the sctp_association_t needs to + * [In the kernel implementation, the struct sctp_association needs to * be created BEFORE causing this primitive to run.] * * Other association parameters may be returned, including the @@ -3340,13 +3348,13 @@ * * The return value is a disposition. */ -sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_prm_asoc(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* The comment below says that we enter COOKIE-WAIT AFTER * sending the INIT, but that doesn't actually work in our @@ -3371,7 +3379,7 @@ * rerun it through as a sideffect. */ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, - SCTP_ASOC((sctp_association_t *) asoc)); + SCTP_ASOC((struct sctp_association *) asoc)); /* After sending the INIT, "A" starts the T1-init timer and * enters the COOKIE-WAIT state. @@ -3446,13 +3454,13 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_prm_send(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_prm_send(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk)); return SCTP_DISPOSITION_CONSUME; @@ -3484,11 +3492,12 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_9_2_prm_shutdown( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { int disposition; @@ -3545,11 +3554,12 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_9_1_prm_abort( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { /* From 9.1 Abort of an Association * Upon receipt of the ABORT primitive from its upper @@ -3560,7 +3570,7 @@ * if necessary to fill gaps. */ struct msghdr *msg = arg; - sctp_chunk_t *abort; + struct sctp_chunk *abort; sctp_disposition_t retval; retval = SCTP_DISPOSITION_CONSUME; @@ -3577,7 +3587,7 @@ */ /* Delete the established association. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_USER_ABORT)); SCTP_INC_STATS(SctpAborteds); @@ -3587,8 +3597,8 @@ } /* We tried an illegal operation on an association which is closed. */ -sctp_disposition_t sctp_sf_error_closed(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_error_closed(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3600,8 +3610,8 @@ /* We tried an illegal operation on an association which is shutting * down. */ -sctp_disposition_t sctp_sf_error_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_error_shutdown(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3626,8 +3636,8 @@ * (timers) */ sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3660,8 +3670,8 @@ * (timers) */ sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { @@ -3685,14 +3695,15 @@ * Outputs * (timers) */ -sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_wait_prm_abort( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { struct msghdr *msg = arg; - sctp_chunk_t *abort; + struct sctp_chunk *abort; sctp_disposition_t retval; /* Stop T1-init timer */ @@ -3717,7 +3728,7 @@ */ /* Delete the established association. */ - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_USER_ABORT)); return retval; @@ -3737,11 +3748,12 @@ * Outputs * (timers) */ -sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_echoed_prm_abort( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { /* There is a single T1 timer, so we should be able to use * common function with the COOKIE-WAIT state. @@ -3762,8 +3774,8 @@ * (timers) */ sctp_disposition_t sctp_sf_shutdown_pending_prm_abort( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3788,8 +3800,8 @@ * (timers) */ sctp_disposition_t sctp_sf_shutdown_sent_prm_abort( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3818,8 +3830,8 @@ * (timers) */ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3853,8 +3865,8 @@ * association on which a heartbeat should be issued. */ sctp_disposition_t sctp_sf_do_prm_requestheartbeat( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3868,11 +3880,12 @@ * * The return value is the disposition of the primitive. */ -sctp_disposition_t sctp_sf_ignore_primitive(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_ignore_primitive( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { SCTP_DEBUG_PRINTK("Primitive type %d is ignored.\n", type.primitive); return SCTP_DISPOSITION_DISCARD; @@ -3895,13 +3908,14 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_9_2_start_shutdown( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *reply; + struct sctp_chunk *reply; /* Once all its outstanding data has been acknowledged, the * endpoint shall send a SHUTDOWN chunk to its peer including @@ -3956,14 +3970,15 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_9_2_shutdown_ack( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = (sctp_chunk_t *) arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = (struct sctp_chunk *) arg; + struct sctp_chunk *reply; /* If it has no more outstanding DATA chunks, the SHUTDOWN receiver * shall send a SHUTDOWN ACK ... @@ -4009,8 +4024,8 @@ * * The return value is the disposition of the event. */ -sctp_disposition_t sctp_sf_ignore_other(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_ignore_other(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4034,8 +4049,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4044,7 +4059,7 @@ if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_INC_STATS(SctpAborteds); SCTP_DEC_STATS(SctpCurrEstab); @@ -4102,8 +4117,8 @@ * allow. However, an SCTP transmitter MUST NOT be more aggressive than * the following algorithms allow. */ -sctp_disposition_t sctp_sf_do_6_2_sack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_6_2_sack(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4137,14 +4152,14 @@ * (timers, events) * */ -sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_t1_timer_expire(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *repl; - sctp_bind_addr_t *bp; + struct sctp_chunk *repl; + struct sctp_bind_addr *bp; sctp_event_timeout_t timer = (sctp_event_timeout_t) arg; int timeout; int attempts; @@ -4159,7 +4174,7 @@ (attempts < asoc->max_init_attempts)) { switch (timer) { case SCTP_EVENT_TIMEOUT_T1_INIT: - bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; + bp = (struct sctp_bind_addr *) &asoc->base.bind_addr; repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0); break; @@ -4180,7 +4195,7 @@ SCTP_TO(timer)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); } else { - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); return SCTP_DISPOSITION_DELETE_TCB; } @@ -4204,18 +4219,18 @@ * the T2-Shutdown timer, giving its peer ample opportunity to transmit * all of its queued DATA chunks that have not yet been sent. */ -sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *reply = NULL; + struct sctp_chunk *reply = NULL; SCTP_DEBUG_PRINTK("Timer T2 expired.\n"); if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_INC_STATS(SctpAborteds); SCTP_DEC_STATS(SctpCurrEstab); @@ -4264,13 +4279,13 @@ * At the expiration of this timer the sender SHOULD abort the association * by sending an ABORT chunk. */ -sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_t5_timer_expire(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *reply = NULL; + struct sctp_chunk *reply = NULL; SCTP_DEBUG_PRINTK("Timer T5 expired.\n"); @@ -4279,7 +4294,7 @@ goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); return SCTP_DISPOSITION_DELETE_TCB; @@ -4292,11 +4307,12 @@ * The work that needs to be done is same as when SHUTDOWN is initiated by * the user. So this routine looks same as sctp_sf_do_9_2_prm_shutdown(). */ -sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_autoclose_timer_expire( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { int disposition; @@ -4337,8 +4353,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_not_impl(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_not_impl(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4354,8 +4370,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_bug(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_bug(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4374,8 +4390,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_timer_ignore(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_timer_ignore(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4389,7 +4405,7 @@ ********************************************************************/ /* Pull the SACK chunk based on the SACK header. */ -sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk) +sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *chunk) { sctp_sackhdr_t *sack; __u16 num_blocks; @@ -4411,14 +4427,14 @@ /* Create an ABORT packet to be sent as a response, with the specified * error causes. */ -struct sctp_packet *sctp_abort_pkt_new(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, +struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, const void *payload, size_t paylen) { struct sctp_packet *packet; - sctp_chunk_t *abort; + struct sctp_chunk *abort; packet = sctp_ootb_pkt_new(asoc, chunk); @@ -4447,8 +4463,8 @@ } /* Allocate a packet for responding in the OOTB conditions. */ -struct sctp_packet *sctp_ootb_pkt_new(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { struct sctp_packet *packet; struct sctp_transport *transport; @@ -4512,11 +4528,11 @@ } /* Send a stale cookie error when a invalid COOKIE ECHO chunk is found */ -void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, sctp_cmd_seq_t *commands, - sctp_chunk_t *err_chunk) + struct sctp_chunk *err_chunk) { struct sctp_packet *packet; @@ -4530,6 +4546,6 @@ SCTP_PACKET(packet)); SCTP_INC_STATS(SctpOutCtrlChunks); } else - sctp_free_chunk (err_chunk); + sctp_chunk_free (err_chunk); } } diff -urN linux-2.5.69-bk3/net/sctp/socket.c linux-2.5.69-bk4/net/sctp/socket.c --- linux-2.5.69-bk3/net/sctp/socket.c 2003-05-04 16:53:57.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/socket.c 2003-05-09 04:41:39.000000000 -0700 @@ -55,7 +55,6 @@ #include #include -#include #include #include #include @@ -63,6 +62,7 @@ #include #include #include +#include #include #include @@ -82,13 +82,14 @@ /* Forward declarations for internal helper functions. */ static int sctp_writeable(struct sock *sk); static inline int sctp_wspace(struct sctp_association *asoc); -static inline void sctp_set_owner_w(sctp_chunk_t *chunk); +static inline void sctp_set_owner_w(struct sctp_chunk *chunk); static void sctp_wfree(struct sk_buff *skb); static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, int msg_len); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); static int sctp_wait_for_accept(struct sock *sk, long timeo); +static void sctp_wait_for_close(struct sock *sk, long timeo); static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); @@ -96,31 +97,33 @@ static int sctp_autobind(struct sock *sk); static void sctp_sock_migrate(struct sock *, struct sock *, struct sctp_association *, sctp_socket_type_t); +static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; /* Look up the association by its id. If this is not a UDP-style * socket, the ID field is always ignored. */ -sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) +struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) { - sctp_association_t *asoc = NULL; + struct sctp_association *asoc = NULL; - /* If this is not a UDP-style socket, assoc id should be + /* If this is not a UDP-style socket, assoc id should be * ignored. */ - if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { + if (!sctp_style(sk, UDP)) { if (!list_empty(&sctp_sk(sk)->ep->asocs)) asoc = list_entry(sctp_sk(sk)->ep->asocs.next, - sctp_association_t, asocs); + struct sctp_association, asocs); return asoc; } /* First, verify that this is a kernel address. */ if (sctp_is_valid_kaddr((unsigned long) id)) { - sctp_association_t *temp = (sctp_association_t *) id; + struct sctp_association *temp; - /* Verify that this _is_ an sctp_association_t + /* Verify that this _is_ an sctp_association * data structure and if so, that the socket matches. */ + temp = (struct sctp_association *)id; if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) && (temp->base.sk == sk)) asoc = temp; @@ -188,13 +191,12 @@ return af; } - /* Bind a local address either to an endpoint or to an association. */ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) { struct sctp_opt *sp = sctp_sk(sk); - sctp_endpoint_t *ep = sp->ep; - sctp_bind_addr_t *bp = &ep->base.bind_addr; + struct sctp_endpoint *ep = sp->ep; + struct sctp_bind_addr *bp = &ep->base.bind_addr; struct sctp_af *af; unsigned short snum; int ret = 0; @@ -260,7 +262,7 @@ /* Copy back into socket for getsockname() use. */ if (!ret) { inet_sk(sk)->sport = htons(inet_sk(sk)->num); - af->to_sk(addr, sk); + af->to_sk_saddr(addr, sk); } return ret; @@ -450,12 +452,12 @@ /* Add these addresses to all associations on this endpoint. */ if (retval >= 0) { struct list_head *pos; - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; ep = sctp_sk(sk)->ep; list_for_each(pos, &ep->asocs) { - asoc = list_entry(pos, sctp_association_t, asocs); + asoc = list_entry(pos, struct sctp_association, asocs); sctp_addip_addr_config(asoc, SCTP_PARAM_ADD_IP, @@ -485,9 +487,9 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) { struct sctp_opt *sp = sctp_sk(sk); - sctp_endpoint_t *ep = sp->ep; + struct sctp_endpoint *ep = sp->ep; int cnt; - sctp_bind_addr_t *bp = &ep->base.bind_addr; + struct sctp_bind_addr *bp = &ep->base.bind_addr; int retval = 0; union sctp_addr saveaddr; @@ -570,12 +572,12 @@ /* Remove these addresses from all associations on this endpoint. */ if (retval >= 0) { struct list_head *pos; - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; ep = sctp_sk(sk)->ep; list_for_each(pos, &ep->asocs) { - asoc = list_entry(pos, sctp_association_t, asocs); + asoc = list_entry(pos, struct sctp_association, asocs); sctp_addip_addr_config(asoc, SCTP_PARAM_DEL_IP, addrs, addrcnt); } @@ -637,7 +639,7 @@ /* Alloc space for the address array in kernel memory. */ kaddrs = (struct sockaddr_storage *) kmalloc(addrssize, GFP_KERNEL); - if (unlikely(NULL == kaddrs)) + if (unlikely(!kaddrs)) return -ENOMEM; if (copy_from_user(kaddrs, addrs, addrssize)) { @@ -670,14 +672,45 @@ * * If sd in the close() call is a branched-off socket representing only * one association, the shutdown is performed on that association only. + * + * 4.1.6 close() - TCP Style Syntax + * + * Applications use close() to gracefully close down an association. + * + * The syntax is: + * + * int close(int sd); + * + * sd - the socket descriptor of the association to be closed. + * + * After an application calls close() on a socket descriptor, no further + * socket operations will succeed on that descriptor. + * + * API 7.1.4 SO_LINGER + * + * An application using the TCP-style socket can use this option to + * perform the SCTP ABORT primitive. The linger option structure is: + * + * struct linger { + * int l_onoff; // option on/off + * int l_linger; // linger time + * }; + * + * To enable the option, set l_onoff to 1. If the l_linger value is set + * to 0, calling close() is the same as the ABORT primitive. If the + * value is set to a negative value, the setsockopt() call will return + * an error. If the value is set to a positive value linger_time, the + * close() can be blocked for at most linger_time ms. If the graceful + * shutdown phase does not finish during this period, close() will + * return but the graceful shutdown phase continues in the system. */ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) { - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; struct list_head *pos, *temp; - SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p...)\n", sk); + printk("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout); sctp_lock_sock(sk); sk->shutdown = SHUTDOWN_MASK; @@ -686,14 +719,35 @@ /* Walk all associations on a socket, not on an endpoint. */ list_for_each_safe(pos, temp, &ep->asocs) { - asoc = list_entry(pos, sctp_association_t, asocs); - sctp_primitive_SHUTDOWN(asoc, NULL); + asoc = list_entry(pos, struct sctp_association, asocs); + + if (sctp_style(sk, TCP)) { + /* A closed association can still be in the list if + * it belongs to a TCP-style listening socket that is + * not yet accepted. If so, free it. If not, send an + * ABORT or SHUTDOWN based on the linger options. + */ + if (sctp_state(asoc, CLOSED)) { + sctp_unhash_established(asoc); + sctp_association_free(asoc); + + } else if (test_bit(SOCK_LINGER, &sk->flags) && + !sk->lingertime) + sctp_primitive_ABORT(asoc, NULL); + else + sctp_primitive_SHUTDOWN(asoc, NULL); + } else + sctp_primitive_SHUTDOWN(asoc, NULL); } /* Clean up any skbs sitting on the receive queue. */ skb_queue_purge(&sk->receive_queue); skb_queue_purge(&sctp_sk(sk)->pd_lobby); + /* On a TCP-style socket, block for at most linger_time if set. */ + if (sctp_style(sk, TCP) && timeout) + sctp_wait_for_close(sk, timeout); + /* This will run the backlog queue. */ sctp_release_sock(sk); @@ -717,6 +771,16 @@ SCTP_DBG_OBJCNT_DEC(sock); } +/* Handle EPIPE error. */ +static int sctp_error(struct sock *sk, int flags, int err) +{ + if (err == -EPIPE) + err = sock_error(sk) ? : -EPIPE; + if (err == -EPIPE && !(flags & MSG_NOSIGNAL)) + send_sig(SIGPIPE, current, 0); + return err; +} + /* API 3.1.3 sendmsg() - UDP Style Syntax * * An application uses sendmsg() and recvmsg() calls to transmit data to @@ -746,10 +810,10 @@ struct msghdr *msg, int msg_len) { struct sctp_opt *sp; - sctp_endpoint_t *ep; - sctp_association_t *new_asoc=NULL, *asoc=NULL; - struct sctp_transport *transport; - sctp_chunk_t *chunk = NULL; + struct sctp_endpoint *ep; + struct sctp_association *new_asoc=NULL, *asoc=NULL; + struct sctp_transport *transport, *chunk_tp; + struct sctp_chunk *chunk; union sctp_addr to; struct sockaddr *msg_name = NULL; struct sctp_sndrcvinfo default_sinfo = { 0 }; @@ -761,7 +825,9 @@ sctp_scope_t scope; long timeo; __u16 sinfo_flags = 0; - struct sk_buff_head chunks; + struct sctp_datamsg *datamsg; + struct list_head *pos; + int msg_flags = msg->msg_flags; SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n", sk, msg, msg_len); @@ -772,6 +838,12 @@ SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name); + /* We cannot send a message over a TCP-style listening socket. */ + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) { + err = -EPIPE; + goto out_nounlock; + } + /* Parse out the SCTP CMSGs. */ err = sctp_msghdr_parse(msg, &cmsgs); @@ -785,7 +857,7 @@ * the address we will send to. * For a peeled-off socket, msg_name is ignored. */ - if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) { + if (!sctp_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) { int msg_namelen = msg->msg_namelen; err = sctp_verify_addr(sk, (union sctp_addr *)msg->msg_name, @@ -816,6 +888,12 @@ SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n", msg_len, sinfo_flags); + /* MSG_EOF or MSG_ABORT cannot be set on a TCP-style socket. */ + if (sctp_style(sk, TCP) && (sinfo_flags & (MSG_EOF | MSG_ABORT))) { + err = -EINVAL; + goto out_nounlock; + } + /* If MSG_EOF is set, no data can be sent. Disallow sending zero * length messages when MSG_EOF|MSG_ABORT is not set. * If MSG_ABORT is set, the message length could be non zero with @@ -827,22 +905,33 @@ goto out_nounlock; } - sctp_lock_sock(sk); + /* If MSG_ADDR_OVER is set, there must be an address + * specified in msg_name. + */ + if ((sinfo_flags & MSG_ADDR_OVER) && (!msg->msg_name)) { + err = -EINVAL; + goto out_nounlock; + } transport = NULL; SCTP_DEBUG_PRINTK("About to look up association.\n"); + sctp_lock_sock(sk); + /* If a msg_name has been specified, assume this is to be used. */ if (msg_name) { /* Look for a matching association on the endpoint. */ asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); if (!asoc) { /* If we could not find a matching association on the - * endpoint, make sure that there is no peeled-off - * association on another socket. + * endpoint, make sure that it is not a TCP-style + * socket that already has an association or there is + * no peeled-off association on another socket. */ - if (sctp_endpoint_is_peeled_off(ep, &to)) { + if ((sctp_style(sk, TCP) && + sctp_sstate(sk, ESTABLISHED)) || + sctp_endpoint_is_peeled_off(ep, &to)) { err = -EADDRNOTAVAIL; goto out_unlock; } @@ -850,14 +939,24 @@ } else { asoc = sctp_id2assoc(sk, associd); if (!asoc) { - err = -EINVAL; + err = -EPIPE; goto out_unlock; } } if (asoc) { - SCTP_DEBUG_PRINTK("Just looked up association: " - "%s. \n", asoc->debug_name); + SCTP_DEBUG_PRINTK("Just looked up association: %p.\n", asoc); + + /* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED + * socket that has an association in CLOSED state. This can + * happen when an accepted socket has an association that is + * already CLOSED. + */ + if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP)) { + err = -EPIPE; + goto out_unlock; + } + if (sinfo_flags & MSG_EOF) { SCTP_DEBUG_PRINTK("Shutting down association: %p\n", asoc); @@ -1004,69 +1103,76 @@ goto out_free; } - /* Break the message into multiple chunks of maximum size. */ - skb_queue_head_init(&chunks); - err = sctp_datachunks_from_user(asoc, sinfo, msg, msg_len, &chunks); - if (err) - goto out_free; + /* If an address is passed with the sendto/sendmsg call, it is used + * to override the primary destination address in the TCP model, or + * when MSG_ADDR_OVER flag is set in the UDP model. + */ + if ((sctp_style(sk, TCP) && msg_name) || + (sinfo_flags & MSG_ADDR_OVER)) { + chunk_tp = sctp_assoc_lookup_paddr(asoc, &to); + if (!chunk_tp) { + err = -EINVAL; + goto out_free; + } + } else + chunk_tp = NULL; /* Auto-connect, if we aren't connected already. */ - if (SCTP_STATE_CLOSED == asoc->state) { + if (sctp_state(asoc, CLOSED)) { err = sctp_primitive_ASSOCIATE(asoc, NULL); if (err < 0) goto out_free; SCTP_DEBUG_PRINTK("We associated primitively.\n"); } + /* Break the message into multiple chunks of maximum size. */ + datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len); + if (!datamsg) { + err = -ENOMEM; + goto out_free; + } + /* Now send the (possibly) fragmented message. */ - while ((chunk = (sctp_chunk_t *)__skb_dequeue(&chunks))) { + list_for_each(pos, &datamsg->chunks) { + chunk = list_entry(pos, struct sctp_chunk, frag_list); + sctp_datamsg_track(chunk); /* Do accounting for the write space. */ sctp_set_owner_w(chunk); - /* This flag, in the UDP model, requests the SCTP stack to - * override the primary destination address with the - * address found with the sendto/sendmsg call. - */ - if (sinfo_flags & MSG_ADDR_OVER) { - if (!msg->msg_name) { - err = -EINVAL; - goto out_free; - } - chunk->transport = sctp_assoc_lookup_paddr(asoc, &to); - if (!chunk->transport) { - err = -EINVAL; - goto out_free; - } - } + chunk->transport = chunk_tp; - /* Send it to the lower layers. */ - sctp_primitive_SEND(asoc, chunk); + /* Send it to the lower layers. Note: all chunks + * must either fail or succeed. The lower layer + * works that way today. Keep it that way or this + * breaks. + */ + err = sctp_primitive_SEND(asoc, chunk); + /* Did the lower layer accept the chunk? */ + if (err) + sctp_chunk_free(chunk); SCTP_DEBUG_PRINTK("We sent primitively.\n"); } - if (!err) { + sctp_datamsg_free(datamsg); + if (err) + goto out_free; + else err = msg_len; - goto out_unlock; - } + /* If we are already past ASSOCIATE, the lower * layers are responsible for association cleanup. */ - goto out_free_chunk; + goto out_unlock; out_free: if (new_asoc) sctp_association_free(asoc); - -out_free_chunk: - if (chunk) - sctp_free_chunk(chunk); - out_unlock: sctp_release_sock(sk); out_nounlock: - return err; + return sctp_error(sk, msg_flags, err); #if 0 do_sock_err: @@ -1134,8 +1240,9 @@ */ static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); -SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - int len, int noblock, int flags, int *addr_len) +SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, int len, int noblock, + int flags, int *addr_len) { struct sctp_ulpevent *event = NULL; struct sctp_opt *sp = sctp_sk(sk); @@ -1151,12 +1258,11 @@ sctp_lock_sock(sk); - if ((SCTP_SOCKET_TCP == sp->type) && - (SCTP_SS_ESTABLISHED != sk->state)) { + if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) { err = -ENOTCONN; goto out; } - + skb = sctp_skb_recv_datagram(sk, flags, noblock, &err); if (!skb) goto out; @@ -1259,7 +1365,7 @@ struct sctp_opt *sp = sctp_sk(sk); /* Applicable to UDP-style socket only */ - if (SCTP_SOCKET_TCP == sp->type) + if (sctp_style(sk, TCP)) return -EOPNOTSUPP; if (optlen != sizeof(int)) return -EINVAL; @@ -1271,10 +1377,10 @@ } static int sctp_setsockopt_peer_addr_params(struct sock *sk, - char *optval, int optlen) + char *optval, int optlen) { struct sctp_paddrparams params; - sctp_association_t *asoc; + struct sctp_association *asoc; union sctp_addr *addr; struct sctp_transport *trans; int error; @@ -1329,8 +1435,7 @@ return 0; } -static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, - int optlen) +static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen) { if (optlen != sizeof(struct sctp_initmsg)) return -EINVAL; @@ -1340,7 +1445,6 @@ } /* - * * 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM) * * Applications that wish to use the sendto() system call may wish to @@ -1358,7 +1462,7 @@ char *optval, int optlen) { struct sctp_sndrcvinfo info; - sctp_association_t *asoc; + struct sctp_association *asoc; if (optlen != sizeof(struct sctp_sndrcvinfo)) return -EINVAL; @@ -1413,7 +1517,6 @@ } /* - * * 7.1.5 SCTP_NODELAY * * Turn on/off any Nagle-like algorithm. This means that packets are @@ -1424,15 +1527,61 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char *optval, int optlen) { - __u8 val; + int val; - if (optlen < sizeof(__u8)) + if (optlen < sizeof(int)) return -EINVAL; - - if (get_user(val, (__u8 *)optval)) + if (get_user(val, (int *)optval)) return -EFAULT; sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1; + return 0; +} + +/* + * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) + * + * This socket option is a boolean flag which turns on or off mapped V4 + * addresses. If this option is turned on and the socket is type + * PF_INET6, then IPv4 addresses will be mapped to V6 representation. + * If this option is turned off, then no mapping will be done of V4 + * addresses and a user will receive both PF_INET6 and PF_INET type + * addresses on the socket. + */ +static int sctp_setsockopt_mappedv4(struct sock *sk, char *optval, int optlen) +{ + int val; + + if (optlen < sizeof(int)) + return -EINVAL; + if (get_user(val, (int *)optval)) + return -EFAULT; + /* FIXME: Put real support here. */ + + return -ENOPROTOOPT; +} + +/* + * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) + * + * This socket option specifies the maximum size to put in any outgoing + * SCTP chunk. If a message is larger than this size it will be + * fragmented by SCTP into the specified size. Note that the underlying + * SCTP implementation may fragment into smaller sized chunks when the + * PMTU of the underlying association is smaller than the value set by + * the user. + */ +static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen) +{ + int val; + + if (optlen < sizeof(int)) + return -EINVAL; + if (get_user(val, (int *)optval)) + return -EFAULT; + if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)) + return -EINVAL; + sctp_sk(sk)->user_frag = val; return 0; } @@ -1526,20 +1675,22 @@ case SCTP_INITMSG: retval = sctp_setsockopt_initmsg(sk, optval, optlen); break; - case SCTP_SET_DEFAULT_SEND_PARAM: retval = sctp_setsockopt_default_send_param(sk, optval, optlen); break; - case SCTP_SET_PEER_PRIMARY_ADDR: retval = sctp_setsockopt_peer_prim(sk, optval, optlen); break; - case SCTP_NODELAY: retval = sctp_setsockopt_nodelay(sk, optval, optlen); break; - + case SCTP_I_WANT_MAPPED_V4_ADDR: + retval = sctp_setsockopt_mappedv4(sk, optval, optlen); + break; + case SCTP_MAXSEG: + retval = sctp_setsockopt_maxseg(sk, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -1572,10 +1723,11 @@ int addr_len) { struct sctp_opt *sp; - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; struct sctp_transport *transport; union sctp_addr to; + struct sctp_af *af; sctp_scope_t scope; long timeo; int err = 0; @@ -1590,12 +1742,11 @@ /* connect() cannot be done on a socket that is already in ESTABLISHED * state - UDP-style peeled off socket or a TCP-style socket that - * is already connected. + * is already connected. * It cannot be done even on a TCP-style listening socket. */ - if ((SCTP_SS_ESTABLISHED == sk->state) || - ((SCTP_SOCKET_TCP == sp->type) && - (SCTP_SS_LISTENING == sk->state))) { + if (sctp_sstate(sk, ESTABLISHED) || + (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) { err = -EISCONN; goto out_unlock; } @@ -1663,6 +1814,11 @@ goto out_unlock; } + /* Initialize sk's dport and daddr for getpeername() */ + inet_sk(sk)->dport = htons(asoc->peer.port); + af = sctp_get_af_specific(to.sa.sa_family); + af->to_sk_daddr(&to, sk); + timeo = sock_sndtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK); err = sctp_wait_for_connect(asoc, &timeo); @@ -1690,21 +1846,21 @@ struct sctp_opt *sp; struct sctp_endpoint *ep; struct sock *newsk = NULL; - struct sctp_association *assoc; + struct sctp_association *asoc; long timeo; int error = 0; - + sctp_lock_sock(sk); sp = sctp_sk(sk); ep = sp->ep; - if (SCTP_SOCKET_TCP != sp->type) { + if (!sctp_style(sk, TCP)) { error = -EOPNOTSUPP; goto out; } - if (SCTP_SS_LISTENING != sk->state) { + if (!sctp_sstate(sk, LISTENING)) { error = -EINVAL; goto out; } @@ -1715,21 +1871,21 @@ if (error) goto out; - /* We treat the list of associations on the endpoint as the accept - * queue and pick the first association on the list. + /* We treat the list of associations on the endpoint as the accept + * queue and pick the first association on the list. */ - assoc = list_entry(ep->asocs.next, struct sctp_association, asocs); + asoc = list_entry(ep->asocs.next, struct sctp_association, asocs); - newsk = sp->pf->create_accept_sk(sk, assoc); + newsk = sp->pf->create_accept_sk(sk, asoc); if (!newsk) { error = -ENOMEM; goto out; } /* Populate the fields of the newsk from the oldsk and migrate the - * assoc to the newsk. - */ - sctp_sock_migrate(sk, newsk, assoc, SCTP_SOCKET_TCP); + * asoc to the newsk. + */ + sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP); out: sctp_release_sock(sk); @@ -1737,10 +1893,10 @@ return newsk; } -/* FIXME: Write Comments. */ +/* The SCTP ioctl handler. */ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) { - return -EOPNOTSUPP; /* STUB */ + return -ENOIOCTLCMD; } /* This is the function which gets called during socket creation to @@ -1749,7 +1905,7 @@ */ SCTP_STATIC int sctp_init_sock(struct sock *sk) { - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; struct sctp_protocol *proto; struct sctp_opt *sp; @@ -1800,7 +1956,7 @@ * enable the events needed. By default, UDP-style * sockets enable io and association change notifications. */ - if (SCTP_SOCKET_UDP == sp->type) { + if (sctp_style(sk, UDP)) { sp->subscribe.sctp_data_io_event = 1; sp->subscribe.sctp_association_event = 1; } @@ -1819,12 +1975,19 @@ /* Turn on/off any Nagle-like algorithm. */ sp->nodelay = 1; + /* Enable by default. */ + sp->v4mapped = 1; + /* Auto-close idle associations after the configured * number of seconds. A value of 0 disables this * feature. Configure through the SCTP_AUTOCLOSE socket option, * for UDP-style sockets only. */ sp->autoclose = 0; + + /* User specified fragmentation limit. */ + sp->user_frag = 0; + sp->pf = sctp_get_pf_specific(sk->family); /* Control variables for partial data delivery. */ @@ -1835,11 +1998,12 @@ * change the data structure relationships, this may still * be useful for storing pre-connect address information. */ - ep = sctp_endpoint_new(proto, sk, GFP_KERNEL); - if (NULL == ep) + ep = sctp_endpoint_new(sk, GFP_KERNEL); + if (!ep) return -ENOMEM; sp->ep = ep; + sp->hmac = NULL; SCTP_DBG_OBJCNT_INC(sock); return 0; @@ -1848,7 +2012,7 @@ /* Cleanup any SCTP per socket resources. */ SCTP_STATIC int sctp_destroy_sock(struct sock *sk) { - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); @@ -1859,11 +2023,38 @@ return 0; } -/* FIXME: Comments needed. */ +/* API 4.1.7 shutdown() - TCP Style Syntax + * int shutdown(int socket, int how); + * + * sd - the socket descriptor of the association to be closed. + * how - Specifies the type of shutdown. The values are + * as follows: + * SHUT_RD + * Disables further receive operations. No SCTP + * protocol action is taken. + * SHUT_WR + * Disables further send operations, and initiates + * the SCTP shutdown sequence. + * SHUT_RDWR + * Disables further send and receive operations + * and initiates the SCTP shutdown sequence. + */ SCTP_STATIC void sctp_shutdown(struct sock *sk, int how) { - /* UDP-style sockets do not support shutdown. */ - /* STUB */ + struct sctp_endpoint *ep; + struct sctp_association *asoc; + + if (!sctp_style(sk, TCP)) + return; + + if (how & SEND_SHUTDOWN) { + ep = sctp_sk(sk)->ep; + if (!list_empty(&ep->asocs)) { + asoc = list_entry(ep->asocs.next, + struct sctp_association, asocs); + sctp_primitive_SHUTDOWN(asoc, NULL); + } + } } /* 7.2.1 Association Status (SCTP_STATUS) @@ -1877,7 +2068,7 @@ int *optlen) { struct sctp_status status; - sctp_association_t *assoc = NULL; + struct sctp_association *asoc = NULL; struct sctp_transport *transport; sctp_assoc_t associd; int retval = 0; @@ -1893,22 +2084,26 @@ } associd = status.sstat_assoc_id; - assoc = sctp_id2assoc(sk, associd); - if (!assoc) { + asoc = sctp_id2assoc(sk, associd); + if (!asoc) { retval = -EINVAL; goto out; } - transport = assoc->peer.primary_path; + transport = asoc->peer.primary_path; - status.sstat_assoc_id = sctp_assoc2id(assoc); - status.sstat_state = assoc->state; - status.sstat_rwnd = assoc->peer.rwnd; - status.sstat_unackdata = assoc->unack_data; - status.sstat_penddata = assoc->peer.tsn_map.pending_data; - status.sstat_instrms = assoc->c.sinit_max_instreams; - status.sstat_outstrms = assoc->c.sinit_num_ostreams; - status.sstat_fragmentation_point = assoc->frag_point; + status.sstat_assoc_id = sctp_assoc2id(asoc); + status.sstat_state = asoc->state; + status.sstat_rwnd = asoc->peer.rwnd; + status.sstat_unackdata = asoc->unack_data; + status.sstat_penddata = asoc->peer.tsn_map.pending_data; + status.sstat_instrms = asoc->c.sinit_max_instreams; + status.sstat_outstrms = asoc->c.sinit_num_ostreams; + /* Just in time frag_point update. */ + if (sctp_sk(sk)->user_frag) + asoc->frag_point + = min_t(int, asoc->frag_point, sctp_sk(sk)->user_frag); + status.sstat_fragmentation_point = asoc->frag_point; status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); memcpy(&status.sstat_primary.spinfo_address, &(transport->ipaddr), sizeof(union sctp_addr)); @@ -1965,7 +2160,7 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) { /* Applicable to UDP-style socket only */ - if (SCTP_SOCKET_TCP == sctp_sk(sk)->type) + if (sctp_style(sk, TCP)) return -EOPNOTSUPP; if (len != sizeof(int)) return -EINVAL; @@ -1975,33 +2170,29 @@ } /* Helper routine to branch off an association to a new socket. */ -SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) +SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, + struct socket **sockp) { - struct sock *oldsk = assoc->base.sk; - struct sock *newsk; - struct socket *tmpsock; + struct sock *sk = asoc->base.sk; + struct socket *sock; int err = 0; /* An association cannot be branched off from an already peeled-off * socket, nor is this supported for tcp style sockets. */ - if (SCTP_SOCKET_UDP != sctp_sk(oldsk)->type) - return -EOPNOTSUPP; + if (!sctp_style(sk, UDP)) + return -EINVAL; /* Create a new socket. */ - err = sock_create(oldsk->family, SOCK_SEQPACKET, IPPROTO_SCTP, - &tmpsock); + err = sock_create(sk->family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); if (err < 0) return err; - newsk = tmpsock->sk; - /* Populate the fields of the newsk from the oldsk and migrate the - * assoc to the newsk. - */ - sctp_sock_migrate(oldsk, newsk, assoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); - - *newsock = tmpsock; + * asoc to the newsk. + */ + sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); + *sockp = sock; return err; } @@ -2011,22 +2202,22 @@ sctp_peeloff_arg_t peeloff; struct socket *newsock; int retval = 0; - sctp_association_t *assoc; + struct sctp_association *asoc; if (len != sizeof(sctp_peeloff_arg_t)) return -EINVAL; if (copy_from_user(&peeloff, optval, len)) return -EFAULT; - assoc = sctp_id2assoc(sk, peeloff.associd); - if (NULL == assoc) { + asoc = sctp_id2assoc(sk, peeloff.associd); + if (!asoc) { retval = -EINVAL; goto out; } - SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc); + SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __FUNCTION__, sk, asoc); - retval = sctp_do_peeloff(assoc, &newsock); + retval = sctp_do_peeloff(asoc, &newsock); if (retval < 0) goto out; @@ -2037,8 +2228,8 @@ goto out; } - SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n", - __FUNCTION__, sk, assoc, newsock->sk, retval); + SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n", + __FUNCTION__, sk, asoc, newsock->sk, retval); /* Return the fd mapped to the new socket. */ peeloff.sd = retval; @@ -2049,11 +2240,11 @@ return retval; } -static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, +static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, char *optval, int *optlen) { struct sctp_paddrparams params; - sctp_association_t *asoc; + struct sctp_association *asoc; union sctp_addr *addr; struct sctp_transport *trans; @@ -2088,7 +2279,9 @@ if (copy_to_user(optval, ¶ms, len)) return -EFAULT; - *optlen = len; + + if (put_user(len, optlen)) + return -EFAULT; return 0; } @@ -2102,11 +2295,11 @@ return 0; } -static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, +static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, char *optval, int *optlen) { sctp_assoc_t id; - sctp_association_t *asoc; + struct sctp_association *asoc; struct list_head *pos; int cnt = 0; @@ -2135,7 +2328,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, char *optval, int *optlen) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct list_head *pos; int cnt = 0; struct sctp_getaddrs getaddrs; @@ -2176,8 +2369,8 @@ char *optval, int *optlen) { sctp_assoc_t id; - sctp_bind_addr_t *bp; - sctp_association_t *asoc; + struct sctp_bind_addr *bp; + struct sctp_association *asoc; struct list_head *pos; int cnt = 0; @@ -2214,8 +2407,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, char *optval, int *optlen) { - sctp_bind_addr_t *bp; - sctp_association_t *asoc; + struct sctp_bind_addr *bp; + struct sctp_association *asoc; struct list_head *pos; int cnt = 0; struct sctp_getaddrs getaddrs; @@ -2317,7 +2510,7 @@ int len, char *optval, int *optlen) { struct sctp_sndrcvinfo info; - sctp_association_t *asoc; + struct sctp_association *asoc; if (len != sizeof(struct sctp_sndrcvinfo)) return -EINVAL; @@ -2350,15 +2543,15 @@ * integer boolean flag. */ -static int sctp_getsockopt_nodelay(struct sock *sk, int len, - char *optval, int *optlen) +static int sctp_getsockopt_nodelay(struct sock *sk, int len, + char *optval, int *optlen) { - __u8 val; + int val; - if (len < sizeof(__u8)) + if (len < sizeof(int)) return -EINVAL; - len = sizeof(__u8); + len = sizeof(int); val = (sctp_sk(sk)->nodelay == 1); if (put_user(len, optlen)) return -EFAULT; @@ -2366,6 +2559,62 @@ return -EFAULT; return 0; } +/* + * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) + * + * This socket option is a boolean flag which turns on or off mapped V4 + * addresses. If this option is turned on and the socket is type + * PF_INET6, then IPv4 addresses will be mapped to V6 representation. + * If this option is turned off, then no mapping will be done of V4 + * addresses and a user will receive both PF_INET6 and PF_INET type + * addresses on the socket. + */ +static int sctp_getsockopt_mappedv4(struct sock *sk, int len, + char *optval, int *optlen) +{ + int val; + if (len < sizeof(int)) + return -EINVAL; + + len = sizeof(int); + /* FIXME: Until we have support, return disabled. */ + val = 0; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + +/* + * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) + * + * This socket option specifies the maximum size to put in any outgoing + * SCTP chunk. If a message is larger than this size it will be + * fragmented by SCTP into the specified size. Note that the underlying + * SCTP implementation may fragment into smaller sized chunks when the + * PMTU of the underlying association is smaller than the value set by + * the user. + */ +static int sctp_getsockopt_maxseg(struct sock *sk, int len, + char *optval, int *optlen) +{ + int val; + + if (len < sizeof(int)) + return -EINVAL; + + len = sizeof(int); + + val = sctp_sk(sk)->user_frag; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) @@ -2418,7 +2667,7 @@ retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); break; case SCTP_GET_PEER_ADDRS_NUM: - retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, + retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, optlen); break; case SCTP_GET_LOCAL_ADDRS_NUM: @@ -2443,6 +2692,12 @@ case SCTP_NODELAY: retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); break; + case SCTP_I_WANT_MAPPED_V4_ADDR: + retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen); + break; + case SCTP_MAXSEG: + retval = sctp_getsockopt_maxseg(sk, len, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -2553,7 +2808,7 @@ } - if (pp != NULL && pp->sk != NULL) { + if (pp && pp->sk) { /* We had a port hash table hit - there is an * available port (pp != NULL) and it is being * used by other socket (pp->sk != NULL); that other @@ -2578,7 +2833,7 @@ * in an endpoint. */ for ( ; sk2 != NULL; sk2 = sk2->bind_next) { - sctp_endpoint_t *ep2; + struct sctp_endpoint *ep2; ep2 = sctp_sk(sk2)->ep; if (sk_reuse && sk2->reuse) @@ -2601,18 +2856,17 @@ /* If there was a hash table miss, create a new port. */ ret = 1; - if (pp == NULL && (pp = sctp_bucket_create(head, snum)) == NULL) + if (!pp && !(pp = sctp_bucket_create(head, snum))) goto fail_unlock; /* In either case (hit or miss), make sure fastreuse is 1 only * if sk->reuse is too (that is, if the caller requested * SO_REUSEADDR on this socket -sk-). */ - if (pp->sk == NULL) { + if (!pp->sk) pp->fastreuse = sk->reuse ? 1 : 0; - } else if (pp->fastreuse && sk->reuse == 0) { + else if (pp->fastreuse && sk->reuse == 0) pp->fastreuse = 0; - } /* We are set, so fill up all the data in the hash table * entry, tie the socket list information with the rest of the @@ -2669,15 +2923,15 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) { struct sctp_opt *sp = sctp_sk(sk); - sctp_endpoint_t *ep = sp->ep; + struct sctp_endpoint *ep = sp->ep; /* Only UDP style sockets that are not peeled off are allowed to * listen(). */ - if (SCTP_SOCKET_UDP != sp->type) + if (!sctp_style(sk, UDP)) return -EINVAL; - if (sk->state == SCTP_SS_LISTENING) + if (sctp_sstate(sk, LISTENING)) return 0; /* @@ -2702,15 +2956,15 @@ /* * 4.1.3 listen() - TCP Style Syntax * - * Applications uses listen() to ready the SCTP endpoint for accepting + * Applications uses listen() to ready the SCTP endpoint for accepting * inbound associations. */ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog) { struct sctp_opt *sp = sctp_sk(sk); - sctp_endpoint_t *ep = sp->ep; + struct sctp_endpoint *ep = sp->ep; - if (sk->state == SCTP_SS_LISTENING) + if (sctp_sstate(sk, LISTENING)) return 0; /* @@ -2739,15 +2993,25 @@ int sctp_inet_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; - int err; + struct crypto_tfm *tfm=NULL; + int err = -EINVAL; + + if (unlikely(backlog < 0)) + goto out; sctp_lock_sock(sk); - err = -EINVAL; if (sock->state != SS_UNCONNECTED) goto out; - if (unlikely(backlog < 0)) - goto out; + + /* Allocate HMAC for generating cookie. */ + if (sctp_hmac_alg) { + tfm = sctp_crypto_alloc_tfm(sctp_hmac_alg, 0); + if (!tfm) { + err = -ENOSYS; + goto out; + } + } switch (sock->type) { case SOCK_SEQPACKET: @@ -2756,14 +3020,21 @@ case SOCK_STREAM: err = sctp_stream_listen(sk, backlog); break; - default: - goto out; + break; }; + if (err) + goto cleanup; + /* Store away the transform reference. */ + sctp_sk(sk)->hmac = tfm; out: sctp_release_sock(sk); return err; +cleanup: + if (tfm) + sctp_crypto_free_tfm(tfm); + goto out; } /* @@ -2782,9 +3053,18 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; + struct sctp_opt *sp = sctp_sk(sk); unsigned int mask; poll_wait(file, sk->sleep, wait); + + /* A TCP-style listening socket becomes readable when the accept queue + * is not empty. + */ + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) + return (!list_empty(&sp->ep->asocs)) ? + (POLLIN | POLLRDNORM) : 0; + mask = 0; /* Is there any exceptional events? */ @@ -2798,19 +3078,9 @@ (sk->shutdown & RCV_SHUTDOWN)) mask |= POLLIN | POLLRDNORM; - /* - * FIXME: We need to set SCTP_SS_DISCONNECTING for TCP-style and - * peeled off sockets. Additionally, TCP-style needs to consider - * other establishment conditions. - */ - if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { - /* The association is going away. */ - if (SCTP_SS_DISCONNECTING == sk->state) - mask |= POLLHUP; - /* The association is either gone or not ready. */ - if (SCTP_SS_CLOSED == sk->state) - return mask; - } + /* The association is either gone or not ready. */ + if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED)) + return mask; /* Is it writable? */ if (sctp_writeable(sk)) { @@ -2967,7 +3237,7 @@ /* Strictly check lengths following example in SCM code. */ switch (cmsg->cmsg_type) { case SCTP_INIT: - /* SCTP Socket API Extension (draft 1) + /* SCTP Socket API Extension * 5.2.1 SCTP Initiation Structure (SCTP_INIT) * * This cmsghdr structure provides information for @@ -2987,7 +3257,7 @@ break; case SCTP_SNDRCV: - /* SCTP Socket API Extension (draft 1) + /* SCTP Socket API Extension * 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV) * * This cmsghdr structure specifies SCTP options for @@ -3002,7 +3272,8 @@ CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) return -EINVAL; - cmsgs->info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + cmsgs->info = + (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); /* Minimally, validate the sinfo_flags. */ if (cmsgs->info->sinfo_flags & @@ -3026,10 +3297,9 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) { int error; - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT(wait); - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue_exclusive(sk->sleep, &wait); + prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE); /* Socket errors? */ error = sock_error(sk); @@ -3049,8 +3319,7 @@ error = -ENOTCONN; /* Is there a good reason to think that we may receive some data? */ - if ((list_empty(&sctp_sk(sk)->ep->asocs)) && - (sk->state != SCTP_SS_LISTENING)) + if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING)) goto out; /* Handle signals. */ @@ -3067,16 +3336,14 @@ sctp_lock_sock(sk); ready: - remove_wait_queue(sk->sleep, &wait); - __set_current_state(TASK_RUNNING); + finish_wait(sk->sleep, &wait); return 0; interrupted: error = sock_intr_errno(*timeo_p); out: - remove_wait_queue(sk->sleep, &wait); - __set_current_state(TASK_RUNNING); + finish_wait(sk->sleep, &wait); *err = error; return error; } @@ -3085,13 +3352,14 @@ * Note: This is pretty much the same routine as in core/datagram.c * with a few changes to make lksctp work. */ -static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) +static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, + int noblock, int *err) { int error; struct sk_buff *skb; long timeo; - /* Caller is allowed not to check sk->err before skb_recv_datagram() */ + /* Caller is allowed not to check sk->err before calling. */ error = sock_error(sk); if (error) goto no_packet; @@ -3126,6 +3394,9 @@ if (skb) return skb; + if (sk->shutdown & RCV_SHUTDOWN) + break; + /* User doesn't want to wait. */ error = -EAGAIN; if (!timeo) @@ -3140,7 +3411,7 @@ } /* Verify that this is a valid address. */ -static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, +static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, int len) { struct sctp_af *af; @@ -3161,7 +3432,7 @@ } /* Get the sndbuf space available at the time on the association. */ -static inline int sctp_wspace(sctp_association_t *asoc) +static inline int sctp_wspace(struct sctp_association *asoc) { struct sock *sk = asoc->base.sk; int amt = 0; @@ -3181,9 +3452,9 @@ * destructor in the data chunk skb for the purpose of the sndbuf space * tracking. */ -static inline void sctp_set_owner_w(sctp_chunk_t *chunk) +static inline void sctp_set_owner_w(struct sctp_chunk *chunk) { - sctp_association_t *asoc = chunk->asoc; + struct sctp_association *asoc = chunk->asoc; struct sock *sk = asoc->base.sk; /* The sndbuf space is tracked per association. */ @@ -3191,14 +3462,14 @@ chunk->skb->destructor = sctp_wfree; /* Save the chunk pointer in skb for sctp_wfree to use later. */ - *((sctp_chunk_t **)(chunk->skb->cb)) = chunk; + *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk); } /* If sndbuf has changed, wake up per association sndbuf waiters. */ -static void __sctp_write_space(sctp_association_t *asoc) +static void __sctp_write_space(struct sctp_association *asoc) { struct sock *sk = asoc->base.sk; struct socket *sock = sk->socket; @@ -3228,12 +3499,12 @@ */ static void sctp_wfree(struct sk_buff *skb) { - sctp_association_t *asoc; - sctp_chunk_t *chunk; + struct sctp_association *asoc; + struct sctp_chunk *chunk; struct sock *sk; /* Get the saved chunk pointer. */ - chunk = *((sctp_chunk_t **)(skb->cb)); + chunk = *((struct sctp_chunk **)(skb->cb)); asoc = chunk->asoc; sk = asoc->base.sk; asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); @@ -3244,24 +3515,24 @@ } /* Helper function to wait for space in the sndbuf. */ -static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, +static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, int msg_len) { struct sock *sk = asoc->base.sk; int err = 0; long current_timeo = *timeo_p; - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT(wait); SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%d\n", asoc, (long)(*timeo_p), msg_len); - /* Wait on the association specific sndbuf space. */ - add_wait_queue_exclusive(&asoc->wait, &wait); - /* Increment the association's refcnt. */ sctp_association_hold(asoc); + + /* Wait on the association specific sndbuf space. */ for (;;) { - set_current_state(TASK_INTERRUPTIBLE); + prepare_to_wait_exclusive(&asoc->wait, &wait, + TASK_INTERRUPTIBLE); if (!*timeo_p) goto do_nonblock; if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || @@ -3283,12 +3554,11 @@ } out: - remove_wait_queue(&asoc->wait, &wait); + finish_wait(&asoc->wait, &wait); /* Release the association's refcnt. */ sctp_association_put(asoc); - __set_current_state(TASK_RUNNING); return err; do_error: @@ -3307,12 +3577,12 @@ /* If socket sndbuf has changed, wake up all per association waiters. */ void sctp_write_space(struct sock *sk) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct list_head *pos; /* Wake up the tasks in each wait queue. */ list_for_each(pos, &((sctp_sk(sk))->ep->asocs)) { - asoc = list_entry(pos, sctp_association_t, asocs); + asoc = list_entry(pos, struct sctp_association, asocs); __sctp_write_space(asoc); } } @@ -3341,32 +3611,33 @@ /* Wait for an association to go into ESTABLISHED state. If timeout is 0, * returns immediately with EINPROGRESS. */ -static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p) +static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) { struct sock *sk = asoc->base.sk; int err = 0; long current_timeo = *timeo_p; - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT(wait); SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc, (long)(*timeo_p)); - add_wait_queue_exclusive(&asoc->wait, &wait); - /* Increment the association's refcnt. */ sctp_association_hold(asoc); for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); + prepare_to_wait_exclusive(&asoc->wait, &wait, + TASK_INTERRUPTIBLE); if (!*timeo_p) goto do_nonblock; + if (sk->shutdown & RCV_SHUTDOWN) + break; if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || asoc->base.dead) goto do_error; if (signal_pending(current)) goto do_interrupted; - if (asoc->state == SCTP_STATE_ESTABLISHED) + if (sctp_state(asoc, ESTABLISHED)) break; /* Let another process have a go. Since we are going @@ -3380,13 +3651,11 @@ } out: - remove_wait_queue(&asoc->wait, &wait); + finish_wait(&asoc->wait, &wait); /* Release the association's refcnt. */ sctp_association_put(asoc); - __set_current_state(TASK_RUNNING); - return err; do_error: @@ -3406,14 +3675,14 @@ { struct sctp_endpoint *ep; int err = 0; - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT(wait); ep = sctp_sk(sk)->ep; - add_wait_queue_exclusive(sk->sleep, &wait); for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); + prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE); + if (list_empty(&ep->asocs)) { sctp_release_sock(sk); timeo = schedule_timeout(timeo); @@ -3421,7 +3690,7 @@ } err = -EINVAL; - if (sk->state != SCTP_SS_LISTENING) + if (!sctp_sstate(sk, LISTENING)) break; err = 0; @@ -3437,21 +3706,37 @@ break; } - remove_wait_queue(sk->sleep, &wait); - __set_current_state(TASK_RUNNING); + finish_wait(sk->sleep, &wait); return err; } -/* Populate the fields of the newsk from the oldsk and migrate the assoc +void sctp_wait_for_close(struct sock *sk, long timeout) +{ + DEFINE_WAIT(wait); + + do { + prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + if (list_empty(&sctp_sk(sk)->ep->asocs)) + break; + sctp_release_sock(sk); + timeout = schedule_timeout(timeout); + sctp_lock_sock(sk); + } while (!signal_pending(current) && timeout); + + finish_wait(sk->sleep, &wait); +} + +/* Populate the fields of the newsk from the oldsk and migrate the assoc * and its messages to the newsk. - */ -void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, - struct sctp_association *assoc, sctp_socket_type_t type) + */ +static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, + struct sctp_association *assoc, + sctp_socket_type_t type) { struct sctp_opt *oldsp = sctp_sk(oldsk); struct sctp_opt *newsp = sctp_sk(newsk); - sctp_endpoint_t *newep = newsp->ep; + struct sctp_endpoint *newep = newsp->ep; struct sk_buff *skb, *tmp; struct sctp_ulpevent *event; @@ -3466,6 +3751,7 @@ * copy. */ newsp->ep = newep; + newsp->hmac = NULL; /* Move any messages in the old socket's receive queue that are for the * peeled off association to the new socket's receive queue. @@ -3524,9 +3810,15 @@ /* Migrate the association to the new socket. */ sctp_assoc_migrate(assoc, newsk); + /* If the association on the newsk is already closed before accept() + * is called, set RCV_SHUTDOWN flag. + */ + if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) + newsk->shutdown |= RCV_SHUTDOWN; + newsk->state = SCTP_SS_ESTABLISHED; } - + /* This proto struct describes the ULP interface for SCTP. */ struct proto sctp_prot = { .name = "SCTP", diff -urN linux-2.5.69-bk3/net/sctp/ssnmap.c linux-2.5.69-bk4/net/sctp/ssnmap.c --- linux-2.5.69-bk3/net/sctp/ssnmap.c 2003-05-04 16:53:37.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/ssnmap.c 2003-05-09 04:41:39.000000000 -0700 @@ -53,11 +53,11 @@ /* Create a new sctp_ssnmap. * Allocate room to store at least 'len' contiguous TSNs. */ -struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int priority) +struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp) { struct sctp_ssnmap *retval; - retval = kmalloc(sctp_ssnmap_size(in, out), priority); + retval = kmalloc(sctp_ssnmap_size(in, out), gfp); if (!retval) goto fail; diff -urN linux-2.5.69-bk3/net/sctp/transport.c linux-2.5.69-bk4/net/sctp/transport.c --- linux-2.5.69-bk3/net/sctp/transport.c 2003-05-04 16:53:07.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/transport.c 2003-05-09 04:41:39.000000000 -0700 @@ -54,16 +54,15 @@ /* 1st Level Abstractions. */ /* Allocate and initialize a new transport. */ -struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, - int priority) +struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp) { struct sctp_transport *transport; - transport = t_new(struct sctp_transport, priority); + transport = t_new(struct sctp_transport, gfp); if (!transport) goto fail; - if (!sctp_transport_init(transport, addr, priority)) + if (!sctp_transport_init(transport, addr, gfp)) goto fail_init; transport->malloced = 1; @@ -81,7 +80,7 @@ /* Initialize a new transport from provided memory. */ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, const union sctp_addr *addr, - int priority) + int gfp) { struct sctp_protocol *proto = sctp_get_protocol(); @@ -117,8 +116,6 @@ peer->error_threshold = 0; peer->error_count = 0; - peer->debug_name = "unnamedtransport"; - INIT_LIST_HEAD(&peer->transmitted); INIT_LIST_HEAD(&peer->send_ready); INIT_LIST_HEAD(&peer->transports); @@ -138,6 +135,13 @@ peer->dead = 0; peer->malloced = 0; + + /* Initialize the state information for SFR-CACC */ + peer->cacc.changeover_active = 0; + peer->cacc.cycling_changeover = 0; + peer->cacc.next_tsn_at_change = 0; + peer->cacc.cacc_saw_newack = 0; + return peer; } @@ -199,13 +203,13 @@ * Register the reference count in the association. */ void sctp_transport_set_owner(struct sctp_transport *transport, - sctp_association_t *asoc) + struct sctp_association *asoc) { transport->asoc = asoc; sctp_association_hold(asoc); } -/* Initialize the pmtu of a transport. */ +/* Initialize the pmtu of a transport. */ void sctp_transport_pmtu(struct sctp_transport *transport) { struct dst_entry *dst; @@ -225,7 +229,7 @@ void sctp_transport_route(struct sctp_transport *transport, union sctp_addr *saddr, struct sctp_opt *opt) { - sctp_association_t *asoc = transport->asoc; + struct sctp_association *asoc = transport->asoc; struct sctp_af *af = transport->af_specific; union sctp_addr *daddr = &transport->ipaddr; struct dst_entry *dst; @@ -238,9 +242,15 @@ af->get_saddr(asoc, dst, daddr, &transport->saddr); transport->dst = dst; - if (dst) + if (dst) { transport->pmtu = dst_pmtu(dst); - else + + /* Initialize sk->rcv_saddr, if the transport is the + * association's active path for getsockname(). + */ + if (asoc && (transport == asoc->peer.active_path)) + af->to_sk_saddr(&transport->saddr, asoc->base.sk); + } else transport->pmtu = SCTP_DEFAULT_MAXSEGMENT; } @@ -359,7 +369,7 @@ * two conditions are met can the cwnd be increased otherwise * the cwnd MUST not be increased. If these conditions are met * then cwnd MUST be increased by at most the lesser of - * 1) the total size of the previously outstanding DATA + * 1) the total size of the previously outstanding DATA * chunk(s) acknowledged, and 2) the destination's path MTU. */ if (bytes_acked > pmtu) @@ -373,17 +383,17 @@ transport, bytes_acked, cwnd, ssthresh, flight_size, pba); } else { - /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, - * upon each SACK arrival that advances the Cumulative TSN Ack - * Point, increase partial_bytes_acked by the total number of - * bytes of all new chunks acknowledged in that SACK including - * chunks acknowledged by the new Cumulative TSN Ack and by + /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, + * upon each SACK arrival that advances the Cumulative TSN Ack + * Point, increase partial_bytes_acked by the total number of + * bytes of all new chunks acknowledged in that SACK including + * chunks acknowledged by the new Cumulative TSN Ack and by * Gap Ack Blocks. * - * When partial_bytes_acked is equal to or greater than cwnd - * and before the arrival of the SACK the sender had cwnd or - * more bytes of data outstanding (i.e., before arrival of the - * SACK, flightsize was greater than or equal to cwnd), + * When partial_bytes_acked is equal to or greater than cwnd + * and before the arrival of the SACK the sender had cwnd or + * more bytes of data outstanding (i.e., before arrival of the + * SACK, flightsize was greater than or equal to cwnd), * increase cwnd by MTU, and reset partial_bytes_acked to * (partial_bytes_acked - cwnd). */ diff -urN linux-2.5.69-bk3/net/sctp/tsnmap.c linux-2.5.69-bk4/net/sctp/tsnmap.c --- linux-2.5.69-bk3/net/sctp/tsnmap.c 2003-05-04 16:53:42.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/tsnmap.c 2003-05-09 04:41:39.000000000 -0700 @@ -55,13 +55,12 @@ /* Create a new sctp_tsnmap. * Allocate room to store at least 'len' contiguous TSNs. */ -struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority) +struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int gfp) { struct sctp_tsnmap *retval; retval = kmalloc(sizeof(struct sctp_tsnmap) + - sctp_tsnmap_storage_size(len), - priority); + sctp_tsnmap_storage_size(len), gfp); if (!retval) goto fail; diff -urN linux-2.5.69-bk3/net/sctp/ulpevent.c linux-2.5.69-bk4/net/sctp/ulpevent.c --- linux-2.5.69-bk3/net/sctp/ulpevent.c 2003-05-04 16:53:03.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/ulpevent.c 2003-05-09 04:41:39.000000000 -0700 @@ -52,12 +52,12 @@ const struct sctp_association *asoc); /* Create a new sctp_ulpevent. */ -struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int priority) +struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp) { struct sctp_ulpevent *event; struct sk_buff *skb; - skb = alloc_skb(size, priority); + skb = alloc_skb(size, gfp); if (!skb) goto fail; @@ -106,16 +106,16 @@ * zero'd out. */ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( - const sctp_association_t *asoc, + const struct sctp_association *asoc, __u16 flags, __u16 state, __u16 error, __u16 outbound, - __u16 inbound, int priority) + __u16 inbound, int gfp) { struct sctp_ulpevent *event; struct sctp_assoc_change *sac; struct sk_buff *skb; event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), - MSG_NOTIFICATION, priority); + MSG_NOTIFICATION, gfp); if (!event) goto fail; skb = sctp_event2skb(event); @@ -207,15 +207,16 @@ * an interface details event is sent. */ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( - const sctp_association_t *asoc, const struct sockaddr_storage *aaddr, - int flags, int state, int error, int priority) + const struct sctp_association *asoc, + const struct sockaddr_storage *aaddr, + int flags, int state, int error, int gfp) { struct sctp_ulpevent *event; struct sctp_paddr_change *spc; struct sk_buff *skb; event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change), - MSG_NOTIFICATION, priority); + MSG_NOTIFICATION, gfp); if (!event) goto fail; @@ -315,8 +316,8 @@ * error formats. */ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( - const sctp_association_t *asoc, sctp_chunk_t *chunk, - __u16 flags, int priority) + const struct sctp_association *asoc, struct sctp_chunk *chunk, + __u16 flags, int gfp) { struct sctp_ulpevent *event; struct sctp_remote_error *sre; @@ -327,7 +328,7 @@ ch = (sctp_errhdr_t *)(chunk->skb->data); cause = ch->cause; - elen = ntohs(ch->length) - sizeof(sctp_errhdr_t); + elen = WORD_ROUND(ntohs(ch->length)) - sizeof(sctp_errhdr_t); /* Pull off the ERROR header. */ skb_pull(chunk->skb, sizeof(sctp_errhdr_t)); @@ -335,10 +336,8 @@ /* Copy the skb to a new skb with room for us to prepend * notification with. */ - skb = skb_copy_expand(chunk->skb, - sizeof(struct sctp_remote_error), /* headroom */ - 0, /* tailroom */ - priority); + skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error), + 0, gfp); /* Pull off the rest of the cause TLV from the chunk. */ skb_pull(chunk->skb, elen); @@ -419,23 +418,27 @@ * 5.3.1.4 SCTP_SEND_FAILED */ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( - const sctp_association_t *asoc, sctp_chunk_t *chunk, - __u16 flags, __u32 error, int priority) + const struct sctp_association *asoc, struct sctp_chunk *chunk, + __u16 flags, __u32 error, int gfp) { struct sctp_ulpevent *event; struct sctp_send_failed *ssf; struct sk_buff *skb; + /* Pull off any padding. */ + int len = ntohs(chunk->chunk_hdr->length); + /* Make skb with more room so we can prepend notification. */ skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_send_failed), /* headroom */ 0, /* tailroom */ - priority); + gfp); if (!skb) goto fail; /* Pull off the common chunk header and DATA header. */ - skb_pull(skb, sizeof(sctp_data_chunk_t)); + skb_pull(skb, sizeof(struct sctp_data_chunk)); + len -= sizeof(struct sctp_data_chunk); /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); @@ -476,7 +479,8 @@ * This field is the total length of the notification data, including * the notification header. */ - ssf->ssf_length = skb->len; + ssf->ssf_length = sizeof(struct sctp_send_failed) + len; + skb_trim(skb, ssf->ssf_length); /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED @@ -497,6 +501,11 @@ */ memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo)); + /* Per TSVWG discussion with Randy. Allow the application to + * ressemble a fragmented message. + */ + ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags; + /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * @@ -521,15 +530,15 @@ * 5.3.1.5 SCTP_SHUTDOWN_EVENT */ struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( - const sctp_association_t *asoc, - __u16 flags, int priority) + const struct sctp_association *asoc, + __u16 flags, int gfp) { struct sctp_ulpevent *event; struct sctp_shutdown_event *sse; struct sk_buff *skb; event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), - MSG_NOTIFICATION, priority); + MSG_NOTIFICATION, gfp); if (!event) goto fail; @@ -586,8 +595,9 @@ * Socket Extensions for SCTP * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) */ -struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, - sctp_chunk_t *chunk, int priority) +struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, + struct sctp_chunk *chunk, + int gfp) { struct sctp_ulpevent *event; struct sctp_sndrcvinfo *info; @@ -595,7 +605,7 @@ size_t padding, len; /* Clone the original skb, sharing the data. */ - skb = skb_clone(chunk->skb, priority); + skb = skb_clone(chunk->skb, gfp); if (!skb) goto fail; @@ -631,7 +641,7 @@ event->iif = sctp_chunk_iif(chunk); /* Note: Not clearing the entire event struct as * this is just a fragment of the real event. However, - * we still need to do rwnd accounting. + * we still need to do rwnd accounting. */ for (list = skb_shinfo(skb)->frag_list; list; list = list->next) sctp_ulpevent_set_owner_r(list, asoc); @@ -690,16 +700,16 @@ info->sinfo_flags |= MSG_UNORDERED; /* sinfo_cumtsn: 32 bit (unsigned integer) - * - * This field will hold the current cumulative TSN as - * known by the underlying SCTP layer. Note this field is - * ignored when sending and only valid for a receive + * + * This field will hold the current cumulative TSN as + * known by the underlying SCTP layer. Note this field is + * ignored when sending and only valid for a receive * operation when sinfo_flags are set to MSG_UNORDERED. */ info->sinfo_cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); } - /* Note: For reassembly, we need to have the fragmentation bits. + /* Note: For reassembly, we need to have the fragmentation bits. * For now, merge these into the msg_flags, since those bit * possitions are not used. */ @@ -732,7 +742,7 @@ return NULL; } -/* Create a partial delivery related event. +/* Create a partial delivery related event. * * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT * @@ -741,14 +751,14 @@ * various events. */ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( - const sctp_association_t *asoc, __u32 indication, int priority) + const struct sctp_association *asoc, __u32 indication, int gfp) { struct sctp_ulpevent *event; struct sctp_rcv_pdapi_event *pd; struct sk_buff *skb; event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), - MSG_NOTIFICATION, priority); + MSG_NOTIFICATION, gfp); if (!event) goto fail; @@ -780,7 +790,7 @@ pd->pdapi_indication = indication; /* pdapi_assoc_id: sizeof (sctp_assoc_t) - * + * * The association id field, holds the identifier for the association. */ pd->pdapi_assoc_id = sctp_assoc2id(asoc); @@ -817,7 +827,7 @@ /* Do accounting for bytes just read by user. */ static void sctp_rcvmsg_rfree(struct sk_buff *skb) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct sctp_ulpevent *event; /* Current stack structures assume that the rcv buffer is @@ -834,7 +844,7 @@ /* Charge receive window for bytes received. */ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, - sctp_association_t *asoc) + struct sctp_association *asoc) { struct sctp_ulpevent *event; diff -urN linux-2.5.69-bk3/net/sctp/ulpqueue.c linux-2.5.69-bk4/net/sctp/ulpqueue.c --- linux-2.5.69-bk3/net/sctp/ulpqueue.c 2003-05-04 16:53:41.000000000 -0700 +++ linux-2.5.69-bk4/net/sctp/ulpqueue.c 2003-05-09 04:41:39.000000000 -0700 @@ -57,11 +57,11 @@ /* 1st Level Abstractions */ /* Create a new ULP queue. */ -struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority) +struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp) { struct sctp_ulpq *ulpq; - ulpq = kmalloc(sizeof(struct sctp_ulpq), priority); + ulpq = kmalloc(sizeof(struct sctp_ulpq), gfp); if (!ulpq) goto fail; if (!sctp_ulpq_init(ulpq, asoc)) @@ -77,7 +77,7 @@ /* Initialize a ULP queue from a block of memory. */ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq, - sctp_association_t *asoc) + struct sctp_association *asoc) { memset(ulpq, sizeof(struct sctp_ulpq), 0x00); @@ -118,8 +118,8 @@ } /* Process an incoming DATA chunk. */ -int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk, - int priority) +int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, + int gfp) { struct sk_buff_head temp; sctp_data_chunk_t *hdr; @@ -128,7 +128,7 @@ hdr = (sctp_data_chunk_t *) chunk->chunk_hdr; /* Create an event from the incoming chunk. */ - event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, priority); + event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, gfp); if (!event) return -ENOMEM; @@ -253,6 +253,21 @@ tsn = event->sndrcvinfo.sinfo_tsn; + /* See if it belongs at the end. */ + pos = skb_peek_tail(&ulpq->reasm); + if (!pos) { + __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); + return; + } + + /* Short circuit just dropping it at the end. */ + cevent = sctp_skb2event(pos); + ctsn = cevent->sndrcvinfo.sinfo_tsn; + if (TSN_lt(ctsn, tsn)) { + __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); + return; + } + /* Find the right place in this list. We store them by TSN. */ skb_queue_walk(&ulpq->reasm, pos) { cevent = sctp_skb2event(pos); @@ -262,12 +277,9 @@ break; } - /* If the queue is empty, we have a different function to call. */ - if (skb_peek(&ulpq->reasm)) - __skb_insert(sctp_event2skb(event), pos->prev, pos, - &ulpq->reasm); - else - __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); + /* Insert before pos. */ + __skb_insert(sctp_event2skb(event), pos->prev, pos, &ulpq->reasm); + } /* Helper function to return an event corresponding to the reassembled @@ -592,8 +604,27 @@ __u16 sid, csid; __u16 ssn, cssn; + pos = skb_peek_tail(&ulpq->lobby); + if (!pos) { + __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); + return; + } + sid = event->sndrcvinfo.sinfo_stream; ssn = event->sndrcvinfo.sinfo_ssn; + + cevent = (struct sctp_ulpevent *) pos->cb; + csid = cevent->sndrcvinfo.sinfo_stream; + cssn = cevent->sndrcvinfo.sinfo_ssn; + if (sid > csid) { + __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); + return; + } + + if ((sid == csid) && SSN_lt(cssn, ssn)) { + __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); + return; + } /* Find the right place in this list. We store them by * stream ID and then by SSN. @@ -609,12 +640,10 @@ break; } - /* If the queue is empty, we have a different function to call. */ - if (skb_peek(&ulpq->lobby)) - __skb_insert(sctp_event2skb(event), pos->prev, pos, - &ulpq->lobby); - else - __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); + + /* Insert before pos. */ + __skb_insert(sctp_event2skb(event), pos->prev, pos, &ulpq->lobby); + } static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, @@ -705,7 +734,7 @@ /* Partial deliver the first message as there is pressure on rwnd. */ void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, - struct sctp_chunk *chunk, int priority) + struct sctp_chunk *chunk, int gfp) { struct sctp_ulpevent *event; struct sctp_association *asoc; @@ -729,7 +758,7 @@ /* Renege some packets to make room for an incoming chunk. */ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, - int priority) + int gfp) { struct sctp_association *asoc; __u16 needed, freed; @@ -755,9 +784,9 @@ __u32 tsn; tsn = ntohl(chunk->subh.data_hdr->tsn); sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn); - sctp_ulpq_tail_data(ulpq, chunk, priority); + sctp_ulpq_tail_data(ulpq, chunk, gfp); - sctp_ulpq_partial_delivery(ulpq, chunk, priority); + sctp_ulpq_partial_delivery(ulpq, chunk, gfp); } return; @@ -768,7 +797,7 @@ /* Notify the application if an association is aborted and in * partial delivery mode. Send up any pending received messages. */ -void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority) +void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int gfp) { struct sctp_ulpevent *ev = NULL; struct sock *sk; @@ -781,7 +810,7 @@ &sctp_sk(sk)->subscribe)) ev = sctp_ulpevent_make_pdapi(ulpq->asoc, SCTP_PARTIAL_DELIVERY_ABORTED, - priority); + gfp); if (ev) __skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev)); diff -urN linux-2.5.69-bk3/scripts/Makefile.build linux-2.5.69-bk4/scripts/Makefile.build --- linux-2.5.69-bk3/scripts/Makefile.build 2003-05-09 04:41:28.000000000 -0700 +++ linux-2.5.69-bk4/scripts/Makefile.build 2003-05-09 04:41:39.000000000 -0700 @@ -66,10 +66,10 @@ $(subdir-ym) $(always) @: -# Linus's kernel sanity checking tool +# Linus' kernel sanity checking tool ifneq ($(KBUILD_CHECKSRC),0) quiet_cmd_checksrc = CHECK $< - cmd_checksrc = $(CHECK) $(CFLAGS) $< ; + cmd_checksrc = $(CHECK) $(c_flags) $< ; endif # Module versioning