Documentation
arch
block
certs
crypto
drivers
firmware
fs
include
init
ipc
kernel
lib
mm
ndm
net
6lowpan
802
8021q
Kconfig
Makefile
vlan.c
vlan.h
vlan_core.c
vlan_dev.c
vlan_gvrp.c
vlan_mvrp.c
vlan_netlink.c
vlanproc.c
vlanproc.h
9p
appletalk
atm
ax25
batman-adv
bluetooth
bridge
caif
can
ceph
core
dcb
dccp
decnet
dns_resolver
dsa
ethernet
hsr
ieee802154
ipv4
ipv6
ipx
irda
iucv
kcm
key
l2tp
l3mdev
lapb
llc
mac80211
mac802154
mpls
ncsi
netfilter
netlabel
netlink
netrom
nfc
openvswitch
packet
phonet
qrtr
rds
rfkill
rose
rxrpc
sched
sctp
strparser
sunrpc
switchdev
tipc
unix
vmw_vsock
wimax
wireless
x25
xfrm
Kconfig
Makefile
compat.c
socket.c
sysctl_net.c
samples
scripts
security
sound
tools
usr
virt
.cocciconfig
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
REPORTING-BUGS
build.config.aarch64
build.config.common
build.config.cuttlefish.aarch64
build.config.cuttlefish.x86_64
build.config.goldfish.arm
build.config.goldfish.arm64
build.config.goldfish.mips
build.config.goldfish.mips64
build.config.goldfish.x86
build.config.goldfish.x86_64
build.config.x86_64
localversion-ndm
verity_dev_keys.x509
Changes in 4.9.209 PM / devfreq: Don't fail devfreq_dev_release if not in list RDMA/cma: add missed unregister_pernet_subsys in init failure scsi: lpfc: Fix memory leak on lpfc_bsg_write_ebuf_set func scsi: qla2xxx: Don't call qlt_async_event twice scsi: iscsi: qla4xxx: fix double free in probe scsi: libsas: stop discovering if oob mode is disconnected usb: gadget: fix wrong endpoint desc md: raid1: check rdev before reference in raid1_sync_request func s390/cpum_sf: Adjust sampling interval to avoid hitting sample limits s390/cpum_sf: Avoid SBD overflow condition in irq handler IB/mlx4: Follow mirror sequence of device add during device removal xen-blkback: prevent premature module unload xen/balloon: fix ballooned page accounting without hotplug enabled PM / hibernate: memory_bm_find_bit(): Tighten node optimisation xfs: fix mount failure crash on invalid iclog memory access taskstats: fix data-race drm: limit to INT_MAX in create_blob ioctl Revert "perf report: Add warning when libunwind not compiled in" ALSA: ice1724: Fix sleep-in-atomic in Infrasonic Quartet support code MIPS: Avoid VDSO ABI breakage due to global register variable mm/zsmalloc.c: fix the migrated zspage statistics. memcg: account security cred as well to kmemcg locks: print unsigned ino in /proc/locks dmaengine: Fix access to uninitialized dma_slave_caps compat_ioctl: block: handle Persistent Reservations ata: libahci_platform: Export again ahci_platform_<en/dis>able_phys() ata: ahci_brcm: Allow optional reset controller to be used ata: ahci_brcm: Fix AHCI resources management gpiolib: fix up emulated open drain outputs tracing: Have the histogram compare functions convert to u64 first ALSA: cs4236: fix error return comparison of an unsigned integer ftrace: Avoid potential division by zero in function profiler arm64: Revert support for execute-only user mappings PM / devfreq: Check NULL governor in available_governors_show nfsd4: fix up replay_matches_cache() xfs: don't check for AG deadlock for realtime files in bunmapi Bluetooth: btusb: fix PM leak in error case of setup Bluetooth: delete a stray unlock Bluetooth: Fix memory leak in hci_connect_le_scan media: flexcop-usb: ensure -EIO is returned on error condition regulator: ab8500: Remove AB8505 USB regulator media: usb: fix memory leak in af9005_identify_state tty: serial: msm_serial: Fix lockup for sysrq and oops fix compat handling of FICLONERANGE, FIDEDUPERANGE and FS_IOC_FIEMAP drm/mst: Fix MST sideband up-reply failure handling powerpc/pseries/hvconsole: Fix stack overread via udbg rxrpc: Fix possible NULL pointer access in ICMP handling ath9k_htc: Modify byte order for an error message ath9k_htc: Discard undersized packets net: add annotations on hh->hh_len lockless accesses s390/smp: fix physical to logical CPU map for SMT xen/blkback: Avoid unmapping unmapped grant pages locking/x86: Remove the unused atomic_inc_short() methd pstore/ram: Write new dumps to start of recycled zones locking/spinlock/debug: Fix various data races netfilter: ctnetlink: netns exit must wait for callbacks efi/gop: Return EFI_NOT_FOUND if there are no usable GOPs efi/gop: Return EFI_SUCCESS if a usable GOP was found efi/gop: Fix memory leak in __gop_query32/64() ARM: vexpress: Set-up shared OPP table instead of individual for each CPU netfilter: uapi: Avoid undefined left-shift in xt_sctp.h spi: spi-cavium-thunderx: Add missing pci_release_regions() ARM: dts: am437x-gp/epos-evm: fix panel compatible samples: bpf: Replace symbol compare of trace_event powerpc: Ensure that swiotlb buffer is allocated from low memory bnx2x: Do not handle requests from VFs after parity bnx2x: Fix logic to get total no. of PFs per engine net: usb: lan78xx: Fix error message format specifier rfkill: Fix incorrect check to avoid NULL pointer dereference ASoC: wm8962: fix lambda value regulator: rn5t618: fix module aliases kconfig: don't crash on NULL expressions in expr_eq() perf/x86/intel: Fix PT PMI handling net: stmmac: RX buffer size must be 16 byte aligned block: fix memleak when __blk_rq_map_user_iov() is failed parisc: Fix compiler warnings in debug_core.c llc2: Fix return statement of llc_stat_ev_rx_null_dsap_xid_c (and _test_c) macvlan: do not assume mac_header is set in macvlan_broadcast() net: stmmac: dwmac-sunxi: Allow all RGMII modes net: usb: lan78xx: fix possible skb leak pkt_sched: fq: do not accept silly TCA_FQ_QUANTUM sctp: free cmd->obj.chunk for the unprocessed SCTP_CMD_REPLY tcp: fix "old stuff" D-SACK causing SACK to be treated as D-SACK vxlan: fix tos value before xmit vlan: vlan_changelink() should propagate errors net: sch_prio: When ungrafting, replace with FIFO vlan: fix memory leak in vlan_dev_set_egress_priority USB: core: fix check for duplicate endpoints USB: serial: option: add Telit ME910G1 0x110a composition Linux 4.9.209 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I37562d713bddce2ead7934800c3f9e231884c43f
282 lines
6.9 KiB
C
282 lines
6.9 KiB
C
/*
|
|
* VLAN netlink control interface
|
|
*
|
|
* Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* version 2 as published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/if_vlan.h>
|
|
#include <linux/module.h>
|
|
#include <net/net_namespace.h>
|
|
#include <net/netlink.h>
|
|
#include <net/rtnetlink.h>
|
|
#include "vlan.h"
|
|
|
|
|
|
static const struct nla_policy vlan_policy[IFLA_VLAN_MAX + 1] = {
|
|
[IFLA_VLAN_ID] = { .type = NLA_U16 },
|
|
[IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) },
|
|
[IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED },
|
|
[IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
|
|
[IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 },
|
|
};
|
|
|
|
static const struct nla_policy vlan_map_policy[IFLA_VLAN_QOS_MAX + 1] = {
|
|
[IFLA_VLAN_QOS_MAPPING] = { .len = sizeof(struct ifla_vlan_qos_mapping) },
|
|
};
|
|
|
|
|
|
static inline int vlan_validate_qos_map(struct nlattr *attr)
|
|
{
|
|
if (!attr)
|
|
return 0;
|
|
return nla_validate_nested(attr, IFLA_VLAN_QOS_MAX, vlan_map_policy);
|
|
}
|
|
|
|
static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
|
|
{
|
|
struct ifla_vlan_flags *flags;
|
|
u16 id;
|
|
int err;
|
|
|
|
if (tb[IFLA_ADDRESS]) {
|
|
if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
|
|
return -EINVAL;
|
|
if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
|
|
return -EADDRNOTAVAIL;
|
|
}
|
|
|
|
if (!data)
|
|
return -EINVAL;
|
|
|
|
if (data[IFLA_VLAN_PROTOCOL]) {
|
|
switch (nla_get_be16(data[IFLA_VLAN_PROTOCOL])) {
|
|
case htons(ETH_P_8021Q):
|
|
case htons(ETH_P_8021AD):
|
|
break;
|
|
default:
|
|
return -EPROTONOSUPPORT;
|
|
}
|
|
}
|
|
|
|
if (data[IFLA_VLAN_ID]) {
|
|
id = nla_get_u16(data[IFLA_VLAN_ID]);
|
|
if (id >= VLAN_VID_MASK)
|
|
return -ERANGE;
|
|
}
|
|
if (data[IFLA_VLAN_FLAGS]) {
|
|
flags = nla_data(data[IFLA_VLAN_FLAGS]);
|
|
if ((flags->flags & flags->mask) &
|
|
~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
|
|
VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP))
|
|
return -EINVAL;
|
|
}
|
|
|
|
err = vlan_validate_qos_map(data[IFLA_VLAN_INGRESS_QOS]);
|
|
if (err < 0)
|
|
return err;
|
|
err = vlan_validate_qos_map(data[IFLA_VLAN_EGRESS_QOS]);
|
|
if (err < 0)
|
|
return err;
|
|
return 0;
|
|
}
|
|
|
|
static int vlan_changelink(struct net_device *dev,
|
|
struct nlattr *tb[], struct nlattr *data[])
|
|
{
|
|
struct ifla_vlan_flags *flags;
|
|
struct ifla_vlan_qos_mapping *m;
|
|
struct nlattr *attr;
|
|
int rem, err;
|
|
|
|
if (data[IFLA_VLAN_FLAGS]) {
|
|
flags = nla_data(data[IFLA_VLAN_FLAGS]);
|
|
err = vlan_dev_change_flags(dev, flags->flags, flags->mask);
|
|
if (err)
|
|
return err;
|
|
}
|
|
if (data[IFLA_VLAN_INGRESS_QOS]) {
|
|
nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) {
|
|
m = nla_data(attr);
|
|
vlan_dev_set_ingress_priority(dev, m->to, m->from);
|
|
}
|
|
}
|
|
if (data[IFLA_VLAN_EGRESS_QOS]) {
|
|
nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) {
|
|
m = nla_data(attr);
|
|
err = vlan_dev_set_egress_priority(dev, m->from, m->to);
|
|
if (err)
|
|
return err;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int vlan_newlink(struct net *src_net, struct net_device *dev,
|
|
struct nlattr *tb[], struct nlattr *data[])
|
|
{
|
|
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
|
|
struct net_device *real_dev;
|
|
unsigned int max_mtu;
|
|
__be16 proto;
|
|
int err;
|
|
|
|
if (!data[IFLA_VLAN_ID])
|
|
return -EINVAL;
|
|
|
|
if (!tb[IFLA_LINK])
|
|
return -EINVAL;
|
|
real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
|
|
if (!real_dev)
|
|
return -ENODEV;
|
|
|
|
if (data[IFLA_VLAN_PROTOCOL])
|
|
proto = nla_get_be16(data[IFLA_VLAN_PROTOCOL]);
|
|
else
|
|
proto = htons(ETH_P_8021Q);
|
|
|
|
vlan->vlan_proto = proto;
|
|
vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]);
|
|
vlan->real_dev = real_dev;
|
|
vlan->flags = VLAN_FLAG_REORDER_HDR;
|
|
|
|
err = vlan_check_real_dev(real_dev, vlan->vlan_proto, vlan->vlan_id);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
max_mtu = netif_reduces_vlan_mtu(real_dev) ? real_dev->mtu - VLAN_HLEN :
|
|
real_dev->mtu;
|
|
if (!tb[IFLA_MTU])
|
|
dev->mtu = max_mtu;
|
|
else if (dev->mtu > max_mtu)
|
|
return -EINVAL;
|
|
|
|
err = vlan_changelink(dev, tb, data);
|
|
if (!err)
|
|
err = register_vlan_dev(dev);
|
|
if (err)
|
|
vlan_dev_uninit(dev);
|
|
return err;
|
|
}
|
|
|
|
static inline size_t vlan_qos_map_size(unsigned int n)
|
|
{
|
|
if (n == 0)
|
|
return 0;
|
|
/* IFLA_VLAN_{EGRESS,INGRESS}_QOS + n * IFLA_VLAN_QOS_MAPPING */
|
|
return nla_total_size(sizeof(struct nlattr)) +
|
|
nla_total_size(sizeof(struct ifla_vlan_qos_mapping)) * n;
|
|
}
|
|
|
|
static size_t vlan_get_size(const struct net_device *dev)
|
|
{
|
|
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
|
|
|
|
return nla_total_size(2) + /* IFLA_VLAN_PROTOCOL */
|
|
nla_total_size(2) + /* IFLA_VLAN_ID */
|
|
nla_total_size(sizeof(struct ifla_vlan_flags)) + /* IFLA_VLAN_FLAGS */
|
|
vlan_qos_map_size(vlan->nr_ingress_mappings) +
|
|
vlan_qos_map_size(vlan->nr_egress_mappings);
|
|
}
|
|
|
|
static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|
{
|
|
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
|
|
struct vlan_priority_tci_mapping *pm;
|
|
struct ifla_vlan_flags f;
|
|
struct ifla_vlan_qos_mapping m;
|
|
struct nlattr *nest;
|
|
unsigned int i;
|
|
|
|
if (nla_put_be16(skb, IFLA_VLAN_PROTOCOL, vlan->vlan_proto) ||
|
|
nla_put_u16(skb, IFLA_VLAN_ID, vlan->vlan_id))
|
|
goto nla_put_failure;
|
|
if (vlan->flags) {
|
|
f.flags = vlan->flags;
|
|
f.mask = ~0;
|
|
if (nla_put(skb, IFLA_VLAN_FLAGS, sizeof(f), &f))
|
|
goto nla_put_failure;
|
|
}
|
|
if (vlan->nr_ingress_mappings) {
|
|
nest = nla_nest_start(skb, IFLA_VLAN_INGRESS_QOS);
|
|
if (nest == NULL)
|
|
goto nla_put_failure;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(vlan->ingress_priority_map); i++) {
|
|
if (!vlan->ingress_priority_map[i])
|
|
continue;
|
|
|
|
m.from = i;
|
|
m.to = vlan->ingress_priority_map[i];
|
|
if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
|
|
sizeof(m), &m))
|
|
goto nla_put_failure;
|
|
}
|
|
nla_nest_end(skb, nest);
|
|
}
|
|
|
|
if (vlan->nr_egress_mappings) {
|
|
nest = nla_nest_start(skb, IFLA_VLAN_EGRESS_QOS);
|
|
if (nest == NULL)
|
|
goto nla_put_failure;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
|
|
for (pm = vlan->egress_priority_map[i]; pm;
|
|
pm = pm->next) {
|
|
if (!pm->vlan_qos)
|
|
continue;
|
|
|
|
m.from = pm->priority;
|
|
m.to = (pm->vlan_qos >> 13) & 0x7;
|
|
if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
|
|
sizeof(m), &m))
|
|
goto nla_put_failure;
|
|
}
|
|
}
|
|
nla_nest_end(skb, nest);
|
|
}
|
|
return 0;
|
|
|
|
nla_put_failure:
|
|
return -EMSGSIZE;
|
|
}
|
|
|
|
static struct net *vlan_get_link_net(const struct net_device *dev)
|
|
{
|
|
struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
|
|
|
|
return dev_net(real_dev);
|
|
}
|
|
|
|
struct rtnl_link_ops vlan_link_ops __read_mostly = {
|
|
.kind = "vlan",
|
|
.maxtype = IFLA_VLAN_MAX,
|
|
.policy = vlan_policy,
|
|
.priv_size = sizeof(struct vlan_dev_priv),
|
|
.setup = vlan_setup,
|
|
.validate = vlan_validate,
|
|
.newlink = vlan_newlink,
|
|
.changelink = vlan_changelink,
|
|
.dellink = unregister_vlan_dev,
|
|
.get_size = vlan_get_size,
|
|
.fill_info = vlan_fill_info,
|
|
.get_link_net = vlan_get_link_net,
|
|
};
|
|
|
|
int __init vlan_netlink_init(void)
|
|
{
|
|
return rtnl_link_register(&vlan_link_ops);
|
|
}
|
|
|
|
void __exit vlan_netlink_fini(void)
|
|
{
|
|
rtnl_link_unregister(&vlan_link_ops);
|
|
}
|
|
|
|
MODULE_ALIAS_RTNL_LINK("vlan");
|