/********************************************************************* * * Filename: parameters.c * Version: 1.0 * Description: A more general way to handle (pi,pl,pv) parameters * Status: Experimental. * Author: Dag Brattli * Created at: Mon Jun 7 10:25:11 1999 * Modified at: Sun Jan 30 14:08:39 2000 * Modified by: Dag Brattli * * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. * * 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. * * This program 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 this program; if not, see . * ********************************************************************/ #include #include #include #include #include #include static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func); static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func); static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func); static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func); static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func); static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func); static int irda_param_unpack(__u8 *buf, char *fmt, ...); /* Parameter value call table. Must match PV_TYPE */ static const PV_HANDLER pv_extract_table[] = { irda_extract_integer, /* Handler for any length integers */ irda_extract_integer, /* Handler for 8 bits integers */ irda_extract_integer, /* Handler for 16 bits integers */ irda_extract_string, /* Handler for strings */ irda_extract_integer, /* Handler for 32 bits integers */ irda_extract_octseq, /* Handler for octet sequences */ irda_extract_no_value /* Handler for no value parameters */ }; static const PV_HANDLER pv_insert_table[] = { irda_insert_integer, /* Handler for any length integers */ irda_insert_integer, /* Handler for 8 bits integers */ irda_insert_integer, /* Handler for 16 bits integers */ NULL, /* Handler for strings */ irda_insert_integer, /* Handler for 32 bits integers */ NULL, /* Handler for octet sequences */ irda_insert_no_value /* Handler for no value parameters */ }; /* * Function irda_insert_no_value (self, buf, len, pi, type, func) */ static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { irda_param_t p; int ret; p.pi = pi; p.pl = 0; /* Call handler for this parameter */ ret = (*func)(self, &p, PV_GET); /* Extract values anyway, since handler may need them */ irda_param_pack(buf, "bb", p.pi, p.pl); if (ret < 0) return ret; return 2; /* Inserted pl+2 bytes */ } /* * Function irda_extract_no_value (self, buf, len, type, func) * * Extracts a parameter without a pv field (pl=0) * */ static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { irda_param_t p; int ret; /* Extract values anyway, since handler may need them */ irda_param_unpack(buf, "bb", &p.pi, &p.pl); /* Call handler for this parameter */ ret = (*func)(self, &p, PV_PUT); if (ret < 0) return ret; return 2; /* Extracted pl+2 bytes */ } /* * Function irda_insert_integer (self, buf, len, pi, type, func) */ static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { irda_param_t p; int n = 0; int err; p.pi = pi; /* In case handler needs to know */ p.pl = type & PV_MASK; /* The integer type codes the length as well */ p.pv.i = 0; /* Clear value */ /* Call handler for this parameter */ err = (*func)(self, &p, PV_GET); if (err < 0) return err; /* * If parameter length is still 0, then (1) this is an any length * integer, and (2) the handler function does not care which length * we choose to use, so we pick the one the gives the fewest bytes. */ if (p.pl == 0) { if (p.pv.i < 0xff) { pr_debug("%s(), using 1 byte\n", __func__); p.pl = 1; } else if (p.pv.i < 0xffff) { pr_debug("%s(), using 2 bytes\n", __func__); p.pl = 2; } else { pr_debug("%s(), using 4 bytes\n", __func__); p.pl = 4; /* Default length */ } } /* Check if buffer is long enough for insertion */ if (len < (2+p.pl)) { net_warn_ratelimited("%s: buffer too short for insertion!\n", __func__); return -1; } pr_debug("%s(), pi=%#x, pl=%d, pi=%d\n", __func__, p.pi, p.pl, p.pv.i); switch (p.pl) { case 1: n += irda_param_pack(buf, "bbb", p.pi, p.pl, (__u8) p.pv.i); break; case 2: if (type & PV_BIG_ENDIAN) p.pv.i = cpu_to_be16((__u16) p.pv.i); else p.pv.i = cpu_to_le16((__u16) p.pv.i); n += irda_param_pack(buf, "bbs", p.pi, p.pl, (__u16) p.pv.i); break; case 4: if (type & PV_BIG_ENDIAN) cpu_to_be32s(&p.pv.i); else cpu_to_le32s(&p.pv.i); n += irda_param_pack(buf, "bbi", p.pi, p.pl, p.pv.i); break; default: net_warn_ratelimited("%s: length %d not supported\n", __func__, p.pl); /* Skip parameter */ return -1; } return p.pl+2; /* Inserted pl+2 bytes */ } /* * Function irda_extract integer (self, buf, len, pi, type, func) * * Extract a possibly variable length integer from buffer, and call * handler for processing of the parameter */ static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { irda_param_t p; int n = 0; int extract_len; /* Real length we extract */ int err; p.pi = pi; /* In case handler needs to know */ p.pl = buf[1]; /* Extract length of value */ p.pv.i = 0; /* Clear value */ extract_len = p.pl; /* Default : extract all */ /* Check if buffer is long enough for parsing */ if (len < (2+p.pl)) { net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n", __func__, p.pl, len); return -1; } /* * Check that the integer length is what we expect it to be. If the * handler want a 16 bits integer then a 32 bits is not good enough * PV_INTEGER means that the handler is flexible. */ if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) { net_err_ratelimited("%s: invalid parameter length! Expected %d bytes, but value had %d bytes!\n", __func__, type & PV_MASK, p.pl); /* Most parameters are bit/byte fields or little endian, * so it's ok to only extract a subset of it (the subset * that the handler expect). This is necessary, as some * broken implementations seems to add extra undefined bits. * If the parameter is shorter than we expect or is big * endian, we can't play those tricks. Jean II */ if((p.pl < (type & PV_MASK)) || (type & PV_BIG_ENDIAN)) { /* Skip parameter */ return p.pl+2; } else { /* Extract subset of it, fallthrough */ extract_len = type & PV_MASK; } } switch (extract_len) { case 1: n += irda_param_unpack(buf+2, "b", &p.pv.i); break; case 2: n += irda_param_unpack(buf+2, "s", &p.pv.i); if (type & PV_BIG_ENDIAN) p.pv.i = be16_to_cpu((__u16) p.pv.i); else p.pv.i = le16_to_cpu((__u16) p.pv.i); break; case 4: n += irda_param_unpack(buf+2, "i", &p.pv.i); if (type & PV_BIG_ENDIAN) be32_to_cpus(&p.pv.i); else le32_to_cpus(&p.pv.i); break; default: net_warn_ratelimited("%s: length %d not supported\n", __func__, p.pl); /* Skip parameter */ return p.pl+2; } pr_debug("%s(), pi=%#x, pl=%d, pi=%d\n", __func__, p.pi, p.pl, p.pv.i); /* Call handler for this parameter */ err = (*func)(self, &p, PV_PUT); if (err < 0) return err; return p.pl+2; /* Extracted pl+2 bytes */ } /* * Function irda_extract_string (self, buf, len, type, func) */ static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { char str[33]; irda_param_t p; int err; p.pi = pi; /* In case handler needs to know */ p.pl = buf[1]; /* Extract length of value */ if (p.pl > 32) p.pl = 32; pr_debug("%s(), pi=%#x, pl=%d\n", __func__, p.pi, p.pl); /* Check if buffer is long enough for parsing */ if (len < (2+p.pl)) { net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n", __func__, p.pl, len); return -1; } /* Should be safe to copy string like this since we have already * checked that the buffer is long enough */ strncpy(str, buf+2, p.pl); pr_debug("%s(), str=0x%02x 0x%02x\n", __func__, (__u8)str[0], (__u8)str[1]); /* Null terminate string */ str[p.pl] = '\0'; p.pv.c = str; /* Handler will need to take a copy */ /* Call handler for this parameter */ err = (*func)(self, &p, PV_PUT); if (err < 0) return err; return p.pl+2; /* Extracted pl+2 bytes */ } /* * Function irda_extract_octseq (self, buf, len, type, func) */ static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi, PV_TYPE type, PI_HANDLER func) { irda_param_t p; p.pi = pi; /* In case handler needs to know */ p.pl = buf[1]; /* Extract length of value */ /* Check if buffer is long enough for parsing */ if (len < (2+p.pl)) { net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n", __func__, p.pl, len); return -1; } pr_debug("%s(), not impl\n", __func__); return p.pl+2; /* Extracted pl+2 bytes */ } /* * Function irda_param_pack (skb, fmt, ...) * * Format: * 'i' = 32 bits integer * 's' = string * */ int irda_param_pack(__u8 *buf, char *fmt, ...) { irda_pv_t arg; va_list args; char *p; int n = 0; va_start(args, fmt); for (p = fmt; *p != '\0'; p++) { switch (*p) { case 'b': /* 8 bits unsigned byte */ buf[n++] = (__u8)va_arg(args, int); break; case 's': /* 16 bits unsigned short */ arg.i = (__u16)va_arg(args, int); put_unaligned((__u16)arg.i, (__u16 *)(buf+n)); n+=2; break; case 'i': /* 32 bits unsigned integer */ arg.i = va_arg(args, __u32); put_unaligned(arg.i, (__u32 *)(buf+n)); n+=4; break; #if 0 case 'c': /* \0 terminated string */ arg.c = va_arg(args, char *); strcpy(buf+n, arg.c); n += strlen(arg.c) + 1; break; #endif default: va_end(args); return -1; } } va_end(args); return 0; } EXPORT_SYMBOL(irda_param_pack); /* * Function irda_param_unpack (skb, fmt, ...) */ static int irda_param_unpack(__u8 *buf, char *fmt, ...) { irda_pv_t arg; va_list args; char *p; int n = 0; va_start(args, fmt); for (p = fmt; *p != '\0'; p++) { switch (*p) { case 'b': /* 8 bits byte */ arg.ip = va_arg(args, __u32 *); *arg.ip = buf[n++]; break; case 's': /* 16 bits short */ arg.ip = va_arg(args, __u32 *); *arg.ip = get_unaligned((__u16 *)(buf+n)); n+=2; break; case 'i': /* 32 bits unsigned integer */ arg.ip = va_arg(args, __u32 *); *arg.ip = get_unaligned((__u32 *)(buf+n)); n+=4; break; #if 0 case 'c': /* \0 terminated string */ arg.c = va_arg(args, char *); strcpy(arg.c, buf+n); n += strlen(arg.c) + 1; break; #endif default: va_end(args); return -1; } } va_end(args); return 0; } /* * Function irda_param_insert (self, pi, buf, len, info) * * Insert the specified parameter (pi) into buffer. Returns number of * bytes inserted */ int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len, pi_param_info_t *info) { const pi_minor_info_t *pi_minor_info; __u8 pi_minor; __u8 pi_major; int type; int ret = -1; int n = 0; IRDA_ASSERT(buf != NULL, return ret;); IRDA_ASSERT(info != NULL, return ret;); pi_minor = pi & info->pi_mask; pi_major = pi >> info->pi_major_offset; /* Check if the identifier value (pi) is valid */ if ((pi_major > info->len-1) || (pi_minor > info->tables[pi_major].len-1)) { pr_debug("%s(), no handler for parameter=0x%02x\n", __func__, pi); /* Skip this parameter */ return -1; } /* Lookup the info on how to parse this parameter */ pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor]; /* Find expected data type for this parameter identifier (pi)*/ type = pi_minor_info->type; /* Check if handler has been implemented */ if (!pi_minor_info->func) { net_info_ratelimited("%s: no handler for pi=%#x\n", __func__, pi); /* Skip this parameter */ return -1; } /* Insert parameter value */ ret = (*pv_insert_table[type & PV_MASK])(self, buf+n, len, pi, type, pi_minor_info->func); return ret; } EXPORT_SYMBOL(irda_param_insert); /* * Function irda_param_extract (self, buf, len, info) * * Parse all parameters. If len is correct, then everything should be * safe. Returns the number of bytes that was parsed * */ static int irda_param_extract(void *self, __u8 *buf, int len, pi_param_info_t *info) { const pi_minor_info_t *pi_minor_info; __u8 pi_minor; __u8 pi_major; int type; int ret = -1; int n = 0; IRDA_ASSERT(buf != NULL, return ret;); IRDA_ASSERT(info != NULL, return ret;); pi_minor = buf[n] & info->pi_mask; pi_major = buf[n] >> info->pi_major_offset; /* Check if the identifier value (pi) is valid */ if ((pi_major > info->len-1) || (pi_minor > info->tables[pi_major].len-1)) { pr_debug("%s(), no handler for parameter=0x%02x\n", __func__, buf[0]); /* Skip this parameter */ return 2 + buf[n + 1]; /* Continue */ } /* Lookup the info on how to parse this parameter */ pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor]; /* Find expected data type for this parameter identifier (pi)*/ type = pi_minor_info->type; pr_debug("%s(), pi=[%d,%d], type=%d\n", __func__, pi_major, pi_minor, type); /* Check if handler has been implemented */ if (!pi_minor_info->func) { net_info_ratelimited("%s: no handler for pi=%#x\n", __func__, buf[n]); /* Skip this parameter */ return 2 + buf[n + 1]; /* Continue */ } /* Parse parameter value */ ret = (*pv_extract_table[type & PV_MASK])(self, buf+n, len, buf[n], type, pi_minor_info->func); return ret; } /* * Function irda_param_extract_all (self, buf, len, info) * * Parse all parameters. If len is correct, then everything should be * safe. Returns the number of bytes that was parsed * */ int irda_param_extract_all(void *self, __u8 *buf, int len, pi_param_info_t *info) { int ret = -1; int n = 0; IRDA_ASSERT(buf != NULL, return ret;); IRDA_ASSERT(info != NULL, return ret;); /* * Parse all parameters. Each parameter must be at least two bytes * long or else there is no point in trying to parse it */ while (len > 2) { ret = irda_param_extract(self, buf+n, len, info); if (ret < 0) return ret; n += ret; len -= ret; } return n; } EXPORT_SYMBOL(irda_param_extract_all); gned-off-by: David S. Miller <davem@davemloft.net> 2017-02-09openvswitch: Add force commit.Jarno Rajahalme1-0/+5 Stateful network admission policy may allow connections to one direction and reject connections initiated in the other direction. After policy change it is possible that for a new connection an overlapping conntrack entry already exists, where the original direction of the existing connection is opposed to the new connection's initial packet. Most importantly, conntrack state relating to the current packet gets the "reply" designation based on whether the original direction tuple or the reply direction tuple matched. If this "directionality" is wrong w.r.t. to the stateful network admission policy it may happen that packets in neither direction are correctly admitted. This patch adds a new "force commit" option to the OVS conntrack action that checks the original direction of an existing conntrack entry. If that direction is opposed to the current packet, the existing conntrack entry is deleted and a new one is subsequently created in the correct direction. Signed-off-by: Jarno Rajahalme <jarno@ovn.org> Acked-by: Pravin B Shelar <pshelar@ovn.org> Acked-by: Joe Stringer <joe@ovn.org> Signed-off-by: David S. Miller <davem@davemloft.net> 2017-02-09openvswitch: Add original direction conntrack tuple to sw_flow_key.Jarno Rajahalme1-1/+19 Add the fields of the conntrack original direction 5-tuple to struct sw_flow_key. The new fields are initially marked as non-existent, and are populated whenever a conntrack action is executed and either finds or generates a conntrack entry. This means that these fields exist for all packets that were not rejected by conntrack as untrackable. The original tuple fields in the sw_flow_key are filled from the original direction tuple of the conntrack entry relating to the current packet, or from the original direction tuple of the master conntrack entry, if the current conntrack entry has a master. Generally, expected connections of connections having an assigned helper (e.g., FTP), have a master conntrack entry. The main purpose of the new conntrack original tuple fields is to allow matching on them for policy decision purposes, with the premise that the admissibility of tracked connections reply packets (as well as original direction packets), and both direction packets of any related connections may be based on ACL rules applying to the master connection's original direction 5-tuple. This also makes it easier to make policy decisions when the actual packet headers might have been transformed by NAT, as the original direction 5-tuple represents the packet headers before any such transformation. When using the original direction 5-tuple the admissibility of return and/or related packets need not be based on the mere existence of a conntrack entry, allowing separation of admission policy from the established conntrack state. While existence of a conntrack entry is required for admission of the return or related packets, policy changes can render connections that were initially admitted to be rejected or dropped afterwards. If the admission of the return and related packets was based on mere conntrack state (e.g., connection being in an established state), a policy change that would make the connection rejected or dropped would need to find and delete all conntrack entries affected by such a change. When using the original direction 5-tuple matching the affected conntrack entries can be allowed to time out instead, as the established state of the connection would not need to be the basis for packet admission any more. It should be noted that the directionality of related connections may be the same or different than that of the master connection, and neither the original direction 5-tuple nor the conntrack state bits carry this information. If needed, the directionality of the master connection can be stored in master's conntrack mark or labels, which are automatically inherited by the expected related connections. The fact that neither ARP nor ND packets are trackable by conntrack allows mutual exclusion between ARP/ND and the new conntrack original tuple fields. Hence, the IP addresses are overlaid in union with ARP and ND fields. This allows the sw_flow_key to not grow much due to this patch, but it also means that we must be careful to never use the new key fields with ARP or ND packets. ARP is easy to distinguish and keep mutually exclusive based on the ethernet type, but ND being an ICMPv6 protocol requires a bit more attention. Signed-off-by: Jarno Rajahalme <jarno@ovn.org> Acked-by: Joe Stringer <joe@ovn.org> Acked-by: Pravin B Shelar <pshelar@ovn.org> Signed-off-by: David S. Miller <davem@davemloft.net> 2017-02-09openvswitch: Unionize ovs_key_ct_label with a u32 array.Jarno Rajahalme1-2/+6 Make the array of labels in struct ovs_key_ct_label an union, adding a u32 array of the same byte size as the existing u8 array. It is faster to loop through the labels 32 bits at the time, which is also the alignment of netlink attributes. Signed-off-by: Jarno Rajahalme <jarno@ovn.org> Acked-by: Joe Stringer <joe@ovn.org> Acked-by: Pravin B Shelar <pshelar@ovn.org> Signed-off-by: David S. Miller <davem@davemloft.net> 2017-02-09sctp: implement sender-side procedures for Add Incoming/Outgoing Streams ↵Xin Long2-0/+9 Request Parameter This patch is to implement Sender-Side Procedures for the Add Outgoing and Incoming Streams Request Parameter described in rfc6525 section 5.1.5-5.1.6. It is also to add sockopt SCTP_ADD_STREAMS in rfc6525 section 6.3.4 for users. Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> 2017-02-09sctp: add support for generating stream reconf add incoming/outgoing streams ↵Xin Long2-0/+10 request chunk This patch is to define Add Incoming/Outgoing Streams Request Parameter described in rfc6525 section 4.5 and 4.6. They can be in one same chunk trunk as rfc6525 section 3.1-7 describes, so make them in one function. Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> 2017-02-09sctp: implement sender-side procedures for SSN/TSN Reset Request ParameterXin Long2-0/+2 This patch is to implement Sender-Side Procedures for the SSN/TSN Reset Request Parameter descibed in rfc6525 section 5.1.4. It is also to add sockopt SCTP_RESET_ASSOC in rfc6525 section 6.3.3 for users. Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> 2017-02-09sctp: add support for generating stream reconf ssn/tsn reset request chunkXin Long2-0/+7 This patch is to define SSN/TSN Reset Request Parameter described in rfc6525 section 4.3. Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> 2017-02-09sctp: drop unnecessary __packed from some stream reconf structuresXin Long1-3/+3 commit 85c727b59483 ("sctp: drop __packed from almost all SCTP structures") has removed __packed from almost all SCTP structures. But there still are three structures where it should be dropped. This patch is to remove it from some stream reconf structures. Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> 2017-02-09cfg80211: fix NAN bands definitionLuca Coelho2-36/+39 The nl80211_nan_dual_band_conf enumeration doesn't make much sense. The default value is assigned to a bit, which makes it weird if the default bit and other bits are set at the same time. To improve this, get rid of NL80211_NAN_BAND_DEFAULT and add a wiphy configuration to let the drivers define which bands are supported. This is exposed to the userspace, which then can make a decision on which band(s) to use. Additionally, rename all "dual_band" elements to "bands", to make things clearer. Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> 2017-02-08ipv4: fib: Notify about nexthop status changesIdo Schimmel1-0/+7 When a multipath route is hit the kernel doesn't consider nexthops that are DEAD or LINKDOWN when IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN is set. Devices that offload multipath routes need to be made aware of nexthop status changes. Otherwise, the device will keep forwarding packets to non-functional nexthops. Add the FIB_EVENT_NH_{ADD,DEL} events to the fib notification chain, which notify capable devices when they should add or delete a nexthop from their tables. Cc: Roopa Prabhu <roopa@cumulusnetworks.com> Cc: David Ahern <dsa@cumulusnetworks.com> Cc: Andy Gospodarek <andy@greyhouse.net> Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Reviewed-by: Andy Gospodarek <gospo@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net> 2017-02-08net: stmmac: Remove the bus_setup function pointerLABBE Corentin1-1/+0 The bus_setup function pointer is not used at all, this patch remove it. Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com> Acked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net> 2017-02-08gro_cells: move to net/core/gro_cells.cEric Dumazet1-82/+4 We have many gro cells users, so lets move the code to avoid duplication. This creates a CONFIG_GRO_CELLS option. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> 2017-02-08net: phy: Add LED mode driver for Microsemi PHYs.Raju Lakkaraju