/* * VLAN netlink control interface * * Copyright (c) 2007 Patrick McHardy * * 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 #include #include #include #include #include #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 }, }; 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_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) 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 vlan_dev_info *vlan = VLAN_DEV_INFO(dev); struct ifla_vlan_flags *flags; struct ifla_vlan_qos_mapping *m; struct nlattr *attr; int rem; if (data[IFLA_VLAN_FLAGS]) { flags = nla_data(data[IFLA_VLAN_FLAGS]); vlan->flags = (vlan->flags & ~flags->mask) | (flags->flags & flags->mask); } 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); vlan_dev_set_egress_priority(dev, m->from, m->to); } } return 0; } static int vlan_newlink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev); struct net_device *real_dev; int err; if (!data[IFLA_VLAN_ID]) return -EINVAL; if (!tb[IFLA_LINK]) return -EINVAL; real_dev = __dev_get_by_index(&init_net, nla_get_u32(tb[IFLA_LINK])); if (!real_dev) return -ENODEV; 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_id); if (err < 0) return err; if (!tb[IFLA_MTU]) dev->mtu = real_dev->mtu; else if (dev->mtu > real_dev->mtu) return -EINVAL; err = vlan_changelink(dev, tb, data); if (err < 0) return err; return register_vlan_dev(dev); } static void vlan_dellink(struct net_device *dev) { unregister_vlan_device(dev); } 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_info *vlan = VLAN_DEV_INFO(dev); return nla_total_size(2) + /* IFLA_VLAN_ID */ 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_info *vlan = VLAN_DEV_INFO(dev); struct vlan_priority_tci_mapping *pm; struct ifla_vlan_flags f; struct ifla_vlan_qos_mapping m; struct nlattr *nest; unsigned int i; NLA_PUT_U16(skb, IFLA_VLAN_ID, VLAN_DEV_INFO(dev)->vlan_id); if (vlan->flags) { f.flags = vlan->flags; f.mask = ~0; NLA_PUT(skb, IFLA_VLAN_FLAGS, sizeof(f), &f); } 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]; NLA_PUT(skb, IFLA_VLAN_QOS_MAPPING, sizeof(m), &m); } 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; NLA_PUT(skb, IFLA_VLAN_QOS_MAPPING, sizeof(m), &m); } } nla_nest_end(skb, nest); } return 0; nla_put_failure: return -EMSGSIZE; } struct rtnl_link_ops vlan_link_ops __read_mostly = { .kind = "vlan", .maxtype = IFLA_VLAN_MAX, .policy = vlan_policy, .priv_size = sizeof(struct vlan_dev_info), .setup = vlan_setup, .validate = vlan_validate, .newlink = vlan_newlink, .changelink = vlan_changelink, .dellink = vlan_dellink, .get_size = vlan_get_size, .fill_info = vlan_fill_info, }; 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"); harger.c?h=net-next&showmsg=1'>sc2731_charger.c
AgeCommit message (Collapse)Author
2024-10-21power: Switch back to struct platform_driver::remove()Uwe Kleine-König
After commit 0edb555a65d1 ("platform: Make platform_driver::remove() return void") .remove() is (again) the right callback to implement for platform drivers. Convert all platform drivers below drivers/power/ to use .remove(), with the eventual goal to drop struct platform_driver::remove_new(). As .remove() and .remove_new() have the same prototypes, conversion is done by just changing the structure member name in the driver initializer. While touching these files, make indention of the struct initializer consistent in several files. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com> Link: https://lore.kernel.org/r/20241010203622.839625-6-u.kleine-koenig@baylibre.com Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
2023-09-18power: supply: sc2731_charger: Convert to platform remove callback returning ↵Uwe Kleine-König
void The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Link: https://lore.kernel.org/r/20230918133700.1254499-25-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
2022-01-03power: supply_core: Pass pointer to battery infoLinus Walleij
The function to retrieve battery info (from the device tree) assumes we have a static info struct that gets populated by calling into power_supply_get_battery_info(). This is awkward since I want to support tables of static battery info by just assigning a pointer to all info based on e.g. a compatible value in the device tree. We also have a mixture of static and dynamically allocated variables here. Bite the bullet and let power_supply_get_battery_info() allocate also the memory used for the very top level struct power_supply_battery_info container. Pass pointers around and lifecycle this with the psy device just like the stuff we allocate inside it. Change all current users over. As part of the change, initializers need to be added to some previously uninitialized fields in struct power_supply_battery_info. Reviewed-By: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
2021-05-13power: supply: sc2731_charger: Add missing MODULE_DEVICE_TABLEZou Wei
This patch adds missing MODULE_DEVICE_TABLE definition which generates correct modalias for automatic loading of this driver when it is built as an external module. Reported-by: Hulk Robot <hulkci@huawei.com> Signed-off-by: Zou Wei <zou_wei@huawei.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
2018-12-05power: supply: sc2731_charger: Free battery informationBaolin Wang
Free battery information in case of adding battery OCV tables. Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
2018-12-05power: supply: sc2731_charger: Avoid repeated charge/dischargeBaolin Wang
Add info->charging validation to avoid repeated charge or discharge operation. Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
2018-12-05power: supply: sc2731_charger: Add charger status detectionBaolin Wang
The USB charger status can be notified before the charger driver registers the USB phy notifier, so we should check the charger status in probe() in case we missed the USB charger notification. Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
2018-12-05power: supply: sc2731_charger: Add one work to charge/dischargeBaolin Wang
Since the USB notifier context is atomic, we can not start or stop charging in atomic context. Thus this patch adds one work to help to charge or discharge. Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
2018-09-20power: supply: Add Spreadtrum SC2731 charger supportBaolin Wang
This patch adds the SC2731 PMIC switch charger support. Signed-off-by: Baolin Wang <baolin.wang@linaro.org> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>