Changes in 4.9.213 ALSA: pcm: Add missing copy ops check before clearing buffer orinoco_usb: fix interface sanity check rsi_91x_usb: fix interface sanity check USB: serial: ir-usb: add missing endpoint sanity check USB: serial: ir-usb: fix link-speed handling USB: serial: ir-usb: fix IrLAP framing staging: most: net: fix buffer overflow staging: wlan-ng: ensure error return is actually returned staging: vt6656: correct packet types for CTS protect, mode. staging: vt6656: use NULLFUCTION stack on mac80211 staging: vt6656: Fix false Tx excessive retries reporting. serial: 8250_bcm2835aux: Fix line mismatch on driver unbind ath9k: fix storage endpoint lookup brcmfmac: fix interface sanity check rtl8xxxu: fix interface sanity check zd1211rw: fix storage endpoint lookup arc: eznps: fix allmodconfig kconfig warning watchdog: rn5t618_wdt: fix module aliases drivers/net/b44: Change to non-atomic bit operations on pwol_mask net: wan: sdla: Fix cast from pointer to integer of different size gpio: max77620: Add missing dependency on GPIOLIB_IRQCHIP atm: eni: fix uninitialized variable warning usb-storage: Disable UAS on JMicron SATA enclosure net_sched: ematch: reject invalid TCF_EM_SIMPLE crypto: af_alg - Use bh_lock_sock in sk_destruct vfs: fix do_last() regression crypto: pcrypt - Fix user-after-free on module unload iio: gyro: st_gyro: inline per-sensor data iio: gyro: st_gyro: fix L3GD20H support tools lib: Fix builds when glibc contains strlcpy() arm64: kbuild: remove compressed images on 'make ARCH=arm64 (dist)clean' mm/mempolicy.c: fix out of bounds write in mpol_parse_str() reiserfs: Fix memory leak of journal device string media: digitv: don't continue if remote control state can't be read media: af9005: uninitialized variable printked media: gspca: zero usb_buf media: dvb-usb/dvb-usb-urb.c: initialize actlen to 0 ttyprintk: fix a potential deadlock in interrupt context issue Bluetooth: Fix race condition in hci_release_sock() usb: dwc3: turn off VBUS when leaving host mode media: si470x-i2c: Move free() past last use of 'radio' ARM: dts: beagle-x15-common: Model 5V0 regulator soc: ti: wkup_m3_ipc: Fix race condition with rproc_boot mac80211: mesh: restrict airtime metric to peered established plinks clk: mmp2: Fix the order of timer mux parents ixgbevf: Remove limit of 10 entries for unicast filter list ixgbe: Fix calculation of queue with VFs and flow director on interface flap wireless: fix enabling channel 12 for custom regulatory domain mac80211: Fix TKIP replay protection immediately after key setup wireless: wext: avoid gcc -O3 warning vti[6]: fix packet tx through bpf_redirect() scsi: fnic: do not queue commands during fwreset airo: Fix possible info leak in AIROOLDIOCTL/SIOCDEVPRIVATE airo: Add missing CAP_NET_ADMIN check in AIROOLDIOCTL/SIOCDEVPRIVATE r8152: get default setting of WOL before initializing qlcnic: Fix CPU soft lockup while collecting firmware dump powerpc/fsl/dts: add fsl,erratum-a011043 net/fsl: treat fsl,erratum-a011043 net: fsl/fman: rename IF_MODE_XGMII to IF_MODE_10G net/sonic: Add mutual exclusion for accessing shared state net/sonic: Use MMIO accessors net/sonic: Fix receive buffer handling net/sonic: Quiesce SONIC before re-initializing descriptor memory seq_tab_next() should increase position index l2t_seq_next should increase position index net: Fix skb->csum update in inet_proto_csum_replace16(). btrfs: do not zero f_bavail if we have available space Linux 4.9.213 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ia11340061ca1d357e98f09bf64ea5d0856e4a5b2
365 lines
8.8 KiB
C
365 lines
8.8 KiB
C
/*
|
|
* Generic address resultion entity
|
|
*
|
|
* Authors:
|
|
* net_random Alan Cox
|
|
* net_ratelimit Andi Kleen
|
|
* in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project
|
|
*
|
|
* Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
|
|
*
|
|
* This program 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 of the License, or (at your option) any later version.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/inet.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/net.h>
|
|
#include <linux/string.h>
|
|
#include <linux/types.h>
|
|
#include <linux/percpu.h>
|
|
#include <linux/init.h>
|
|
#include <linux/ratelimit.h>
|
|
|
|
#include <net/sock.h>
|
|
#include <net/net_ratelimit.h>
|
|
|
|
#include <asm/byteorder.h>
|
|
#include <asm/uaccess.h>
|
|
|
|
DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10);
|
|
/*
|
|
* All net warning printk()s should be guarded by this function.
|
|
*/
|
|
int net_ratelimit(void)
|
|
{
|
|
return __ratelimit(&net_ratelimit_state);
|
|
}
|
|
EXPORT_SYMBOL(net_ratelimit);
|
|
|
|
/*
|
|
* Convert an ASCII string to binary IP.
|
|
* This is outside of net/ipv4/ because various code that uses IP addresses
|
|
* is otherwise not dependent on the TCP/IP stack.
|
|
*/
|
|
|
|
__be32 in_aton(const char *str)
|
|
{
|
|
unsigned long l;
|
|
unsigned int val;
|
|
int i;
|
|
|
|
l = 0;
|
|
for (i = 0; i < 4; i++) {
|
|
l <<= 8;
|
|
if (*str != '\0') {
|
|
val = 0;
|
|
while (*str != '\0' && *str != '.' && *str != '\n') {
|
|
val *= 10;
|
|
val += *str - '0';
|
|
str++;
|
|
}
|
|
l |= val;
|
|
if (*str != '\0')
|
|
str++;
|
|
}
|
|
}
|
|
return htonl(l);
|
|
}
|
|
EXPORT_SYMBOL(in_aton);
|
|
|
|
#define IN6PTON_XDIGIT 0x00010000
|
|
#define IN6PTON_DIGIT 0x00020000
|
|
#define IN6PTON_COLON_MASK 0x00700000
|
|
#define IN6PTON_COLON_1 0x00100000 /* single : requested */
|
|
#define IN6PTON_COLON_2 0x00200000 /* second : requested */
|
|
#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */
|
|
#define IN6PTON_DOT 0x00800000 /* . */
|
|
#define IN6PTON_DELIM 0x10000000
|
|
#define IN6PTON_NULL 0x20000000 /* first/tail */
|
|
#define IN6PTON_UNKNOWN 0x40000000
|
|
|
|
static inline int xdigit2bin(char c, int delim)
|
|
{
|
|
int val;
|
|
|
|
if (c == delim || c == '\0')
|
|
return IN6PTON_DELIM;
|
|
if (c == ':')
|
|
return IN6PTON_COLON_MASK;
|
|
if (c == '.')
|
|
return IN6PTON_DOT;
|
|
|
|
val = hex_to_bin(c);
|
|
if (val >= 0)
|
|
return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
|
|
|
|
if (delim == -1)
|
|
return IN6PTON_DELIM;
|
|
return IN6PTON_UNKNOWN;
|
|
}
|
|
|
|
/**
|
|
* in4_pton - convert an IPv4 address from literal to binary representation
|
|
* @src: the start of the IPv4 address string
|
|
* @srclen: the length of the string, -1 means strlen(src)
|
|
* @dst: the binary (u8[4] array) representation of the IPv4 address
|
|
* @delim: the delimiter of the IPv4 address in @src, -1 means no delimiter
|
|
* @end: A pointer to the end of the parsed string will be placed here
|
|
*
|
|
* Return one on success, return zero when any error occurs
|
|
* and @end will point to the end of the parsed string.
|
|
*
|
|
*/
|
|
int in4_pton(const char *src, int srclen,
|
|
u8 *dst,
|
|
int delim, const char **end)
|
|
{
|
|
const char *s;
|
|
u8 *d;
|
|
u8 dbuf[4];
|
|
int ret = 0;
|
|
int i;
|
|
int w = 0;
|
|
|
|
if (srclen < 0)
|
|
srclen = strlen(src);
|
|
s = src;
|
|
d = dbuf;
|
|
i = 0;
|
|
while (1) {
|
|
int c;
|
|
c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
|
|
if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) {
|
|
goto out;
|
|
}
|
|
if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
|
|
if (w == 0)
|
|
goto out;
|
|
*d++ = w & 0xff;
|
|
w = 0;
|
|
i++;
|
|
if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
|
|
if (i != 4)
|
|
goto out;
|
|
break;
|
|
}
|
|
goto cont;
|
|
}
|
|
w = (w * 10) + c;
|
|
if ((w & 0xffff) > 255) {
|
|
goto out;
|
|
}
|
|
cont:
|
|
if (i >= 4)
|
|
goto out;
|
|
s++;
|
|
srclen--;
|
|
}
|
|
ret = 1;
|
|
memcpy(dst, dbuf, sizeof(dbuf));
|
|
out:
|
|
if (end)
|
|
*end = s;
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(in4_pton);
|
|
|
|
/**
|
|
* in6_pton - convert an IPv6 address from literal to binary representation
|
|
* @src: the start of the IPv6 address string
|
|
* @srclen: the length of the string, -1 means strlen(src)
|
|
* @dst: the binary (u8[16] array) representation of the IPv6 address
|
|
* @delim: the delimiter of the IPv6 address in @src, -1 means no delimiter
|
|
* @end: A pointer to the end of the parsed string will be placed here
|
|
*
|
|
* Return one on success, return zero when any error occurs
|
|
* and @end will point to the end of the parsed string.
|
|
*
|
|
*/
|
|
int in6_pton(const char *src, int srclen,
|
|
u8 *dst,
|
|
int delim, const char **end)
|
|
{
|
|
const char *s, *tok = NULL;
|
|
u8 *d, *dc = NULL;
|
|
u8 dbuf[16];
|
|
int ret = 0;
|
|
int i;
|
|
int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
|
|
int w = 0;
|
|
|
|
memset(dbuf, 0, sizeof(dbuf));
|
|
|
|
s = src;
|
|
d = dbuf;
|
|
if (srclen < 0)
|
|
srclen = strlen(src);
|
|
|
|
while (1) {
|
|
int c;
|
|
|
|
c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
|
|
if (!(c & state))
|
|
goto out;
|
|
if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
|
|
/* process one 16-bit word */
|
|
if (!(state & IN6PTON_NULL)) {
|
|
*d++ = (w >> 8) & 0xff;
|
|
*d++ = w & 0xff;
|
|
}
|
|
w = 0;
|
|
if (c & IN6PTON_DELIM) {
|
|
/* We've processed last word */
|
|
break;
|
|
}
|
|
/*
|
|
* COLON_1 => XDIGIT
|
|
* COLON_2 => XDIGIT|DELIM
|
|
* COLON_1_2 => COLON_2
|
|
*/
|
|
switch (state & IN6PTON_COLON_MASK) {
|
|
case IN6PTON_COLON_2:
|
|
dc = d;
|
|
state = IN6PTON_XDIGIT | IN6PTON_DELIM;
|
|
if (dc - dbuf >= sizeof(dbuf))
|
|
state |= IN6PTON_NULL;
|
|
break;
|
|
case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
|
|
state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
|
|
break;
|
|
case IN6PTON_COLON_1:
|
|
state = IN6PTON_XDIGIT;
|
|
break;
|
|
case IN6PTON_COLON_1_2:
|
|
state = IN6PTON_COLON_2;
|
|
break;
|
|
default:
|
|
state = 0;
|
|
}
|
|
tok = s + 1;
|
|
goto cont;
|
|
}
|
|
|
|
if (c & IN6PTON_DOT) {
|
|
ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
|
|
if (ret > 0) {
|
|
d += 4;
|
|
break;
|
|
}
|
|
goto out;
|
|
}
|
|
|
|
w = (w << 4) | (0xff & c);
|
|
state = IN6PTON_COLON_1 | IN6PTON_DELIM;
|
|
if (!(w & 0xf000)) {
|
|
state |= IN6PTON_XDIGIT;
|
|
}
|
|
if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
|
|
state |= IN6PTON_COLON_1_2;
|
|
state &= ~IN6PTON_DELIM;
|
|
}
|
|
if (d + 2 >= dbuf + sizeof(dbuf)) {
|
|
state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
|
|
}
|
|
cont:
|
|
if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
|
|
d + 4 == dbuf + sizeof(dbuf)) {
|
|
state |= IN6PTON_DOT;
|
|
}
|
|
if (d >= dbuf + sizeof(dbuf)) {
|
|
state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
|
|
}
|
|
s++;
|
|
srclen--;
|
|
}
|
|
|
|
i = 15; d--;
|
|
|
|
if (dc) {
|
|
while (d >= dc)
|
|
dst[i--] = *d--;
|
|
while (i >= dc - dbuf)
|
|
dst[i--] = 0;
|
|
while (i >= 0)
|
|
dst[i--] = *d--;
|
|
} else
|
|
memcpy(dst, dbuf, sizeof(dbuf));
|
|
|
|
ret = 1;
|
|
out:
|
|
if (end)
|
|
*end = s;
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(in6_pton);
|
|
|
|
void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
|
|
__be32 from, __be32 to, bool pseudohdr)
|
|
{
|
|
if (skb->ip_summed != CHECKSUM_PARTIAL) {
|
|
csum_replace4(sum, from, to);
|
|
if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
|
|
skb->csum = ~csum_add(csum_sub(~(skb->csum),
|
|
(__force __wsum)from),
|
|
(__force __wsum)to);
|
|
} else if (pseudohdr)
|
|
*sum = ~csum_fold(csum_add(csum_sub(csum_unfold(*sum),
|
|
(__force __wsum)from),
|
|
(__force __wsum)to));
|
|
}
|
|
EXPORT_SYMBOL(inet_proto_csum_replace4);
|
|
|
|
/**
|
|
* inet_proto_csum_replace16 - update layer 4 header checksum field
|
|
* @sum: Layer 4 header checksum field
|
|
* @skb: sk_buff for the packet
|
|
* @from: old IPv6 address
|
|
* @to: new IPv6 address
|
|
* @pseudohdr: True if layer 4 header checksum includes pseudoheader
|
|
*
|
|
* Update layer 4 header as per the update in IPv6 src/dst address.
|
|
*
|
|
* There is no need to update skb->csum in this function, because update in two
|
|
* fields a.) IPv6 src/dst address and b.) L4 header checksum cancels each other
|
|
* for skb->csum calculation. Whereas inet_proto_csum_replace4 function needs to
|
|
* update skb->csum, because update in 3 fields a.) IPv4 src/dst address,
|
|
* b.) IPv4 Header checksum and c.) L4 header checksum results in same diff as
|
|
* L4 Header checksum for skb->csum calculation.
|
|
*/
|
|
void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
|
|
const __be32 *from, const __be32 *to,
|
|
bool pseudohdr)
|
|
{
|
|
__be32 diff[] = {
|
|
~from[0], ~from[1], ~from[2], ~from[3],
|
|
to[0], to[1], to[2], to[3],
|
|
};
|
|
if (skb->ip_summed != CHECKSUM_PARTIAL) {
|
|
*sum = csum_fold(csum_partial(diff, sizeof(diff),
|
|
~csum_unfold(*sum)));
|
|
} else if (pseudohdr)
|
|
*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
|
|
csum_unfold(*sum)));
|
|
}
|
|
EXPORT_SYMBOL(inet_proto_csum_replace16);
|
|
|
|
void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb,
|
|
__wsum diff, bool pseudohdr)
|
|
{
|
|
if (skb->ip_summed != CHECKSUM_PARTIAL) {
|
|
*sum = csum_fold(csum_add(diff, ~csum_unfold(*sum)));
|
|
if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
|
|
skb->csum = ~csum_add(diff, ~skb->csum);
|
|
} else if (pseudohdr) {
|
|
*sum = ~csum_fold(csum_add(diff, csum_unfold(*sum)));
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(inet_proto_csum_replace_by_diff);
|