Annotation of /trunk/kernel-magellan/patches-3.15/0108-3.15.9-all-fixes.patch
Parent Directory | Revision Log
Revision 2493 -
(hide annotations)
(download)
Thu Sep 4 19:55:25 2014 UTC (10 years ago) by niro
File size: 42002 byte(s)
Thu Sep 4 19:55:25 2014 UTC (10 years ago) by niro
File size: 42002 byte(s)
-linux-3.15.9
1 | niro | 2493 | diff --git a/Makefile b/Makefile |
2 | index 25b85aba1e2e..76b75f7b8485 100644 | ||
3 | --- a/Makefile | ||
4 | +++ b/Makefile | ||
5 | @@ -1,6 +1,6 @@ | ||
6 | VERSION = 3 | ||
7 | PATCHLEVEL = 15 | ||
8 | -SUBLEVEL = 9 | ||
9 | +SUBLEVEL = 10 | ||
10 | EXTRAVERSION = | ||
11 | NAME = Double Funky Skunk | ||
12 | |||
13 | diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h | ||
14 | index 3c3c89f52643..7f9bab26a499 100644 | ||
15 | --- a/arch/sparc/include/asm/tlbflush_64.h | ||
16 | +++ b/arch/sparc/include/asm/tlbflush_64.h | ||
17 | @@ -34,6 +34,8 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, | ||
18 | { | ||
19 | } | ||
20 | |||
21 | +void flush_tlb_kernel_range(unsigned long start, unsigned long end); | ||
22 | + | ||
23 | #define __HAVE_ARCH_ENTER_LAZY_MMU_MODE | ||
24 | |||
25 | extern void flush_tlb_pending(void); | ||
26 | @@ -48,11 +50,6 @@ extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end); | ||
27 | |||
28 | #ifndef CONFIG_SMP | ||
29 | |||
30 | -#define flush_tlb_kernel_range(start,end) \ | ||
31 | -do { flush_tsb_kernel_range(start,end); \ | ||
32 | - __flush_tlb_kernel_range(start,end); \ | ||
33 | -} while (0) | ||
34 | - | ||
35 | static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr) | ||
36 | { | ||
37 | __flush_tlb_page(CTX_HWBITS(mm->context), vaddr); | ||
38 | @@ -63,11 +60,6 @@ static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vad | ||
39 | extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end); | ||
40 | extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr); | ||
41 | |||
42 | -#define flush_tlb_kernel_range(start, end) \ | ||
43 | -do { flush_tsb_kernel_range(start,end); \ | ||
44 | - smp_flush_tlb_kernel_range(start, end); \ | ||
45 | -} while (0) | ||
46 | - | ||
47 | #define global_flush_tlb_page(mm, vaddr) \ | ||
48 | smp_flush_tlb_page(mm, vaddr) | ||
49 | |||
50 | diff --git a/arch/sparc/include/uapi/asm/unistd.h b/arch/sparc/include/uapi/asm/unistd.h | ||
51 | index b73274fb961a..42f2bca1d338 100644 | ||
52 | --- a/arch/sparc/include/uapi/asm/unistd.h | ||
53 | +++ b/arch/sparc/include/uapi/asm/unistd.h | ||
54 | @@ -410,8 +410,9 @@ | ||
55 | #define __NR_finit_module 342 | ||
56 | #define __NR_sched_setattr 343 | ||
57 | #define __NR_sched_getattr 344 | ||
58 | +#define __NR_renameat2 345 | ||
59 | |||
60 | -#define NR_syscalls 345 | ||
61 | +#define NR_syscalls 346 | ||
62 | |||
63 | /* Bitmask values returned from kern_features system call. */ | ||
64 | #define KERN_FEATURE_MIXED_MODE_STACK 0x00000001 | ||
65 | diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c | ||
66 | index e01d75d40329..66dacd56bb10 100644 | ||
67 | --- a/arch/sparc/kernel/ldc.c | ||
68 | +++ b/arch/sparc/kernel/ldc.c | ||
69 | @@ -1336,7 +1336,7 @@ int ldc_connect(struct ldc_channel *lp) | ||
70 | if (!(lp->flags & LDC_FLAG_ALLOCED_QUEUES) || | ||
71 | !(lp->flags & LDC_FLAG_REGISTERED_QUEUES) || | ||
72 | lp->hs_state != LDC_HS_OPEN) | ||
73 | - err = -EINVAL; | ||
74 | + err = ((lp->hs_state > LDC_HS_OPEN) ? 0 : -EINVAL); | ||
75 | else | ||
76 | err = start_handshake(lp); | ||
77 | |||
78 | diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S | ||
79 | index d066eb18650c..f834224208ed 100644 | ||
80 | --- a/arch/sparc/kernel/sys32.S | ||
81 | +++ b/arch/sparc/kernel/sys32.S | ||
82 | @@ -48,6 +48,7 @@ SIGN1(sys32_futex, compat_sys_futex, %o1) | ||
83 | SIGN1(sys32_recvfrom, compat_sys_recvfrom, %o0) | ||
84 | SIGN1(sys32_recvmsg, compat_sys_recvmsg, %o0) | ||
85 | SIGN1(sys32_sendmsg, compat_sys_sendmsg, %o0) | ||
86 | +SIGN2(sys32_renameat2, sys_renameat2, %o0, %o2) | ||
87 | |||
88 | .globl sys32_mmap2 | ||
89 | sys32_mmap2: | ||
90 | diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S | ||
91 | index 151ace8766cc..85fe9b1087cd 100644 | ||
92 | --- a/arch/sparc/kernel/systbls_32.S | ||
93 | +++ b/arch/sparc/kernel/systbls_32.S | ||
94 | @@ -86,3 +86,4 @@ sys_call_table: | ||
95 | /*330*/ .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime | ||
96 | /*335*/ .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev | ||
97 | /*340*/ .long sys_ni_syscall, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr | ||
98 | +/*345*/ .long sys_renameat2 | ||
99 | diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S | ||
100 | index 4bd4e2bb26cf..33ecba2826ea 100644 | ||
101 | --- a/arch/sparc/kernel/systbls_64.S | ||
102 | +++ b/arch/sparc/kernel/systbls_64.S | ||
103 | @@ -87,6 +87,7 @@ sys_call_table32: | ||
104 | /*330*/ .word compat_sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime | ||
105 | .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev | ||
106 | /*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr | ||
107 | + .word sys32_renameat2 | ||
108 | |||
109 | #endif /* CONFIG_COMPAT */ | ||
110 | |||
111 | @@ -165,3 +166,4 @@ sys_call_table: | ||
112 | /*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime | ||
113 | .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev | ||
114 | /*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr | ||
115 | + .word sys_renameat2 | ||
116 | diff --git a/arch/sparc/math-emu/math_32.c b/arch/sparc/math-emu/math_32.c | ||
117 | index aa4d55b0bdf0..5ce8f2f64604 100644 | ||
118 | --- a/arch/sparc/math-emu/math_32.c | ||
119 | +++ b/arch/sparc/math-emu/math_32.c | ||
120 | @@ -499,7 +499,7 @@ static int do_one_mathemu(u32 insn, unsigned long *pfsr, unsigned long *fregs) | ||
121 | case 0: fsr = *pfsr; | ||
122 | if (IR == -1) IR = 2; | ||
123 | /* fcc is always fcc0 */ | ||
124 | - fsr &= ~0xc00; fsr |= (IR << 10); break; | ||
125 | + fsr &= ~0xc00; fsr |= (IR << 10); | ||
126 | *pfsr = fsr; | ||
127 | break; | ||
128 | case 1: rd->s = IR; break; | ||
129 | diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c | ||
130 | index ed3c969a5f4c..96862241b342 100644 | ||
131 | --- a/arch/sparc/mm/init_64.c | ||
132 | +++ b/arch/sparc/mm/init_64.c | ||
133 | @@ -350,6 +350,10 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t * | ||
134 | |||
135 | mm = vma->vm_mm; | ||
136 | |||
137 | + /* Don't insert a non-valid PTE into the TSB, we'll deadlock. */ | ||
138 | + if (!pte_accessible(mm, pte)) | ||
139 | + return; | ||
140 | + | ||
141 | spin_lock_irqsave(&mm->context.lock, flags); | ||
142 | |||
143 | #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) | ||
144 | @@ -2614,6 +2618,10 @@ void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, | ||
145 | |||
146 | pte = pmd_val(entry); | ||
147 | |||
148 | + /* Don't insert a non-valid PMD into the TSB, we'll deadlock. */ | ||
149 | + if (!(pte & _PAGE_VALID)) | ||
150 | + return; | ||
151 | + | ||
152 | /* We are fabricating 8MB pages using 4MB real hw pages. */ | ||
153 | pte |= (addr & (1UL << REAL_HPAGE_SHIFT)); | ||
154 | |||
155 | @@ -2694,3 +2702,26 @@ void hugetlb_setup(struct pt_regs *regs) | ||
156 | } | ||
157 | } | ||
158 | #endif | ||
159 | + | ||
160 | +#ifdef CONFIG_SMP | ||
161 | +#define do_flush_tlb_kernel_range smp_flush_tlb_kernel_range | ||
162 | +#else | ||
163 | +#define do_flush_tlb_kernel_range __flush_tlb_kernel_range | ||
164 | +#endif | ||
165 | + | ||
166 | +void flush_tlb_kernel_range(unsigned long start, unsigned long end) | ||
167 | +{ | ||
168 | + if (start < HI_OBP_ADDRESS && end > LOW_OBP_ADDRESS) { | ||
169 | + if (start < LOW_OBP_ADDRESS) { | ||
170 | + flush_tsb_kernel_range(start, LOW_OBP_ADDRESS); | ||
171 | + do_flush_tlb_kernel_range(start, LOW_OBP_ADDRESS); | ||
172 | + } | ||
173 | + if (end > HI_OBP_ADDRESS) { | ||
174 | + flush_tsb_kernel_range(end, HI_OBP_ADDRESS); | ||
175 | + do_flush_tlb_kernel_range(end, HI_OBP_ADDRESS); | ||
176 | + } | ||
177 | + } else { | ||
178 | + flush_tsb_kernel_range(start, end); | ||
179 | + do_flush_tlb_kernel_range(start, end); | ||
180 | + } | ||
181 | +} | ||
182 | diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | ||
183 | index 4d8f8aba0ea5..b87434c99f4d 100644 | ||
184 | --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | ||
185 | +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | ||
186 | @@ -346,6 +346,7 @@ struct sw_tx_bd { | ||
187 | u8 flags; | ||
188 | /* Set on the first BD descriptor when there is a split BD */ | ||
189 | #define BNX2X_TSO_SPLIT_BD (1<<0) | ||
190 | +#define BNX2X_HAS_SECOND_PBD (1<<1) | ||
191 | }; | ||
192 | |||
193 | struct sw_rx_page { | ||
194 | diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | ||
195 | index 0979967577a1..b2b0d2e684ef 100644 | ||
196 | --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | ||
197 | +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | ||
198 | @@ -227,6 +227,12 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, | ||
199 | --nbd; | ||
200 | bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); | ||
201 | |||
202 | + if (tx_buf->flags & BNX2X_HAS_SECOND_PBD) { | ||
203 | + /* Skip second parse bd... */ | ||
204 | + --nbd; | ||
205 | + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); | ||
206 | + } | ||
207 | + | ||
208 | /* TSO headers+data bds share a common mapping. See bnx2x_tx_split() */ | ||
209 | if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) { | ||
210 | tx_data_bd = &txdata->tx_desc_ring[bd_idx].reg_bd; | ||
211 | @@ -3877,6 +3883,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
212 | /* set encapsulation flag in start BD */ | ||
213 | SET_FLAG(tx_start_bd->general_data, | ||
214 | ETH_TX_START_BD_TUNNEL_EXIST, 1); | ||
215 | + | ||
216 | + tx_buf->flags |= BNX2X_HAS_SECOND_PBD; | ||
217 | + | ||
218 | nbd++; | ||
219 | } else if (xmit_type & XMIT_CSUM) { | ||
220 | /* Set PBD in checksum offload case w/o encapsulation */ | ||
221 | diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c | ||
222 | index 0966bd04375f..837224639148 100644 | ||
223 | --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c | ||
224 | +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c | ||
225 | @@ -1149,6 +1149,11 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) | ||
226 | goto out; | ||
227 | } | ||
228 | |||
229 | + if (skb_padto(skb, ETH_ZLEN)) { | ||
230 | + ret = NETDEV_TX_OK; | ||
231 | + goto out; | ||
232 | + } | ||
233 | + | ||
234 | /* set the SKB transmit checksum */ | ||
235 | if (priv->desc_64b_en) { | ||
236 | ret = bcmgenet_put_tx_csum(dev, skb); | ||
237 | diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c | ||
238 | index 675550fe8ee9..ac1ebe0374be 100644 | ||
239 | --- a/drivers/net/ethernet/brocade/bna/bnad.c | ||
240 | +++ b/drivers/net/ethernet/brocade/bna/bnad.c | ||
241 | @@ -600,9 +600,9 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget) | ||
242 | prefetch(bnad->netdev); | ||
243 | |||
244 | cq = ccb->sw_q; | ||
245 | - cmpl = &cq[ccb->producer_index]; | ||
246 | |||
247 | while (packets < budget) { | ||
248 | + cmpl = &cq[ccb->producer_index]; | ||
249 | if (!cmpl->valid) | ||
250 | break; | ||
251 | /* The 'valid' field is set by the adapter, only after writing | ||
252 | diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c | ||
253 | index 7eec598c5cb6..d650b911dae4 100644 | ||
254 | --- a/drivers/net/macvlan.c | ||
255 | +++ b/drivers/net/macvlan.c | ||
256 | @@ -547,6 +547,7 @@ static int macvlan_init(struct net_device *dev) | ||
257 | (lowerdev->state & MACVLAN_STATE_MASK); | ||
258 | dev->features = lowerdev->features & MACVLAN_FEATURES; | ||
259 | dev->features |= ALWAYS_ON_FEATURES; | ||
260 | + dev->vlan_features = lowerdev->vlan_features & MACVLAN_FEATURES; | ||
261 | dev->gso_max_size = lowerdev->gso_max_size; | ||
262 | dev->iflink = lowerdev->ifindex; | ||
263 | dev->hard_header_len = lowerdev->hard_header_len; | ||
264 | diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c | ||
265 | index 4987a1c6dc52..b96c4a226624 100644 | ||
266 | --- a/drivers/net/phy/phy_device.c | ||
267 | +++ b/drivers/net/phy/phy_device.c | ||
268 | @@ -354,7 +354,7 @@ int phy_device_register(struct phy_device *phydev) | ||
269 | phydev->bus->phy_map[phydev->addr] = phydev; | ||
270 | |||
271 | /* Run all of the fixups for this PHY */ | ||
272 | - err = phy_init_hw(phydev); | ||
273 | + err = phy_scan_fixups(phydev); | ||
274 | if (err) { | ||
275 | pr_err("PHY %d failed to initialize\n", phydev->addr); | ||
276 | goto out; | ||
277 | diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c | ||
278 | index 01805319e1e0..1aff970be33e 100644 | ||
279 | --- a/drivers/net/ppp/pptp.c | ||
280 | +++ b/drivers/net/ppp/pptp.c | ||
281 | @@ -281,7 +281,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) | ||
282 | nf_reset(skb); | ||
283 | |||
284 | skb->ip_summed = CHECKSUM_NONE; | ||
285 | - ip_select_ident(skb, &rt->dst, NULL); | ||
286 | + ip_select_ident(skb, NULL); | ||
287 | ip_send_check(iph); | ||
288 | |||
289 | ip_local_out(skb); | ||
290 | diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c | ||
291 | index 160e7510aca6..0787b9756165 100644 | ||
292 | --- a/drivers/sbus/char/bbc_envctrl.c | ||
293 | +++ b/drivers/sbus/char/bbc_envctrl.c | ||
294 | @@ -452,6 +452,9 @@ static void attach_one_temp(struct bbc_i2c_bus *bp, struct platform_device *op, | ||
295 | if (!tp) | ||
296 | return; | ||
297 | |||
298 | + INIT_LIST_HEAD(&tp->bp_list); | ||
299 | + INIT_LIST_HEAD(&tp->glob_list); | ||
300 | + | ||
301 | tp->client = bbc_i2c_attach(bp, op); | ||
302 | if (!tp->client) { | ||
303 | kfree(tp); | ||
304 | @@ -497,6 +500,9 @@ static void attach_one_fan(struct bbc_i2c_bus *bp, struct platform_device *op, | ||
305 | if (!fp) | ||
306 | return; | ||
307 | |||
308 | + INIT_LIST_HEAD(&fp->bp_list); | ||
309 | + INIT_LIST_HEAD(&fp->glob_list); | ||
310 | + | ||
311 | fp->client = bbc_i2c_attach(bp, op); | ||
312 | if (!fp->client) { | ||
313 | kfree(fp); | ||
314 | diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c | ||
315 | index c7763e482eb2..812b5f0361b6 100644 | ||
316 | --- a/drivers/sbus/char/bbc_i2c.c | ||
317 | +++ b/drivers/sbus/char/bbc_i2c.c | ||
318 | @@ -300,13 +300,18 @@ static struct bbc_i2c_bus * attach_one_i2c(struct platform_device *op, int index | ||
319 | if (!bp) | ||
320 | return NULL; | ||
321 | |||
322 | + INIT_LIST_HEAD(&bp->temps); | ||
323 | + INIT_LIST_HEAD(&bp->fans); | ||
324 | + | ||
325 | bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs"); | ||
326 | if (!bp->i2c_control_regs) | ||
327 | goto fail; | ||
328 | |||
329 | - bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel"); | ||
330 | - if (!bp->i2c_bussel_reg) | ||
331 | - goto fail; | ||
332 | + if (op->num_resources == 2) { | ||
333 | + bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel"); | ||
334 | + if (!bp->i2c_bussel_reg) | ||
335 | + goto fail; | ||
336 | + } | ||
337 | |||
338 | bp->waiting = 0; | ||
339 | init_waitqueue_head(&bp->wq); | ||
340 | diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c | ||
341 | index 2f57df9a71d9..a1e09c0d46f2 100644 | ||
342 | --- a/drivers/tty/serial/sunsab.c | ||
343 | +++ b/drivers/tty/serial/sunsab.c | ||
344 | @@ -157,6 +157,15 @@ receive_chars(struct uart_sunsab_port *up, | ||
345 | (up->port.line == up->port.cons->index)) | ||
346 | saw_console_brk = 1; | ||
347 | |||
348 | + if (count == 0) { | ||
349 | + if (unlikely(stat->sreg.isr1 & SAB82532_ISR1_BRK)) { | ||
350 | + stat->sreg.isr0 &= ~(SAB82532_ISR0_PERR | | ||
351 | + SAB82532_ISR0_FERR); | ||
352 | + up->port.icount.brk++; | ||
353 | + uart_handle_break(&up->port); | ||
354 | + } | ||
355 | + } | ||
356 | + | ||
357 | for (i = 0; i < count; i++) { | ||
358 | unsigned char ch = buf[i], flag; | ||
359 | |||
360 | diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h | ||
361 | index 2c4004475e71..84e0deb95abd 100644 | ||
362 | --- a/fs/xfs/xfs_log.h | ||
363 | +++ b/fs/xfs/xfs_log.h | ||
364 | @@ -24,7 +24,8 @@ struct xfs_log_vec { | ||
365 | struct xfs_log_iovec *lv_iovecp; /* iovec array */ | ||
366 | struct xfs_log_item *lv_item; /* owner */ | ||
367 | char *lv_buf; /* formatted buffer */ | ||
368 | - int lv_buf_len; /* size of formatted buffer */ | ||
369 | + int lv_bytes; /* accounted space in buffer */ | ||
370 | + int lv_buf_len; /* aligned size of buffer */ | ||
371 | int lv_size; /* size of allocated lv */ | ||
372 | }; | ||
373 | |||
374 | @@ -52,15 +53,21 @@ xlog_prepare_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec **vecp, | ||
375 | return vec->i_addr; | ||
376 | } | ||
377 | |||
378 | +/* | ||
379 | + * We need to make sure the next buffer is naturally aligned for the biggest | ||
380 | + * basic data type we put into it. We already accounted for this padding when | ||
381 | + * sizing the buffer. | ||
382 | + * | ||
383 | + * However, this padding does not get written into the log, and hence we have to | ||
384 | + * track the space used by the log vectors separately to prevent log space hangs | ||
385 | + * due to inaccurate accounting (i.e. a leak) of the used log space through the | ||
386 | + * CIL context ticket. | ||
387 | + */ | ||
388 | static inline void | ||
389 | xlog_finish_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec *vec, int len) | ||
390 | { | ||
391 | - /* | ||
392 | - * We need to make sure the next buffer is naturally aligned for the | ||
393 | - * biggest basic data type we put into it. We already accounted for | ||
394 | - * this when sizing the buffer. | ||
395 | - */ | ||
396 | lv->lv_buf_len += round_up(len, sizeof(uint64_t)); | ||
397 | + lv->lv_bytes += len; | ||
398 | vec->i_len = len; | ||
399 | } | ||
400 | |||
401 | diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c | ||
402 | index 7e5455391176..de835da6764d 100644 | ||
403 | --- a/fs/xfs/xfs_log_cil.c | ||
404 | +++ b/fs/xfs/xfs_log_cil.c | ||
405 | @@ -97,7 +97,7 @@ xfs_cil_prepare_item( | ||
406 | { | ||
407 | /* Account for the new LV being passed in */ | ||
408 | if (lv->lv_buf_len != XFS_LOG_VEC_ORDERED) { | ||
409 | - *diff_len += lv->lv_buf_len; | ||
410 | + *diff_len += lv->lv_bytes; | ||
411 | *diff_iovecs += lv->lv_niovecs; | ||
412 | } | ||
413 | |||
414 | @@ -111,7 +111,7 @@ xfs_cil_prepare_item( | ||
415 | else if (old_lv != lv) { | ||
416 | ASSERT(lv->lv_buf_len != XFS_LOG_VEC_ORDERED); | ||
417 | |||
418 | - *diff_len -= old_lv->lv_buf_len; | ||
419 | + *diff_len -= old_lv->lv_bytes; | ||
420 | *diff_iovecs -= old_lv->lv_niovecs; | ||
421 | kmem_free(old_lv); | ||
422 | } | ||
423 | @@ -239,7 +239,7 @@ xlog_cil_insert_format_items( | ||
424 | * that the space reservation accounting is correct. | ||
425 | */ | ||
426 | *diff_iovecs -= lv->lv_niovecs; | ||
427 | - *diff_len -= lv->lv_buf_len; | ||
428 | + *diff_len -= lv->lv_bytes; | ||
429 | } else { | ||
430 | /* allocate new data chunk */ | ||
431 | lv = kmem_zalloc(buf_size, KM_SLEEP|KM_NOFS); | ||
432 | @@ -259,6 +259,7 @@ xlog_cil_insert_format_items( | ||
433 | |||
434 | /* The allocated data region lies beyond the iovec region */ | ||
435 | lv->lv_buf_len = 0; | ||
436 | + lv->lv_bytes = 0; | ||
437 | lv->lv_buf = (char *)lv + buf_size - nbytes; | ||
438 | ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t))); | ||
439 | |||
440 | diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h | ||
441 | index 058271bde27a..823ec7bb9c67 100644 | ||
442 | --- a/include/net/inetpeer.h | ||
443 | +++ b/include/net/inetpeer.h | ||
444 | @@ -41,14 +41,13 @@ struct inet_peer { | ||
445 | struct rcu_head gc_rcu; | ||
446 | }; | ||
447 | /* | ||
448 | - * Once inet_peer is queued for deletion (refcnt == -1), following fields | ||
449 | - * are not available: rid, ip_id_count | ||
450 | + * Once inet_peer is queued for deletion (refcnt == -1), following field | ||
451 | + * is not available: rid | ||
452 | * We can share memory with rcu_head to help keep inet_peer small. | ||
453 | */ | ||
454 | union { | ||
455 | struct { | ||
456 | atomic_t rid; /* Frag reception counter */ | ||
457 | - atomic_t ip_id_count; /* IP ID for the next packet */ | ||
458 | }; | ||
459 | struct rcu_head rcu; | ||
460 | struct inet_peer *gc_next; | ||
461 | @@ -165,7 +164,7 @@ bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); | ||
462 | void inetpeer_invalidate_tree(struct inet_peer_base *); | ||
463 | |||
464 | /* | ||
465 | - * temporary check to make sure we dont access rid, ip_id_count, tcp_ts, | ||
466 | + * temporary check to make sure we dont access rid, tcp_ts, | ||
467 | * tcp_ts_stamp if no refcount is taken on inet_peer | ||
468 | */ | ||
469 | static inline void inet_peer_refcheck(const struct inet_peer *p) | ||
470 | @@ -173,13 +172,4 @@ static inline void inet_peer_refcheck(const struct inet_peer *p) | ||
471 | WARN_ON_ONCE(atomic_read(&p->refcnt) <= 0); | ||
472 | } | ||
473 | |||
474 | - | ||
475 | -/* can be called with or without local BH being disabled */ | ||
476 | -static inline int inet_getid(struct inet_peer *p, int more) | ||
477 | -{ | ||
478 | - more++; | ||
479 | - inet_peer_refcheck(p); | ||
480 | - return atomic_add_return(more, &p->ip_id_count) - more; | ||
481 | -} | ||
482 | - | ||
483 | #endif /* _NET_INETPEER_H */ | ||
484 | diff --git a/include/net/ip.h b/include/net/ip.h | ||
485 | index 3ec2b0fb9d83..54de0292ac53 100644 | ||
486 | --- a/include/net/ip.h | ||
487 | +++ b/include/net/ip.h | ||
488 | @@ -310,9 +310,10 @@ static inline unsigned int ip_skb_dst_mtu(const struct sk_buff *skb) | ||
489 | } | ||
490 | } | ||
491 | |||
492 | -void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more); | ||
493 | +u32 ip_idents_reserve(u32 hash, int segs); | ||
494 | +void __ip_select_ident(struct iphdr *iph, int segs); | ||
495 | |||
496 | -static inline void ip_select_ident(struct sk_buff *skb, struct dst_entry *dst, struct sock *sk) | ||
497 | +static inline void ip_select_ident_segs(struct sk_buff *skb, struct sock *sk, int segs) | ||
498 | { | ||
499 | struct iphdr *iph = ip_hdr(skb); | ||
500 | |||
501 | @@ -322,24 +323,20 @@ static inline void ip_select_ident(struct sk_buff *skb, struct dst_entry *dst, s | ||
502 | * does not change, they drop every other packet in | ||
503 | * a TCP stream using header compression. | ||
504 | */ | ||
505 | - iph->id = (sk && inet_sk(sk)->inet_daddr) ? | ||
506 | - htons(inet_sk(sk)->inet_id++) : 0; | ||
507 | - } else | ||
508 | - __ip_select_ident(iph, dst, 0); | ||
509 | -} | ||
510 | - | ||
511 | -static inline void ip_select_ident_more(struct sk_buff *skb, struct dst_entry *dst, struct sock *sk, int more) | ||
512 | -{ | ||
513 | - struct iphdr *iph = ip_hdr(skb); | ||
514 | - | ||
515 | - if ((iph->frag_off & htons(IP_DF)) && !skb->local_df) { | ||
516 | if (sk && inet_sk(sk)->inet_daddr) { | ||
517 | iph->id = htons(inet_sk(sk)->inet_id); | ||
518 | - inet_sk(sk)->inet_id += 1 + more; | ||
519 | - } else | ||
520 | + inet_sk(sk)->inet_id += segs; | ||
521 | + } else { | ||
522 | iph->id = 0; | ||
523 | - } else | ||
524 | - __ip_select_ident(iph, dst, more); | ||
525 | + } | ||
526 | + } else { | ||
527 | + __ip_select_ident(iph, segs); | ||
528 | + } | ||
529 | +} | ||
530 | + | ||
531 | +static inline void ip_select_ident(struct sk_buff *skb, struct sock *sk) | ||
532 | +{ | ||
533 | + ip_select_ident_segs(skb, sk, 1); | ||
534 | } | ||
535 | |||
536 | /* | ||
537 | diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h | ||
538 | index a4daf9eb8562..8dd8cab88b87 100644 | ||
539 | --- a/include/net/ip_tunnels.h | ||
540 | +++ b/include/net/ip_tunnels.h | ||
541 | @@ -40,6 +40,7 @@ struct ip_tunnel_prl_entry { | ||
542 | |||
543 | struct ip_tunnel_dst { | ||
544 | struct dst_entry __rcu *dst; | ||
545 | + __be32 saddr; | ||
546 | }; | ||
547 | |||
548 | struct ip_tunnel { | ||
549 | diff --git a/include/net/ipv6.h b/include/net/ipv6.h | ||
550 | index d640925bc454..d6815688ad9e 100644 | ||
551 | --- a/include/net/ipv6.h | ||
552 | +++ b/include/net/ipv6.h | ||
553 | @@ -660,8 +660,6 @@ static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_add | ||
554 | return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); | ||
555 | } | ||
556 | |||
557 | -void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt); | ||
558 | - | ||
559 | int ip6_dst_hoplimit(struct dst_entry *dst); | ||
560 | |||
561 | /* | ||
562 | diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h | ||
563 | index f257486f17be..3f36d45b714a 100644 | ||
564 | --- a/include/net/secure_seq.h | ||
565 | +++ b/include/net/secure_seq.h | ||
566 | @@ -3,8 +3,6 @@ | ||
567 | |||
568 | #include <linux/types.h> | ||
569 | |||
570 | -__u32 secure_ip_id(__be32 daddr); | ||
571 | -__u32 secure_ipv6_id(const __be32 daddr[4]); | ||
572 | u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport); | ||
573 | u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, | ||
574 | __be16 dport); | ||
575 | diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c | ||
576 | index f14e54a05691..022d18ab27a6 100644 | ||
577 | --- a/net/batman-adv/fragmentation.c | ||
578 | +++ b/net/batman-adv/fragmentation.c | ||
579 | @@ -128,6 +128,7 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, | ||
580 | { | ||
581 | struct batadv_frag_table_entry *chain; | ||
582 | struct batadv_frag_list_entry *frag_entry_new = NULL, *frag_entry_curr; | ||
583 | + struct batadv_frag_list_entry *frag_entry_last = NULL; | ||
584 | struct batadv_frag_packet *frag_packet; | ||
585 | uint8_t bucket; | ||
586 | uint16_t seqno, hdr_size = sizeof(struct batadv_frag_packet); | ||
587 | @@ -180,11 +181,14 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, | ||
588 | ret = true; | ||
589 | goto out; | ||
590 | } | ||
591 | + | ||
592 | + /* store current entry because it could be the last in list */ | ||
593 | + frag_entry_last = frag_entry_curr; | ||
594 | } | ||
595 | |||
596 | - /* Reached the end of the list, so insert after 'frag_entry_curr'. */ | ||
597 | - if (likely(frag_entry_curr)) { | ||
598 | - hlist_add_after(&frag_entry_curr->list, &frag_entry_new->list); | ||
599 | + /* Reached the end of the list, so insert after 'frag_entry_last'. */ | ||
600 | + if (likely(frag_entry_last)) { | ||
601 | + hlist_add_after(&frag_entry_last->list, &frag_entry_new->list); | ||
602 | chain->size += skb->len - hdr_size; | ||
603 | chain->timestamp = jiffies; | ||
604 | ret = true; | ||
605 | diff --git a/net/compat.c b/net/compat.c | ||
606 | index 9a76eaf63184..bc8aeefddf3f 100644 | ||
607 | --- a/net/compat.c | ||
608 | +++ b/net/compat.c | ||
609 | @@ -85,7 +85,7 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, | ||
610 | { | ||
611 | int tot_len; | ||
612 | |||
613 | - if (kern_msg->msg_namelen) { | ||
614 | + if (kern_msg->msg_name && kern_msg->msg_namelen) { | ||
615 | if (mode == VERIFY_READ) { | ||
616 | int err = move_addr_to_kernel(kern_msg->msg_name, | ||
617 | kern_msg->msg_namelen, | ||
618 | @@ -93,10 +93,11 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, | ||
619 | if (err < 0) | ||
620 | return err; | ||
621 | } | ||
622 | - if (kern_msg->msg_name) | ||
623 | - kern_msg->msg_name = kern_address; | ||
624 | - } else | ||
625 | + kern_msg->msg_name = kern_address; | ||
626 | + } else { | ||
627 | kern_msg->msg_name = NULL; | ||
628 | + kern_msg->msg_namelen = 0; | ||
629 | + } | ||
630 | |||
631 | tot_len = iov_from_user_compat_to_kern(kern_iov, | ||
632 | (struct compat_iovec __user *)kern_msg->msg_iov, | ||
633 | diff --git a/net/core/iovec.c b/net/core/iovec.c | ||
634 | index b61869429f4c..26dc0062652f 100644 | ||
635 | --- a/net/core/iovec.c | ||
636 | +++ b/net/core/iovec.c | ||
637 | @@ -39,7 +39,7 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a | ||
638 | { | ||
639 | int size, ct, err; | ||
640 | |||
641 | - if (m->msg_namelen) { | ||
642 | + if (m->msg_name && m->msg_namelen) { | ||
643 | if (mode == VERIFY_READ) { | ||
644 | void __user *namep; | ||
645 | namep = (void __user __force *) m->msg_name; | ||
646 | @@ -48,10 +48,10 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a | ||
647 | if (err < 0) | ||
648 | return err; | ||
649 | } | ||
650 | - if (m->msg_name) | ||
651 | - m->msg_name = address; | ||
652 | + m->msg_name = address; | ||
653 | } else { | ||
654 | m->msg_name = NULL; | ||
655 | + m->msg_namelen = 0; | ||
656 | } | ||
657 | |||
658 | size = m->msg_iovlen * sizeof(struct iovec); | ||
659 | @@ -107,6 +107,10 @@ EXPORT_SYMBOL(memcpy_toiovecend); | ||
660 | int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, | ||
661 | int offset, int len) | ||
662 | { | ||
663 | + /* No data? Done! */ | ||
664 | + if (len == 0) | ||
665 | + return 0; | ||
666 | + | ||
667 | /* Skip over the finished iovecs */ | ||
668 | while (offset >= iov->iov_len) { | ||
669 | offset -= iov->iov_len; | ||
670 | diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c | ||
671 | index 897da56f3aff..ba71212f0251 100644 | ||
672 | --- a/net/core/secure_seq.c | ||
673 | +++ b/net/core/secure_seq.c | ||
674 | @@ -85,31 +85,6 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral); | ||
675 | #endif | ||
676 | |||
677 | #ifdef CONFIG_INET | ||
678 | -__u32 secure_ip_id(__be32 daddr) | ||
679 | -{ | ||
680 | - u32 hash[MD5_DIGEST_WORDS]; | ||
681 | - | ||
682 | - net_secret_init(); | ||
683 | - hash[0] = (__force __u32) daddr; | ||
684 | - hash[1] = net_secret[13]; | ||
685 | - hash[2] = net_secret[14]; | ||
686 | - hash[3] = net_secret[15]; | ||
687 | - | ||
688 | - md5_transform(hash, net_secret); | ||
689 | - | ||
690 | - return hash[0]; | ||
691 | -} | ||
692 | - | ||
693 | -__u32 secure_ipv6_id(const __be32 daddr[4]) | ||
694 | -{ | ||
695 | - __u32 hash[4]; | ||
696 | - | ||
697 | - net_secret_init(); | ||
698 | - memcpy(hash, daddr, 16); | ||
699 | - md5_transform(hash, net_secret); | ||
700 | - | ||
701 | - return hash[0]; | ||
702 | -} | ||
703 | |||
704 | __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, | ||
705 | __be16 sport, __be16 dport) | ||
706 | diff --git a/net/core/skbuff.c b/net/core/skbuff.c | ||
707 | index 9433047b2453..6ab5f7721cdb 100644 | ||
708 | --- a/net/core/skbuff.c | ||
709 | +++ b/net/core/skbuff.c | ||
710 | @@ -2968,9 +2968,9 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, | ||
711 | tail = nskb; | ||
712 | |||
713 | __copy_skb_header(nskb, head_skb); | ||
714 | - nskb->mac_len = head_skb->mac_len; | ||
715 | |||
716 | skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom); | ||
717 | + skb_reset_mac_len(nskb); | ||
718 | |||
719 | skb_copy_from_linear_data_offset(head_skb, -tnl_hlen, | ||
720 | nskb->data - tnl_hlen, | ||
721 | diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c | ||
722 | index 9db3b877fcaf..0ffcd4d64e0a 100644 | ||
723 | --- a/net/ipv4/igmp.c | ||
724 | +++ b/net/ipv4/igmp.c | ||
725 | @@ -369,7 +369,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) | ||
726 | pip->saddr = fl4.saddr; | ||
727 | pip->protocol = IPPROTO_IGMP; | ||
728 | pip->tot_len = 0; /* filled in later */ | ||
729 | - ip_select_ident(skb, &rt->dst, NULL); | ||
730 | + ip_select_ident(skb, NULL); | ||
731 | ((u8 *)&pip[1])[0] = IPOPT_RA; | ||
732 | ((u8 *)&pip[1])[1] = 4; | ||
733 | ((u8 *)&pip[1])[2] = 0; | ||
734 | @@ -714,7 +714,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, | ||
735 | iph->daddr = dst; | ||
736 | iph->saddr = fl4.saddr; | ||
737 | iph->protocol = IPPROTO_IGMP; | ||
738 | - ip_select_ident(skb, &rt->dst, NULL); | ||
739 | + ip_select_ident(skb, NULL); | ||
740 | ((u8 *)&iph[1])[0] = IPOPT_RA; | ||
741 | ((u8 *)&iph[1])[1] = 4; | ||
742 | ((u8 *)&iph[1])[2] = 0; | ||
743 | diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c | ||
744 | index 48f424465112..bf2cb4a4714b 100644 | ||
745 | --- a/net/ipv4/inetpeer.c | ||
746 | +++ b/net/ipv4/inetpeer.c | ||
747 | @@ -26,20 +26,7 @@ | ||
748 | * Theory of operations. | ||
749 | * We keep one entry for each peer IP address. The nodes contains long-living | ||
750 | * information about the peer which doesn't depend on routes. | ||
751 | - * At this moment this information consists only of ID field for the next | ||
752 | - * outgoing IP packet. This field is incremented with each packet as encoded | ||
753 | - * in inet_getid() function (include/net/inetpeer.h). | ||
754 | - * At the moment of writing this notes identifier of IP packets is generated | ||
755 | - * to be unpredictable using this code only for packets subjected | ||
756 | - * (actually or potentially) to defragmentation. I.e. DF packets less than | ||
757 | - * PMTU in size when local fragmentation is disabled use a constant ID and do | ||
758 | - * not use this code (see ip_select_ident() in include/net/ip.h). | ||
759 | * | ||
760 | - * Route cache entries hold references to our nodes. | ||
761 | - * New cache entries get references via lookup by destination IP address in | ||
762 | - * the avl tree. The reference is grabbed only when it's needed i.e. only | ||
763 | - * when we try to output IP packet which needs an unpredictable ID (see | ||
764 | - * __ip_select_ident() in net/ipv4/route.c). | ||
765 | * Nodes are removed only when reference counter goes to 0. | ||
766 | * When it's happened the node may be removed when a sufficient amount of | ||
767 | * time has been passed since its last use. The less-recently-used entry can | ||
768 | @@ -62,7 +49,6 @@ | ||
769 | * refcnt: atomically against modifications on other CPU; | ||
770 | * usually under some other lock to prevent node disappearing | ||
771 | * daddr: unchangeable | ||
772 | - * ip_id_count: atomic value (no lock needed) | ||
773 | */ | ||
774 | |||
775 | static struct kmem_cache *peer_cachep __read_mostly; | ||
776 | @@ -497,10 +483,6 @@ relookup: | ||
777 | p->daddr = *daddr; | ||
778 | atomic_set(&p->refcnt, 1); | ||
779 | atomic_set(&p->rid, 0); | ||
780 | - atomic_set(&p->ip_id_count, | ||
781 | - (daddr->family == AF_INET) ? | ||
782 | - secure_ip_id(daddr->addr.a4) : | ||
783 | - secure_ipv6_id(daddr->addr.a6)); | ||
784 | p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW; | ||
785 | p->rate_tokens = 0; | ||
786 | /* 60*HZ is arbitrary, but chosen enough high so that the first | ||
787 | diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c | ||
788 | index a52f50187b54..4ecc1600f84d 100644 | ||
789 | --- a/net/ipv4/ip_output.c | ||
790 | +++ b/net/ipv4/ip_output.c | ||
791 | @@ -148,7 +148,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, | ||
792 | iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr); | ||
793 | iph->saddr = saddr; | ||
794 | iph->protocol = sk->sk_protocol; | ||
795 | - ip_select_ident(skb, &rt->dst, sk); | ||
796 | + ip_select_ident(skb, sk); | ||
797 | |||
798 | if (opt && opt->opt.optlen) { | ||
799 | iph->ihl += opt->opt.optlen>>2; | ||
800 | @@ -430,8 +430,7 @@ packet_routed: | ||
801 | ip_options_build(skb, &inet_opt->opt, inet->inet_daddr, rt, 0); | ||
802 | } | ||
803 | |||
804 | - ip_select_ident_more(skb, &rt->dst, sk, | ||
805 | - (skb_shinfo(skb)->gso_segs ?: 1) - 1); | ||
806 | + ip_select_ident_segs(skb, sk, skb_shinfo(skb)->gso_segs ?: 1); | ||
807 | |||
808 | /* TODO : should we use skb->sk here instead of sk ? */ | ||
809 | skb->priority = sk->sk_priority; | ||
810 | @@ -1379,7 +1378,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk, | ||
811 | iph->ttl = ttl; | ||
812 | iph->protocol = sk->sk_protocol; | ||
813 | ip_copy_addrs(iph, fl4); | ||
814 | - ip_select_ident(skb, &rt->dst, sk); | ||
815 | + ip_select_ident(skb, sk); | ||
816 | |||
817 | if (opt) { | ||
818 | iph->ihl += opt->optlen>>2; | ||
819 | diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c | ||
820 | index b77b6a55b05e..e3e3a91f249e 100644 | ||
821 | --- a/net/ipv4/ip_tunnel.c | ||
822 | +++ b/net/ipv4/ip_tunnel.c | ||
823 | @@ -69,23 +69,25 @@ static unsigned int ip_tunnel_hash(__be32 key, __be32 remote) | ||
824 | } | ||
825 | |||
826 | static void __tunnel_dst_set(struct ip_tunnel_dst *idst, | ||
827 | - struct dst_entry *dst) | ||
828 | + struct dst_entry *dst, __be32 saddr) | ||
829 | { | ||
830 | struct dst_entry *old_dst; | ||
831 | |||
832 | dst_clone(dst); | ||
833 | old_dst = xchg((__force struct dst_entry **)&idst->dst, dst); | ||
834 | dst_release(old_dst); | ||
835 | + idst->saddr = saddr; | ||
836 | } | ||
837 | |||
838 | -static void tunnel_dst_set(struct ip_tunnel *t, struct dst_entry *dst) | ||
839 | +static void tunnel_dst_set(struct ip_tunnel *t, | ||
840 | + struct dst_entry *dst, __be32 saddr) | ||
841 | { | ||
842 | - __tunnel_dst_set(this_cpu_ptr(t->dst_cache), dst); | ||
843 | + __tunnel_dst_set(this_cpu_ptr(t->dst_cache), dst, saddr); | ||
844 | } | ||
845 | |||
846 | static void tunnel_dst_reset(struct ip_tunnel *t) | ||
847 | { | ||
848 | - tunnel_dst_set(t, NULL); | ||
849 | + tunnel_dst_set(t, NULL, 0); | ||
850 | } | ||
851 | |||
852 | void ip_tunnel_dst_reset_all(struct ip_tunnel *t) | ||
853 | @@ -93,20 +95,25 @@ void ip_tunnel_dst_reset_all(struct ip_tunnel *t) | ||
854 | int i; | ||
855 | |||
856 | for_each_possible_cpu(i) | ||
857 | - __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL); | ||
858 | + __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL, 0); | ||
859 | } | ||
860 | EXPORT_SYMBOL(ip_tunnel_dst_reset_all); | ||
861 | |||
862 | -static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, u32 cookie) | ||
863 | +static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, | ||
864 | + u32 cookie, __be32 *saddr) | ||
865 | { | ||
866 | + struct ip_tunnel_dst *idst; | ||
867 | struct dst_entry *dst; | ||
868 | |||
869 | rcu_read_lock(); | ||
870 | - dst = rcu_dereference(this_cpu_ptr(t->dst_cache)->dst); | ||
871 | + idst = this_cpu_ptr(t->dst_cache); | ||
872 | + dst = rcu_dereference(idst->dst); | ||
873 | if (dst && !atomic_inc_not_zero(&dst->__refcnt)) | ||
874 | dst = NULL; | ||
875 | if (dst) { | ||
876 | - if (dst->obsolete && dst->ops->check(dst, cookie) == NULL) { | ||
877 | + if (!dst->obsolete || dst->ops->check(dst, cookie)) { | ||
878 | + *saddr = idst->saddr; | ||
879 | + } else { | ||
880 | tunnel_dst_reset(t); | ||
881 | dst_release(dst); | ||
882 | dst = NULL; | ||
883 | @@ -366,7 +373,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev) | ||
884 | |||
885 | if (!IS_ERR(rt)) { | ||
886 | tdev = rt->dst.dev; | ||
887 | - tunnel_dst_set(tunnel, &rt->dst); | ||
888 | + tunnel_dst_set(tunnel, &rt->dst, fl4.saddr); | ||
889 | ip_rt_put(rt); | ||
890 | } | ||
891 | if (dev->type != ARPHRD_ETHER) | ||
892 | @@ -610,7 +617,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | ||
893 | init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, | ||
894 | tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); | ||
895 | |||
896 | - rt = connected ? tunnel_rtable_get(tunnel, 0) : NULL; | ||
897 | + rt = connected ? tunnel_rtable_get(tunnel, 0, &fl4.saddr) : NULL; | ||
898 | |||
899 | if (!rt) { | ||
900 | rt = ip_route_output_key(tunnel->net, &fl4); | ||
901 | @@ -620,7 +627,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, | ||
902 | goto tx_error; | ||
903 | } | ||
904 | if (connected) | ||
905 | - tunnel_dst_set(tunnel, &rt->dst); | ||
906 | + tunnel_dst_set(tunnel, &rt->dst, fl4.saddr); | ||
907 | } | ||
908 | |||
909 | if (rt->dst.dev == dev) { | ||
910 | diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c | ||
911 | index bcf206c79005..847e69cbff7e 100644 | ||
912 | --- a/net/ipv4/ip_tunnel_core.c | ||
913 | +++ b/net/ipv4/ip_tunnel_core.c | ||
914 | @@ -74,7 +74,7 @@ int iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb, | ||
915 | iph->daddr = dst; | ||
916 | iph->saddr = src; | ||
917 | iph->ttl = ttl; | ||
918 | - __ip_select_ident(iph, &rt->dst, (skb_shinfo(skb)->gso_segs ?: 1) - 1); | ||
919 | + __ip_select_ident(iph, skb_shinfo(skb)->gso_segs ?: 1); | ||
920 | |||
921 | err = ip_local_out_sk(sk, skb); | ||
922 | if (unlikely(net_xmit_eval(err))) | ||
923 | diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c | ||
924 | index d84dc8d4c916..d11a50d24295 100644 | ||
925 | --- a/net/ipv4/ipmr.c | ||
926 | +++ b/net/ipv4/ipmr.c | ||
927 | @@ -1663,7 +1663,7 @@ static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr) | ||
928 | iph->protocol = IPPROTO_IPIP; | ||
929 | iph->ihl = 5; | ||
930 | iph->tot_len = htons(skb->len); | ||
931 | - ip_select_ident(skb, skb_dst(skb), NULL); | ||
932 | + ip_select_ident(skb, NULL); | ||
933 | ip_send_check(iph); | ||
934 | |||
935 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | ||
936 | diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c | ||
937 | index a9dbe58bdfe7..2c65160565e1 100644 | ||
938 | --- a/net/ipv4/raw.c | ||
939 | +++ b/net/ipv4/raw.c | ||
940 | @@ -389,7 +389,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, | ||
941 | iph->check = 0; | ||
942 | iph->tot_len = htons(length); | ||
943 | if (!iph->id) | ||
944 | - ip_select_ident(skb, &rt->dst, NULL); | ||
945 | + ip_select_ident(skb, NULL); | ||
946 | |||
947 | iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); | ||
948 | } | ||
949 | diff --git a/net/ipv4/route.c b/net/ipv4/route.c | ||
950 | index be9f2b1ac3ab..fd618d48f4ce 100644 | ||
951 | --- a/net/ipv4/route.c | ||
952 | +++ b/net/ipv4/route.c | ||
953 | @@ -89,6 +89,7 @@ | ||
954 | #include <linux/rcupdate.h> | ||
955 | #include <linux/times.h> | ||
956 | #include <linux/slab.h> | ||
957 | +#include <linux/jhash.h> | ||
958 | #include <net/dst.h> | ||
959 | #include <net/net_namespace.h> | ||
960 | #include <net/protocol.h> | ||
961 | @@ -456,39 +457,45 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, | ||
962 | return neigh_create(&arp_tbl, pkey, dev); | ||
963 | } | ||
964 | |||
965 | -/* | ||
966 | - * Peer allocation may fail only in serious out-of-memory conditions. However | ||
967 | - * we still can generate some output. | ||
968 | - * Random ID selection looks a bit dangerous because we have no chances to | ||
969 | - * select ID being unique in a reasonable period of time. | ||
970 | - * But broken packet identifier may be better than no packet at all. | ||
971 | +#define IP_IDENTS_SZ 2048u | ||
972 | +struct ip_ident_bucket { | ||
973 | + atomic_t id; | ||
974 | + u32 stamp32; | ||
975 | +}; | ||
976 | + | ||
977 | +static struct ip_ident_bucket *ip_idents __read_mostly; | ||
978 | + | ||
979 | +/* In order to protect privacy, we add a perturbation to identifiers | ||
980 | + * if one generator is seldom used. This makes hard for an attacker | ||
981 | + * to infer how many packets were sent between two points in time. | ||
982 | */ | ||
983 | -static void ip_select_fb_ident(struct iphdr *iph) | ||
984 | +u32 ip_idents_reserve(u32 hash, int segs) | ||
985 | { | ||
986 | - static DEFINE_SPINLOCK(ip_fb_id_lock); | ||
987 | - static u32 ip_fallback_id; | ||
988 | - u32 salt; | ||
989 | + struct ip_ident_bucket *bucket = ip_idents + hash % IP_IDENTS_SZ; | ||
990 | + u32 old = ACCESS_ONCE(bucket->stamp32); | ||
991 | + u32 now = (u32)jiffies; | ||
992 | + u32 delta = 0; | ||
993 | + | ||
994 | + if (old != now && cmpxchg(&bucket->stamp32, old, now) == old) | ||
995 | + delta = prandom_u32_max(now - old); | ||
996 | |||
997 | - spin_lock_bh(&ip_fb_id_lock); | ||
998 | - salt = secure_ip_id((__force __be32)ip_fallback_id ^ iph->daddr); | ||
999 | - iph->id = htons(salt & 0xFFFF); | ||
1000 | - ip_fallback_id = salt; | ||
1001 | - spin_unlock_bh(&ip_fb_id_lock); | ||
1002 | + return atomic_add_return(segs + delta, &bucket->id) - segs; | ||
1003 | } | ||
1004 | +EXPORT_SYMBOL(ip_idents_reserve); | ||
1005 | |||
1006 | -void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more) | ||
1007 | +void __ip_select_ident(struct iphdr *iph, int segs) | ||
1008 | { | ||
1009 | - struct net *net = dev_net(dst->dev); | ||
1010 | - struct inet_peer *peer; | ||
1011 | + static u32 ip_idents_hashrnd __read_mostly; | ||
1012 | + u32 hash, id; | ||
1013 | |||
1014 | - peer = inet_getpeer_v4(net->ipv4.peers, iph->daddr, 1); | ||
1015 | - if (peer) { | ||
1016 | - iph->id = htons(inet_getid(peer, more)); | ||
1017 | - inet_putpeer(peer); | ||
1018 | - return; | ||
1019 | - } | ||
1020 | + net_get_random_once(&ip_idents_hashrnd, sizeof(ip_idents_hashrnd)); | ||
1021 | |||
1022 | - ip_select_fb_ident(iph); | ||
1023 | + hash = jhash_3words((__force u32)iph->daddr, | ||
1024 | + (__force u32)iph->saddr, | ||
1025 | + iph->protocol, | ||
1026 | + ip_idents_hashrnd); | ||
1027 | + id = ip_idents_reserve(hash, segs); | ||
1028 | + iph->id = htons(id); | ||
1029 | } | ||
1030 | EXPORT_SYMBOL(__ip_select_ident); | ||
1031 | |||
1032 | @@ -2705,6 +2712,12 @@ int __init ip_rt_init(void) | ||
1033 | { | ||
1034 | int rc = 0; | ||
1035 | |||
1036 | + ip_idents = kmalloc(IP_IDENTS_SZ * sizeof(*ip_idents), GFP_KERNEL); | ||
1037 | + if (!ip_idents) | ||
1038 | + panic("IP: failed to allocate ip_idents\n"); | ||
1039 | + | ||
1040 | + prandom_bytes(ip_idents, IP_IDENTS_SZ * sizeof(*ip_idents)); | ||
1041 | + | ||
1042 | #ifdef CONFIG_IP_ROUTE_CLASSID | ||
1043 | ip_rt_acct = __alloc_percpu(256 * sizeof(struct ip_rt_acct), __alignof__(struct ip_rt_acct)); | ||
1044 | if (!ip_rt_acct) | ||
1045 | diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c | ||
1046 | index 48539fff6357..08c8ab490fe5 100644 | ||
1047 | --- a/net/ipv4/tcp_vegas.c | ||
1048 | +++ b/net/ipv4/tcp_vegas.c | ||
1049 | @@ -219,7 +219,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked, | ||
1050 | * This is: | ||
1051 | * (actual rate in segments) * baseRTT | ||
1052 | */ | ||
1053 | - target_cwnd = tp->snd_cwnd * vegas->baseRTT / rtt; | ||
1054 | + target_cwnd = (u64)tp->snd_cwnd * vegas->baseRTT; | ||
1055 | + do_div(target_cwnd, rtt); | ||
1056 | |||
1057 | /* Calculate the difference between the window we had, | ||
1058 | * and the window we would like to have. This quantity | ||
1059 | diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c | ||
1060 | index 1b8e28fcd7e1..4cd4e1be3a71 100644 | ||
1061 | --- a/net/ipv4/tcp_veno.c | ||
1062 | +++ b/net/ipv4/tcp_veno.c | ||
1063 | @@ -145,7 +145,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked, | ||
1064 | |||
1065 | rtt = veno->minrtt; | ||
1066 | |||
1067 | - target_cwnd = (tp->snd_cwnd * veno->basertt); | ||
1068 | + target_cwnd = (u64)tp->snd_cwnd * veno->basertt; | ||
1069 | target_cwnd <<= V_PARAM_SHIFT; | ||
1070 | do_div(target_cwnd, rtt); | ||
1071 | |||
1072 | diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c | ||
1073 | index 05f2b484954f..91771a7c802f 100644 | ||
1074 | --- a/net/ipv4/xfrm4_mode_tunnel.c | ||
1075 | +++ b/net/ipv4/xfrm4_mode_tunnel.c | ||
1076 | @@ -58,12 +58,12 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | ||
1077 | |||
1078 | top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? | ||
1079 | 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF)); | ||
1080 | - ip_select_ident(skb, dst->child, NULL); | ||
1081 | |||
1082 | top_iph->ttl = ip4_dst_hoplimit(dst->child); | ||
1083 | |||
1084 | top_iph->saddr = x->props.saddr.a4; | ||
1085 | top_iph->daddr = x->id.daddr.a4; | ||
1086 | + ip_select_ident(skb, NULL); | ||
1087 | |||
1088 | return 0; | ||
1089 | } | ||
1090 | diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c | ||
1091 | index fbf11562b54c..1362d3a7b26f 100644 | ||
1092 | --- a/net/ipv6/ip6_output.c | ||
1093 | +++ b/net/ipv6/ip6_output.c | ||
1094 | @@ -537,6 +537,20 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) | ||
1095 | skb_copy_secmark(to, from); | ||
1096 | } | ||
1097 | |||
1098 | +static void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) | ||
1099 | +{ | ||
1100 | + static u32 ip6_idents_hashrnd __read_mostly; | ||
1101 | + u32 hash, id; | ||
1102 | + | ||
1103 | + net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd)); | ||
1104 | + | ||
1105 | + hash = __ipv6_addr_jhash(&rt->rt6i_dst.addr, ip6_idents_hashrnd); | ||
1106 | + hash = __ipv6_addr_jhash(&rt->rt6i_src.addr, hash); | ||
1107 | + | ||
1108 | + id = ip_idents_reserve(hash, 1); | ||
1109 | + fhdr->identification = htonl(id); | ||
1110 | +} | ||
1111 | + | ||
1112 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | ||
1113 | { | ||
1114 | struct sk_buff *frag; | ||
1115 | diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c | ||
1116 | index 56596ce390a1..6179ac186ab9 100644 | ||
1117 | --- a/net/ipv6/output_core.c | ||
1118 | +++ b/net/ipv6/output_core.c | ||
1119 | @@ -8,31 +8,6 @@ | ||
1120 | #include <net/addrconf.h> | ||
1121 | #include <net/secure_seq.h> | ||
1122 | |||
1123 | -void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) | ||
1124 | -{ | ||
1125 | - static atomic_t ipv6_fragmentation_id; | ||
1126 | - struct in6_addr addr; | ||
1127 | - int ident; | ||
1128 | - | ||
1129 | -#if IS_ENABLED(CONFIG_IPV6) | ||
1130 | - struct inet_peer *peer; | ||
1131 | - struct net *net; | ||
1132 | - | ||
1133 | - net = dev_net(rt->dst.dev); | ||
1134 | - peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); | ||
1135 | - if (peer) { | ||
1136 | - fhdr->identification = htonl(inet_getid(peer, 0)); | ||
1137 | - inet_putpeer(peer); | ||
1138 | - return; | ||
1139 | - } | ||
1140 | -#endif | ||
1141 | - ident = atomic_inc_return(&ipv6_fragmentation_id); | ||
1142 | - | ||
1143 | - addr = rt->rt6i_dst.addr; | ||
1144 | - addr.s6_addr32[0] ^= (__force __be32)ident; | ||
1145 | - fhdr->identification = htonl(secure_ipv6_id(addr.s6_addr32)); | ||
1146 | -} | ||
1147 | -EXPORT_SYMBOL(ipv6_select_ident); | ||
1148 | |||
1149 | int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | ||
1150 | { | ||
1151 | diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c | ||
1152 | index c47444e4cf8c..7f0e1cf2d7e8 100644 | ||
1153 | --- a/net/netfilter/ipvs/ip_vs_xmit.c | ||
1154 | +++ b/net/netfilter/ipvs/ip_vs_xmit.c | ||
1155 | @@ -883,7 +883,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | ||
1156 | iph->daddr = cp->daddr.ip; | ||
1157 | iph->saddr = saddr; | ||
1158 | iph->ttl = old_iph->ttl; | ||
1159 | - ip_select_ident(skb, &rt->dst, NULL); | ||
1160 | + ip_select_ident(skb, NULL); | ||
1161 | |||
1162 | /* Another hack: avoid icmp_send in ip_fragment */ | ||
1163 | skb->local_df = 1; | ||
1164 | diff --git a/net/sctp/associola.c b/net/sctp/associola.c | ||
1165 | index 0b999987b658..a6953b0436a5 100644 | ||
1166 | --- a/net/sctp/associola.c | ||
1167 | +++ b/net/sctp/associola.c | ||
1168 | @@ -1151,6 +1151,7 @@ void sctp_assoc_update(struct sctp_association *asoc, | ||
1169 | asoc->c = new->c; | ||
1170 | asoc->peer.rwnd = new->peer.rwnd; | ||
1171 | asoc->peer.sack_needed = new->peer.sack_needed; | ||
1172 | + asoc->peer.auth_capable = new->peer.auth_capable; | ||
1173 | asoc->peer.i = new->peer.i; | ||
1174 | sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL, | ||
1175 | asoc->peer.i.initial_tsn, GFP_ATOMIC); | ||
1176 | diff --git a/net/sctp/output.c b/net/sctp/output.c | ||
1177 | index 0f4d15fc2627..8267b06c3646 100644 | ||
1178 | --- a/net/sctp/output.c | ||
1179 | +++ b/net/sctp/output.c | ||
1180 | @@ -599,7 +599,7 @@ out: | ||
1181 | return err; | ||
1182 | no_route: | ||
1183 | kfree_skb(nskb); | ||
1184 | - IP_INC_STATS_BH(sock_net(asoc->base.sk), IPSTATS_MIB_OUTNOROUTES); | ||
1185 | + IP_INC_STATS(sock_net(asoc->base.sk), IPSTATS_MIB_OUTNOROUTES); | ||
1186 | |||
1187 | /* FIXME: Returning the 'err' will effect all the associations | ||
1188 | * associated with a socket, although only one of the paths of the | ||
1189 | diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c | ||
1190 | index c08fbd11ceff..ed608432e4f9 100644 | ||
1191 | --- a/net/xfrm/xfrm_policy.c | ||
1192 | +++ b/net/xfrm/xfrm_policy.c | ||
1193 | @@ -2107,6 +2107,8 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, | ||
1194 | goto no_transform; | ||
1195 | } | ||
1196 | |||
1197 | + dst_hold(&xdst->u.dst); | ||
1198 | + xdst->u.dst.flags |= DST_NOCACHE; | ||
1199 | route = xdst->route; | ||
1200 | } | ||
1201 | } | ||
1202 | diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c | ||
1203 | index 51398ae6cda8..d4c0fbe568ff 100644 | ||
1204 | --- a/net/xfrm/xfrm_user.c | ||
1205 | +++ b/net/xfrm/xfrm_user.c | ||
1206 | @@ -177,9 +177,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | ||
1207 | attrs[XFRMA_ALG_AEAD] || | ||
1208 | attrs[XFRMA_ALG_CRYPT] || | ||
1209 | attrs[XFRMA_ALG_COMP] || | ||
1210 | - attrs[XFRMA_TFCPAD] || | ||
1211 | - (ntohl(p->id.spi) >= 0x10000)) | ||
1212 | - | ||
1213 | + attrs[XFRMA_TFCPAD]) | ||
1214 | goto out; | ||
1215 | break; | ||
1216 | |||
1217 | @@ -207,7 +205,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | ||
1218 | attrs[XFRMA_ALG_AUTH] || | ||
1219 | attrs[XFRMA_ALG_AUTH_TRUNC] || | ||
1220 | attrs[XFRMA_ALG_CRYPT] || | ||
1221 | - attrs[XFRMA_TFCPAD]) | ||
1222 | + attrs[XFRMA_TFCPAD] || | ||
1223 | + (ntohl(p->id.spi) >= 0x10000)) | ||
1224 | goto out; | ||
1225 | break; | ||
1226 |