mirror of
https://github.com/tikoci/mikrotik-gpl.git
synced 2025-12-10 07:44:45 +01:00
rename dir with correct year
This commit is contained in:
parent
9c02be5a6c
commit
2eb07b25a1
79236 changed files with 32443970 additions and 0 deletions
31
2025-03-19/atl1c/Makefile
Normal file
31
2025-03-19/atl1c/Makefile
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
MODULE = x86_64/atl1c.ko \
|
||||
powerpc/atl1c.ko 440/atl1c.ko e500/atl1c.ko e500-smp/atl1c.ko \
|
||||
tile/atl1c.ko arm64/atl1c.ko arm/atl1c.ko
|
||||
|
||||
atl1c_FILES = atl1c.c
|
||||
atl1c_PREFIX = drivers/net
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
EXTRA_CFLAGS := $(CFLAGS)
|
||||
|
||||
define moddef
|
||||
obj-m += $(1).o
|
||||
ifneq ($(1).o, $(2))
|
||||
$(1)-y := $(2)
|
||||
EXTRA_CFLAGS += $($(1)_CFLAGS)
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach m, $(MODULE), $(eval $(call moddef,$(m:.ko=),$($(m:.ko=)_FILES:.c=.o))))
|
||||
|
||||
EXTRA_CFLAGS := $(subst -I, -I$(src)/, $(EXTRA_CFLAGS))
|
||||
|
||||
else
|
||||
|
||||
KERNELDIR := /lib/modules/$$(uname -r)/build
|
||||
|
||||
all::
|
||||
$(MAKE) -C $(KERNELDIR) M=$$(pwd) $@
|
||||
|
||||
endif
|
||||
2896
2025-03-19/atl1c/atl1c.c
Normal file
2896
2025-03-19/atl1c/atl1c.c
Normal file
File diff suppressed because it is too large
Load diff
1566
2025-03-19/atl1c/atl1c.h
Normal file
1566
2025-03-19/atl1c/atl1c.h
Normal file
File diff suppressed because it is too large
Load diff
39
2025-03-19/bridge2/Makefile
Normal file
39
2025-03-19/bridge2/Makefile
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
MODULE = bridge2.ko bridge2_netfilter.ko
|
||||
|
||||
bridge2_FILES = br_fdb.c br_input.c br_forward.c br_if.c \
|
||||
br_device.c br_ioctl.c br.c br_nf_core.c fast_path.c \
|
||||
br_multicast.c br_vlan.c br_netlink.c \
|
||||
br_dhcp_snooping.c br_vlan_tunnel.c br_netlink_tunnel.c br_vlan_options.c \
|
||||
br_mdb.c br_switchdev.c
|
||||
|
||||
bridge2_PREFIX = net/bridge
|
||||
bridge2_CFLAGS += -O2 --param=max-inline-insns-auto=40
|
||||
|
||||
bridge2_netfilter_FILES = br_nf_core.c br_netfilter_hooks.c br_netfilter_ipv6.c
|
||||
bridge2_netfilter_PREFIX = net/bridge
|
||||
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
EXTRA_CFLAGS := $(CFLAGS)
|
||||
|
||||
define moddef
|
||||
obj-m += $(1).o
|
||||
ifneq ($(1).o, $(2))
|
||||
$(1)-y := $(2)
|
||||
EXTRA_CFLAGS += $($(1)_CFLAGS)
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach m, $(MODULE), $(eval $(call moddef,$(m:.ko=),$($(m:.ko=)_FILES:.c=.o))))
|
||||
|
||||
EXTRA_CFLAGS := $(subst -I, -I$(src)/, $(EXTRA_CFLAGS))
|
||||
|
||||
else
|
||||
|
||||
KERNELDIR := /lib/modules/$$(uname -r)/build
|
||||
|
||||
all::
|
||||
$(MAKE) -C $(KERNELDIR) M=$$(pwd) $@
|
||||
|
||||
endif
|
||||
412
2025-03-19/bridge2/br.c
Normal file
412
2025-03-19/bridge2/br.c
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Generic parts
|
||||
* Linux ethernet bridge
|
||||
*
|
||||
* Authors:
|
||||
* Lennert Buytenhek <buytenh@gnu.org>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/llc.h>
|
||||
#include <net/llc.h>
|
||||
#include <net/stp.h>
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "br_private.h"
|
||||
|
||||
int __init bridge_fast_path_init(void);
|
||||
void __exit bridge_fast_path_exit(void);
|
||||
|
||||
#include <net/addrconf.h>
|
||||
|
||||
/*
|
||||
* Handle changes in state of network devices enslaved to a bridge.
|
||||
*
|
||||
* Note: don't care about up/down if bridge itself is down, because
|
||||
* port state is checked when bridge is brought up.
|
||||
*/
|
||||
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
|
||||
{
|
||||
struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
|
||||
struct netdev_notifier_pre_changeaddr_info *prechaddr_info;
|
||||
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
struct net_bridge_port *p;
|
||||
struct net_bridge *br;
|
||||
bool notified = false;
|
||||
// bool changed_addr;
|
||||
int err;
|
||||
|
||||
if (dev->priv_flags & IFF_EBRIDGE) {
|
||||
err = br_vlan_bridge_event(dev, event, ptr);
|
||||
if (err)
|
||||
return notifier_from_errno(err);
|
||||
|
||||
if (event == NETDEV_REGISTER) {
|
||||
// /* register of bridge completed, add sysfs entries */
|
||||
// br_sysfs_addbr(dev);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* not a port of a bridge */
|
||||
p = br_port_get_rtnl(dev);
|
||||
if (!p)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
br = p->br;
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_CHANGEMTU:
|
||||
// FIXME - do we really disable? Now it doesnt change if user has changed.
|
||||
// br_mtu_auto_adjust(br);
|
||||
break;
|
||||
|
||||
case NETDEV_PRE_CHANGEADDR:
|
||||
if (br->dev->addr_assign_type == NET_ADDR_SET)
|
||||
break;
|
||||
prechaddr_info = ptr;
|
||||
err = dev_pre_changeaddr_notify(br->dev,
|
||||
prechaddr_info->dev_addr,
|
||||
extack);
|
||||
if (err)
|
||||
return notifier_from_errno(err);
|
||||
break;
|
||||
|
||||
case NETDEV_CHANGEADDR:
|
||||
spin_lock_bh(&br->lock);
|
||||
br_fdb_changeaddr(p, dev->dev_addr);
|
||||
// changed_addr = br_stp_recalculate_bridge_id(br);
|
||||
spin_unlock_bh(&br->lock);
|
||||
|
||||
// if (changed_addr)
|
||||
// call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
|
||||
|
||||
break;
|
||||
|
||||
case NETDEV_CHANGE:
|
||||
// FIXME? this could call br_stp_disable_port which affect backup and multicast
|
||||
// br_port_carrier_check(p, ¬ified);
|
||||
break;
|
||||
|
||||
case NETDEV_FEAT_CHANGE:
|
||||
netdev_update_features(br->dev);
|
||||
break;
|
||||
|
||||
case NETDEV_DOWN:
|
||||
spin_lock_bh(&br->lock);
|
||||
if (br->dev->flags & IFF_UP) {
|
||||
// br_stp_disable_port(p);
|
||||
// notified = true;
|
||||
{
|
||||
if (!rcu_access_pointer(p->backup_port))
|
||||
br_fdb_delete_by_port(br, p, 0, 0);
|
||||
br_multicast_disable_port(p);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&br->lock);
|
||||
break;
|
||||
|
||||
case NETDEV_UP:
|
||||
// if (netif_running(br->dev) && netif_oper_up(dev)) {
|
||||
// spin_lock_bh(&br->lock);
|
||||
// br_stp_enable_port(p);
|
||||
// notified = true;
|
||||
// spin_unlock_bh(&br->lock);
|
||||
// }
|
||||
break;
|
||||
|
||||
case NETDEV_UNREGISTER:
|
||||
br_del_if(br, dev);
|
||||
break;
|
||||
|
||||
case NETDEV_CHANGENAME:
|
||||
// err = br_sysfs_renameif(p);
|
||||
// if (err)
|
||||
// return notifier_from_errno(err);
|
||||
break;
|
||||
|
||||
case NETDEV_PRE_TYPE_CHANGE:
|
||||
/* Forbid underlaying device to change its type. */
|
||||
return NOTIFY_BAD;
|
||||
|
||||
case NETDEV_RESEND_IGMP:
|
||||
/* Propagate to master device */
|
||||
call_netdevice_notifiers(event, br->dev);
|
||||
break;
|
||||
}
|
||||
|
||||
if (event != NETDEV_UNREGISTER)
|
||||
br_vlan_port_event(p, event);
|
||||
|
||||
/* Events that may cause spanning tree to refresh */
|
||||
if (!notified && (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||
|
||||
event == NETDEV_CHANGE || event == NETDEV_DOWN))
|
||||
br_ifinfo_notify(RTM_NEWLINK, NULL, p);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block br_device_notifier = {
|
||||
.notifier_call = br_device_event
|
||||
};
|
||||
|
||||
/* called with RTNL or RCU */
|
||||
static int br_switchdev_event(struct notifier_block *unused,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
|
||||
struct net_bridge_port *p;
|
||||
struct net_bridge *br;
|
||||
struct switchdev_notifier_fdb_info *fdb_info;
|
||||
int err = NOTIFY_DONE;
|
||||
|
||||
p = br_port_get_rtnl_rcu(dev);
|
||||
if (!p)
|
||||
goto out;
|
||||
|
||||
br = p->br;
|
||||
|
||||
switch (event) {
|
||||
case SWITCHDEV_FDB_ADD_TO_BRIDGE:
|
||||
fdb_info = ptr;
|
||||
err = br_fdb_external_learn_add(br, p, fdb_info->addr,
|
||||
fdb_info->vid, false);
|
||||
if (err) {
|
||||
err = notifier_from_errno(err);
|
||||
break;
|
||||
}
|
||||
br_fdb_offloaded_set(br, p, fdb_info->addr,
|
||||
fdb_info->vid, true);
|
||||
break;
|
||||
case SWITCHDEV_FDB_DEL_TO_BRIDGE:
|
||||
fdb_info = ptr;
|
||||
err = br_fdb_external_learn_del(br, p, fdb_info->addr,
|
||||
fdb_info->vid, false);
|
||||
if (err)
|
||||
err = notifier_from_errno(err);
|
||||
break;
|
||||
case SWITCHDEV_FDB_OFFLOADED:
|
||||
fdb_info = ptr;
|
||||
br_fdb_offloaded_set(br, p, fdb_info->addr,
|
||||
fdb_info->vid, fdb_info->offloaded);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block br_switchdev_notifier = {
|
||||
.notifier_call = br_switchdev_event,
|
||||
};
|
||||
|
||||
/* br_boolopt_toggle - change user-controlled boolean option
|
||||
*
|
||||
* @br: bridge device
|
||||
* @opt: id of the option to change
|
||||
* @on: new option value
|
||||
* @extack: extack for error messages
|
||||
*
|
||||
* Changes the value of the respective boolean option to @on taking care of
|
||||
* any internal option value mapping and configuration.
|
||||
*/
|
||||
int br_boolopt_toggle(struct net_bridge *br, enum br_boolopt_id opt, bool on,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
switch (opt) {
|
||||
case BR_BOOLOPT_NO_LL_LEARN:
|
||||
br_opt_toggle(br, BROPT_NO_LL_LEARN, on);
|
||||
break;
|
||||
default:
|
||||
/* shouldn't be called with unsupported options */
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int br_boolopt_get(const struct net_bridge *br, enum br_boolopt_id opt)
|
||||
{
|
||||
switch (opt) {
|
||||
case BR_BOOLOPT_NO_LL_LEARN:
|
||||
return br_opt_get(br, BROPT_NO_LL_LEARN);
|
||||
default:
|
||||
/* shouldn't be called with unsupported options */
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int br_boolopt_multi_toggle(struct net_bridge *br,
|
||||
struct br_boolopt_multi *bm,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
unsigned long bitmap = bm->optmask;
|
||||
int err = 0;
|
||||
int opt_id;
|
||||
|
||||
for_each_set_bit(opt_id, &bitmap, BR_BOOLOPT_MAX) {
|
||||
bool on = !!(bm->optval & BIT(opt_id));
|
||||
|
||||
err = br_boolopt_toggle(br, opt_id, on, extack);
|
||||
if (err) {
|
||||
br_debug(br, "boolopt multi-toggle error: option: %d current: %d new: %d error: %d\n",
|
||||
opt_id, br_boolopt_get(br, opt_id), on, err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void br_boolopt_multi_get(const struct net_bridge *br,
|
||||
struct br_boolopt_multi *bm)
|
||||
{
|
||||
u32 optval = 0;
|
||||
int opt_id;
|
||||
|
||||
for (opt_id = 0; opt_id < BR_BOOLOPT_MAX; opt_id++)
|
||||
optval |= (br_boolopt_get(br, opt_id) << opt_id);
|
||||
|
||||
bm->optval = optval;
|
||||
bm->optmask = GENMASK((BR_BOOLOPT_MAX - 1), 0);
|
||||
}
|
||||
|
||||
/* private bridge options, controlled by the kernel */
|
||||
void br_opt_toggle(struct net_bridge *br, enum net_bridge_opts opt, bool on)
|
||||
{
|
||||
bool cur = !!br_opt_get(br, opt);
|
||||
|
||||
br_debug(br, "toggle option: %d state: %d -> %d\n",
|
||||
opt, cur, on);
|
||||
|
||||
if (cur == on)
|
||||
return;
|
||||
|
||||
if (on)
|
||||
set_bit(opt, &br->options);
|
||||
else
|
||||
clear_bit(opt, &br->options);
|
||||
}
|
||||
|
||||
static void __net_exit br_net_exit(struct net *net)
|
||||
{
|
||||
struct net_device *dev;
|
||||
LIST_HEAD(list);
|
||||
|
||||
rtnl_lock();
|
||||
for_each_netdev(net, dev)
|
||||
if (dev->priv_flags & IFF_EBRIDGE)
|
||||
br_dev_delete(dev, &list);
|
||||
|
||||
unregister_netdevice_many(&list);
|
||||
rtnl_unlock();
|
||||
|
||||
}
|
||||
|
||||
static struct pernet_operations br_net_ops = {
|
||||
.exit = br_net_exit,
|
||||
};
|
||||
|
||||
//static const struct stp_proto br_stp_proto = {
|
||||
// .rcv = br_stp_rcv,
|
||||
//};
|
||||
|
||||
static int __init br_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct br_input_skb_cb) > sizeof_field(struct sk_buff, cb));
|
||||
|
||||
// err = stp_proto_register(&br_stp_proto);
|
||||
// if (err < 0) {
|
||||
// pr_err("bridge: can't register sap for STP\n");
|
||||
// return err;
|
||||
// }
|
||||
|
||||
err = br_fdb_init();
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = register_pernet_subsys(&br_net_ops);
|
||||
if (err)
|
||||
goto err_out1;
|
||||
|
||||
err = br_nf_core_init();
|
||||
if (err)
|
||||
goto err_out2;
|
||||
|
||||
err = register_netdevice_notifier(&br_device_notifier);
|
||||
if (err)
|
||||
goto err_out3;
|
||||
|
||||
err = register_switchdev_notifier(&br_switchdev_notifier);
|
||||
if (err)
|
||||
goto err_out4;
|
||||
|
||||
err = br_netlink_init();
|
||||
if (err)
|
||||
goto err_out5;
|
||||
|
||||
brioctl_set(br_ioctl_deviceless_stub);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ATM_LANE)
|
||||
br_fdb_test_addr_hook = br_fdb_test_addr;
|
||||
#endif
|
||||
|
||||
#if IS_MODULE(CONFIG_BRIDGE_NETFILTER)
|
||||
pr_info("bridge: filtering via arp/ip/ip6tables is no longer available "
|
||||
"by default. Update your scripts to load br_netfilter if you "
|
||||
"need this.\n");
|
||||
#endif
|
||||
|
||||
bridge_fast_path_init();
|
||||
return 0;
|
||||
|
||||
err_out5:
|
||||
unregister_switchdev_notifier(&br_switchdev_notifier);
|
||||
err_out4:
|
||||
unregister_netdevice_notifier(&br_device_notifier);
|
||||
err_out3:
|
||||
br_nf_core_fini();
|
||||
err_out2:
|
||||
unregister_pernet_subsys(&br_net_ops);
|
||||
err_out1:
|
||||
br_fdb_fini();
|
||||
err_out:
|
||||
// stp_proto_unregister(&br_stp_proto);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit br_deinit(void)
|
||||
{
|
||||
// stp_proto_unregister(&br_stp_proto);
|
||||
bridge_fast_path_exit();
|
||||
br_netlink_fini();
|
||||
unregister_switchdev_notifier(&br_switchdev_notifier);
|
||||
unregister_netdevice_notifier(&br_device_notifier);
|
||||
brioctl_set(NULL);
|
||||
unregister_pernet_subsys(&br_net_ops);
|
||||
|
||||
rcu_barrier(); /* Wait for completion of call_rcu()'s */
|
||||
|
||||
br_nf_core_fini();
|
||||
#if IS_ENABLED(CONFIG_ATM_LANE)
|
||||
br_fdb_test_addr_hook = NULL;
|
||||
#endif
|
||||
br_fdb_fini();
|
||||
}
|
||||
|
||||
module_init(br_init)
|
||||
module_exit(br_deinit)
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(BR_VERSION);
|
||||
MODULE_ALIAS_RTNL_LINK("bridge");
|
||||
525
2025-03-19/bridge2/br_device.c
Normal file
525
2025-03-19/bridge2/br_device.c
Normal file
|
|
@ -0,0 +1,525 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Device handling code
|
||||
* Linux ethernet bridge
|
||||
*
|
||||
* Authors:
|
||||
* Lennert Buytenhek <buytenh@gnu.org>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netpoll.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include <linux/packet_hook.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include "br_private.h"
|
||||
|
||||
#define COMMON_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | \
|
||||
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM)
|
||||
|
||||
const struct nf_br_ops __rcu *nf_br_ops __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_br_ops);
|
||||
|
||||
/* net device transmit always called with BH disabled */
|
||||
netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
struct net_bridge_fdb_entry *dst;
|
||||
struct net_bridge_mdb_entry *mdst;
|
||||
// struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
|
||||
const struct nf_br_ops *nf_ops;
|
||||
u8 state = BR_STATE_FORWARDING;
|
||||
const unsigned char *dest;
|
||||
u16 vid = 0;
|
||||
|
||||
fast_path_sp_tx_inc(br->dev, skb->len);
|
||||
|
||||
rcu_read_lock();
|
||||
nf_ops = rcu_dereference(nf_br_ops);
|
||||
if (nf_ops && nf_ops->br_dev_xmit_hook(skb)) {
|
||||
rcu_read_unlock();
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
// u64_stats_update_begin(&brstats->syncp);
|
||||
// brstats->tx_packets++;
|
||||
// brstats->tx_bytes += skb->len;
|
||||
// u64_stats_update_end(&brstats->syncp);
|
||||
|
||||
br_switchdev_frame_unmark(skb);
|
||||
BR_INPUT_SKB_CB(skb)->brdev = dev;
|
||||
// BR_INPUT_SKB_CB(skb)->frag_max_size = 0;
|
||||
BR_INPUT_SKB_CB(skb)->dhcp_rep = 0;
|
||||
BR_INPUT_SKB_CB(skb)->dhcp_req = 0;
|
||||
BR_INPUT_SKB_CB(skb)->igmp = 0;
|
||||
BR_INPUT_SKB_CB(skb)->mrouters_only = 0;
|
||||
BR_INPUT_SKB_CB(skb)->ll_mc = 0;
|
||||
BR_INPUT_SKB_CB(skb)->src_port_hw_switched = 0;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_pull(skb, ETH_HLEN);
|
||||
|
||||
if (!br_allowed_ingress(br, br_vlan_group_rcu(br), br->vlan_ingress, skb, &vid, &state))
|
||||
goto out;
|
||||
|
||||
// if (IS_ENABLED(CONFIG_INET) &&
|
||||
// (eth_hdr(skb)->h_proto == htons(ETH_P_ARP) ||
|
||||
// eth_hdr(skb)->h_proto == htons(ETH_P_RARP)) &&
|
||||
// br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) {
|
||||
// br_do_proxy_suppress_arp(skb, br, vid, NULL);
|
||||
// } else if (IS_ENABLED(CONFIG_IPV6) &&
|
||||
// skb->protocol == htons(ETH_P_IPV6) &&
|
||||
// br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) &&
|
||||
// pskb_may_pull(skb, sizeof(struct ipv6hdr) +
|
||||
// sizeof(struct nd_msg)) &&
|
||||
// ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
|
||||
// struct nd_msg *msg, _msg;
|
||||
|
||||
// msg = br_is_nd_neigh_msg(skb, &_msg);
|
||||
// if (msg)
|
||||
// br_do_suppress_nd(skb, br, vid, NULL, msg);
|
||||
// }
|
||||
|
||||
dest = eth_hdr(skb)->h_dest;
|
||||
if (is_broadcast_ether_addr(dest)) {
|
||||
br_flood(br, skb, BR_PKT_BROADCAST, false, true, BR_NOHORIZON, BR_NOSWITCH);
|
||||
} else if (is_multicast_ether_addr(dest)) {
|
||||
// if (unlikely(netpoll_tx_running(dev))) {
|
||||
// br_flood(br, skb, BR_PKT_MULTICAST, false, true, BR_NOHORIZON, BR_NOSWITCH);
|
||||
// goto out;
|
||||
// }
|
||||
if (br_multicast_rcv(br, NULL, skb, vid, false)) {
|
||||
kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mdst = br_mdb_get(br, skb, vid);
|
||||
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
|
||||
br_multicast_querier_exists(br, eth_hdr(skb)))
|
||||
br_multicast_flood(mdst, skb, false, true, BR_NOHORIZON, BR_NOSWITCH);
|
||||
else
|
||||
br_flood(br, skb, BR_PKT_MULTICAST, false, true, BR_NOHORIZON, BR_NOSWITCH);
|
||||
} else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) {
|
||||
br_forward(dst->dst, skb, false, true, BR_NOHORIZON, BR_NOSWITCH);
|
||||
} else {
|
||||
br_flood(br, skb, BR_PKT_UNICAST, false, true, BR_NOHORIZON, BR_NOSWITCH);
|
||||
}
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static int br_dev_init(struct net_device *dev)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
int err;
|
||||
// br->stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
||||
// if (!br->stats)
|
||||
// return -ENOMEM;
|
||||
|
||||
err = br_fdb_hash_init(br);
|
||||
if (err) {
|
||||
// free_percpu(br->stats);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = br_mdb_hash_init(br);
|
||||
if (err) {
|
||||
// free_percpu(br->stats);
|
||||
br_fdb_hash_fini(br);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = br_vlan_init(br);
|
||||
if (err) {
|
||||
// free_percpu(br->stats);
|
||||
br_mdb_hash_fini(br);
|
||||
br_fdb_hash_fini(br);
|
||||
return err;
|
||||
}
|
||||
|
||||
// err = br_multicast_init_stats(br);
|
||||
// if (err) {
|
||||
// free_percpu(br->stats);
|
||||
// br_vlan_flush(br);
|
||||
// br_mdb_hash_fini(br);
|
||||
// br_fdb_hash_fini(br);
|
||||
// }
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void br_dev_uninit(struct net_device *dev)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
|
||||
br_multicast_dev_del(br);
|
||||
// br_multicast_uninit_stats(br);
|
||||
br_vlan_flush(br);
|
||||
br_mdb_hash_fini(br);
|
||||
br_fdb_hash_fini(br);
|
||||
// free_percpu(br->stats);
|
||||
}
|
||||
|
||||
static int br_dev_open(struct net_device *dev)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
netdev_update_features(dev);
|
||||
netif_start_queue(dev);
|
||||
// br_stp_enable_bridge(br);
|
||||
{
|
||||
mod_delayed_work(system_long_wq, &br->gc_work, HZ / 10);
|
||||
}
|
||||
br_multicast_open(br);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void br_dev_set_multicast_list(struct net_device *dev)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
struct netdev_hw_addr *ha = NULL;
|
||||
struct net_bridge_vlan_group *vg = br_vlan_group(br);
|
||||
|
||||
br_update_fast_forward(br);
|
||||
|
||||
br_fdb_flush_bridge_local(br);
|
||||
netdev_for_each_uc_addr(ha, dev) {
|
||||
if (!vg) {
|
||||
br_fdb_insert(br, NULL, ha->addr, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void br_dev_change_rx_flags(struct net_device *dev, int change)
|
||||
{
|
||||
if (change & IFF_PROMISC)
|
||||
br_manage_promisc(netdev_priv(dev));
|
||||
}
|
||||
|
||||
static int br_dev_stop(struct net_device *dev)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
|
||||
// br_stp_disable_bridge(br);
|
||||
{
|
||||
cancel_delayed_work_sync(&br->gc_work);
|
||||
}
|
||||
br_multicast_stop(br);
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//static void br_get_stats64(struct net_device *dev,
|
||||
// struct rtnl_link_stats64 *stats)
|
||||
//{
|
||||
// struct net_bridge *br = netdev_priv(dev);
|
||||
// struct pcpu_sw_netstats tmp, sum = { 0 };
|
||||
// unsigned int cpu;
|
||||
|
||||
// for_each_possible_cpu(cpu) {
|
||||
// unsigned int start;
|
||||
// const struct pcpu_sw_netstats *bstats
|
||||
// = per_cpu_ptr(br->stats, cpu);
|
||||
// do {
|
||||
// start = u64_stats_fetch_begin_irq(&bstats->syncp);
|
||||
// memcpy(&tmp, bstats, sizeof(tmp));
|
||||
// } while (u64_stats_fetch_retry_irq(&bstats->syncp, start));
|
||||
// sum.tx_bytes += tmp.tx_bytes;
|
||||
// sum.tx_packets += tmp.tx_packets;
|
||||
// sum.rx_bytes += tmp.rx_bytes;
|
||||
// sum.rx_packets += tmp.rx_packets;
|
||||
// }
|
||||
|
||||
// stats->tx_bytes = sum.tx_bytes;
|
||||
// stats->tx_packets = sum.tx_packets;
|
||||
// stats->rx_bytes = sum.rx_bytes;
|
||||
// stats->rx_packets = sum.rx_packets;
|
||||
//}
|
||||
|
||||
static int br_change_mtu(struct net_device *dev, int new_mtu)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
|
||||
dev->mtu = new_mtu;
|
||||
|
||||
/* this flag will be cleared if the MTU was automatically adjusted */
|
||||
br_opt_toggle(br, BROPT_MTU_SET_BY_USER, true);
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
/* remember the MTU in the rtable for PMTU */
|
||||
dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int br_change_l2mtu(struct net_device *dev, int new_mtu)
|
||||
{
|
||||
dev->l2mtu = new_mtu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allow setting mac address to any valid ethernet address. */
|
||||
static int br_set_mac_address(struct net_device *dev, void *p)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
struct sockaddr *addr = p;
|
||||
|
||||
if (!is_valid_ether_addr(addr->sa_data))
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
/* dev_set_mac_addr() can be called by a master device on bridge's
|
||||
* NETDEV_UNREGISTER, but since it's being destroyed do nothing
|
||||
*/
|
||||
if (dev->reg_state != NETREG_REGISTERED)
|
||||
return -EBUSY;
|
||||
|
||||
spin_lock_bh(&br->lock);
|
||||
if (!ether_addr_equal(dev->dev_addr, addr->sa_data)) {
|
||||
br_fdb_change_mac_address(br, addr->sa_data);
|
||||
memcpy(br->dev->dev_addr, addr->sa_data, ETH_ALEN);
|
||||
// /* Mac address will be changed in br_stp_change_bridge_id(). */
|
||||
// br_stp_change_bridge_id(br, addr->sa_data);
|
||||
}
|
||||
spin_unlock_bh(&br->lock);
|
||||
|
||||
br_update_fast_forward(br);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
|
||||
{
|
||||
strlcpy(info->driver, "bridge", sizeof(info->driver));
|
||||
strlcpy(info->version, BR_VERSION, sizeof(info->version));
|
||||
strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
|
||||
strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
|
||||
}
|
||||
|
||||
static int br_get_link_ksettings(struct net_device *dev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
struct net_bridge_port *p;
|
||||
|
||||
cmd->base.duplex = DUPLEX_UNKNOWN;
|
||||
cmd->base.port = PORT_OTHER;
|
||||
cmd->base.speed = SPEED_UNKNOWN;
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
struct ethtool_link_ksettings ecmd;
|
||||
struct net_device *pdev = p->dev;
|
||||
|
||||
if (!netif_running(pdev) || !netif_oper_up(pdev))
|
||||
continue;
|
||||
|
||||
if (__ethtool_get_link_ksettings(pdev, &ecmd))
|
||||
continue;
|
||||
|
||||
if (ecmd.base.speed == (__u32)SPEED_UNKNOWN)
|
||||
continue;
|
||||
|
||||
if (cmd->base.speed == (__u32)SPEED_UNKNOWN ||
|
||||
cmd->base.speed < ecmd.base.speed)
|
||||
cmd->base.speed = ecmd.base.speed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static netdev_features_t br_fix_features(struct net_device *dev,
|
||||
netdev_features_t features)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
|
||||
return br_features_recompute(br, features);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
static void br_poll_controller(struct net_device *br_dev)
|
||||
{
|
||||
}
|
||||
|
||||
static void br_netpoll_cleanup(struct net_device *dev)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
struct net_bridge_port *p;
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list)
|
||||
br_netpoll_disable(p);
|
||||
}
|
||||
|
||||
static int __br_netpoll_enable(struct net_bridge_port *p)
|
||||
{
|
||||
struct netpoll *np;
|
||||
int err;
|
||||
|
||||
np = kzalloc(sizeof(*p->np), GFP_KERNEL);
|
||||
if (!np)
|
||||
return -ENOMEM;
|
||||
|
||||
err = __netpoll_setup(np, p->dev);
|
||||
if (err) {
|
||||
kfree(np);
|
||||
return err;
|
||||
}
|
||||
|
||||
p->np = np;
|
||||
return err;
|
||||
}
|
||||
|
||||
int br_netpoll_enable(struct net_bridge_port *p)
|
||||
{
|
||||
if (!p->br->dev->npinfo)
|
||||
return 0;
|
||||
|
||||
return __br_netpoll_enable(p);
|
||||
}
|
||||
|
||||
static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
struct net_bridge_port *p;
|
||||
int err = 0;
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (!p->dev)
|
||||
continue;
|
||||
err = __br_netpoll_enable(p);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
fail:
|
||||
br_netpoll_cleanup(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
void br_netpoll_disable(struct net_bridge_port *p)
|
||||
{
|
||||
struct netpoll *np = p->np;
|
||||
|
||||
if (!np)
|
||||
return;
|
||||
|
||||
p->np = NULL;
|
||||
|
||||
__netpoll_free(np);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int br_add_slave(struct net_device *dev, struct net_device *slave_dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
|
||||
return br_add_if(br, slave_dev, extack);
|
||||
}
|
||||
|
||||
static int br_del_slave(struct net_device *dev, struct net_device *slave_dev)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
|
||||
return br_del_if(br, slave_dev);
|
||||
}
|
||||
|
||||
static const struct ethtool_ops br_ethtool_ops = {
|
||||
.get_drvinfo = br_getinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_link_ksettings = br_get_link_ksettings,
|
||||
};
|
||||
|
||||
struct net_device_ops br_netdev_ops = {
|
||||
.ndo_open = br_dev_open,
|
||||
.ndo_stop = br_dev_stop,
|
||||
.ndo_init = br_dev_init,
|
||||
.ndo_uninit = br_dev_uninit,
|
||||
.ndo_start_xmit = br_dev_xmit,
|
||||
.ndo_get_stats64 = fast_path_get_stats64,
|
||||
.ndo_set_mac_address = br_set_mac_address,
|
||||
.ndo_set_rx_mode = br_dev_set_multicast_list,
|
||||
.ndo_change_rx_flags = br_dev_change_rx_flags,
|
||||
.ndo_change_mtu = br_change_mtu,
|
||||
.ndo_change_l2mtu = br_change_l2mtu,
|
||||
.ndo_do_ioctl = br_dev_ioctl,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_netpoll_setup = br_netpoll_setup,
|
||||
.ndo_netpoll_cleanup = br_netpoll_cleanup,
|
||||
.ndo_poll_controller = br_poll_controller,
|
||||
#endif
|
||||
.ndo_add_slave = br_add_slave,
|
||||
.ndo_del_slave = br_del_slave,
|
||||
.ndo_fix_features = br_fix_features,
|
||||
.ndo_fdb_add = br_fdb_add,
|
||||
.ndo_fdb_del = br_fdb_delete,
|
||||
.ndo_fdb_dump = br_fdb_dump,
|
||||
.ndo_fdb_get = br_fdb_get,
|
||||
.ndo_bridge_getlink = br_getlink,
|
||||
.ndo_bridge_setlink = br_setlink,
|
||||
.ndo_bridge_dellink = br_dellink,
|
||||
.ndo_features_check = passthru_features_check,
|
||||
};
|
||||
|
||||
static struct device_type br_type = {
|
||||
.name = "bridge",
|
||||
};
|
||||
|
||||
void br_dev_setup(struct net_device *dev)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
|
||||
eth_hw_addr_random(dev);
|
||||
ether_setup(dev);
|
||||
|
||||
dev->netdev_ops = &br_netdev_ops;
|
||||
dev->needs_free_netdev = true;
|
||||
dev->ethtool_ops = &br_ethtool_ops;
|
||||
SET_NETDEV_DEVTYPE(dev, &br_type);
|
||||
dev->priv_flags = IFF_EBRIDGE | IFF_NO_QUEUE;
|
||||
|
||||
dev->features = COMMON_FEATURES | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL |
|
||||
NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
|
||||
dev->hw_features = COMMON_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
|
||||
NETIF_F_HW_VLAN_STAG_TX;
|
||||
dev->vlan_features = COMMON_FEATURES;
|
||||
|
||||
br->dev = dev;
|
||||
spin_lock_init(&br->lock);
|
||||
INIT_LIST_HEAD(&br->port_list);
|
||||
INIT_HLIST_HEAD(&br->fdb_list);
|
||||
spin_lock_init(&br->hash_lock);
|
||||
|
||||
// br->bridge_id.prio[0] = 0x80;
|
||||
// br->bridge_id.prio[1] = 0x00;
|
||||
|
||||
ether_addr_copy(br->group_addr, eth_stp_addr);
|
||||
|
||||
// br->stp_enabled = BR_NO_STP;
|
||||
br->group_fwd_mask = BR_GROUPFWD_DEFAULT;
|
||||
br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT;
|
||||
|
||||
// br->designated_root = br->bridge_id;
|
||||
// br->bridge_max_age = br->max_age = 20 * HZ;
|
||||
// br->bridge_hello_time = br->hello_time = 2 * HZ;
|
||||
// br->bridge_forward_delay = br->forward_delay = 15 * HZ;
|
||||
// br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
|
||||
br->ageing_time = BR_DEFAULT_AGEING_TIME;
|
||||
dev->max_mtu = ETH_MAX_MTU;
|
||||
dev->l2mtu = 65535;
|
||||
|
||||
br_netfilter_rtable_init(br);
|
||||
// br_stp_timer_init(br);
|
||||
br_multicast_init(br);
|
||||
INIT_DELAYED_WORK(&br->gc_work, br_fdb_cleanup);
|
||||
}
|
||||
360
2025-03-19/bridge2/br_dhcp_snooping.c
Normal file
360
2025-03-19/bridge2/br_dhcp_snooping.c
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
#include <net/ip.h>
|
||||
#include <net/udp.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/log.h>
|
||||
|
||||
#include "br_private.h"
|
||||
|
||||
struct dhcphdr {
|
||||
unsigned char op;
|
||||
unsigned char htype;
|
||||
unsigned char hlen;
|
||||
unsigned char hops;
|
||||
unsigned xid;
|
||||
unsigned short secs;
|
||||
unsigned short flags;
|
||||
unsigned ciaddr;
|
||||
unsigned yiaddr;
|
||||
unsigned siaddr;
|
||||
unsigned giaddr;
|
||||
unsigned char chaddr[16];
|
||||
unsigned char sname[64];
|
||||
unsigned char file[128];
|
||||
unsigned char options[0];
|
||||
};
|
||||
|
||||
struct opt {
|
||||
unsigned char type;
|
||||
unsigned char len;
|
||||
unsigned char value[0];
|
||||
};
|
||||
|
||||
enum {
|
||||
BOOTREQUEST = 1,
|
||||
BOOTREPLY = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
DHCP_HOST_NAME = 12,
|
||||
DHCP_REQ_ADDR = 50,
|
||||
DHCP_LEASE_TIME = 51,
|
||||
DHCP_MSG_TYPE = 53,
|
||||
DHCP_SERVER_ID = 54,
|
||||
DHCP_CLIENT_IDENTIFIER = 61,
|
||||
DHCP_RELAY_AGENT = 82,
|
||||
};
|
||||
|
||||
enum {
|
||||
DHCP_DISCOVER = 1,
|
||||
DHCP_OFFER = 2,
|
||||
DHCP_REQUEST = 3,
|
||||
DHCP_ACK = 5,
|
||||
DHCP_RELEASE = 7,
|
||||
};
|
||||
|
||||
void destroy_info_opt(struct rcu_head *head)
|
||||
{
|
||||
struct net_dhcp_info_opt *info_opt =
|
||||
container_of(head, struct net_dhcp_info_opt, rcu);
|
||||
kfree(info_opt->circuit_id);
|
||||
kfree(info_opt->remote_id);
|
||||
kfree(info_opt);
|
||||
}
|
||||
|
||||
static struct opt *find_opt(unsigned char *opts, unsigned char *end,
|
||||
unsigned type) {
|
||||
struct opt *c = (struct opt *) opts;
|
||||
while (true) {
|
||||
if ((unsigned char *) c + sizeof(struct opt) > end) {
|
||||
if ((unsigned char *) c + 1 > end) break;
|
||||
if (type == 255 && c->type == 255) return c;
|
||||
break;
|
||||
}
|
||||
if (c->type == 255) {
|
||||
if (type == 255) return c;
|
||||
else break;
|
||||
}
|
||||
if (c->value + c->len > end) break;
|
||||
if (c->type == type) return c;
|
||||
c = (struct opt *) (c->value + c->len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned put_relay_agent_info(unsigned char *buf,
|
||||
struct net_dhcp_info_opt *info,
|
||||
unsigned circuit_id_len,
|
||||
unsigned remote_id_len,
|
||||
char *vid_str,
|
||||
unsigned vid_len) {
|
||||
struct opt *opt = (struct opt *) buf;
|
||||
opt->type = 1;
|
||||
opt->len = circuit_id_len + vid_len;
|
||||
memcpy(opt->value, info->circuit_id, circuit_id_len);
|
||||
if (vid_len) {
|
||||
memcpy(opt->value + circuit_id_len, vid_str, vid_len);
|
||||
}
|
||||
opt = (struct opt *) (opt->value + opt->len);
|
||||
opt->type = 2;
|
||||
opt->len = remote_id_len;
|
||||
memcpy(opt->value, info->remote_id, remote_id_len);
|
||||
return opt->value + opt->len - buf;
|
||||
}
|
||||
|
||||
static int br_add_info_opt(struct sk_buff *skb, struct net_dhcp_info_opt *info,
|
||||
struct dhcphdr *dhcph, struct opt *r, u16 vid)
|
||||
{
|
||||
unsigned circuit_id_len = strlen(info->circuit_id);
|
||||
unsigned remote_id_len = strlen(info->remote_id);
|
||||
int opt_len = sizeof(struct opt) * 3 +
|
||||
circuit_id_len + remote_id_len + 1;
|
||||
unsigned vid_len = 0;
|
||||
char vid_str[6] = {0, 0, 0, 0, 0, 0};
|
||||
if (vid) {
|
||||
vid_len = snprintf(vid_str, 6, ":%d", vid);
|
||||
opt_len += vid_len;
|
||||
}
|
||||
|
||||
int free = skb_tail_pointer(skb) - (unsigned char *) r;
|
||||
if (free < opt_len) {
|
||||
opt_len -= free;
|
||||
if (!pskb_may_pull(skb, opt_len)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
__skb_put(skb, opt_len);
|
||||
}
|
||||
else {
|
||||
opt_len = 0;
|
||||
}
|
||||
|
||||
r->type = DHCP_RELAY_AGENT;
|
||||
r->len = put_relay_agent_info(r->value, info, circuit_id_len,
|
||||
remote_id_len, vid_str, vid_len);
|
||||
unsigned char *e = r->value + r->len;
|
||||
*e = 255;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void br_checksum_udp(struct sk_buff *skb, unsigned len)
|
||||
{
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
struct udphdr *udph = udp_hdr(skb);
|
||||
|
||||
udph->len = htons(len);
|
||||
udph->check = 0;
|
||||
|
||||
__wsum csum = csum_partial(udph, len, 0);
|
||||
udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, len,
|
||||
iph->protocol, csum);
|
||||
if (udph->check == 0)
|
||||
udph->check = CSUM_MANGLED_0;
|
||||
|
||||
len += ip_hdrlen(skb);
|
||||
iph->tot_len = htons(len);
|
||||
iph->check = 0;
|
||||
iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
|
||||
}
|
||||
|
||||
|
||||
static int br_check_udp(struct net_bridge *br, struct net_bridge_port *port,
|
||||
struct sk_buff *skb, u16 vid)
|
||||
{
|
||||
struct udphdr *udph;
|
||||
struct dhcphdr *dhcph;
|
||||
unsigned int len;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!pskb_may_pull(skb, sizeof(struct udphdr)))
|
||||
return -EINVAL;
|
||||
|
||||
udph = udp_hdr(skb);
|
||||
|
||||
if (udph->source != htons(67) && udph->dest != htons(67))
|
||||
return 0;
|
||||
|
||||
len = ntohs(udph->len);
|
||||
if (skb->len < len || len < sizeof(struct dhcphdr))
|
||||
return -EINVAL;
|
||||
|
||||
if (!pskb_may_pull(skb, sizeof(*dhcph)))
|
||||
return -EINVAL;
|
||||
|
||||
dhcph = (struct dhcphdr *) (skb_transport_header(skb) + sizeof(*udph));
|
||||
if (dhcph->op == BOOTREPLY && !(port->flags & BR_TRUSTED_PORT)) {
|
||||
if (__ratelimit(&br_warn_ratelimit_state)) {
|
||||
log_message(bridge_warning_topics,
|
||||
"*%08x: received DHCP server message "
|
||||
"on untrusted port from source IP %pI4, "
|
||||
"MAC %pM",
|
||||
port->dev->ifindex,
|
||||
&ip_hdr(skb)->saddr,
|
||||
eth_hdr(skb)->h_source);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
unsigned char *end = skb_tail_pointer(skb);
|
||||
unsigned char *opts = dhcph->options;
|
||||
if (opts + 4 > end || get_unaligned((u32 *) opts) != htonl(0x63825363))
|
||||
return 0;
|
||||
opts += 4;
|
||||
|
||||
struct opt *type = find_opt(opts, end, DHCP_MSG_TYPE);
|
||||
if (!type) {
|
||||
if (dhcph->op == BOOTREQUEST) {
|
||||
BR_INPUT_SKB_CB(skb)->dhcp_req = 1;
|
||||
}
|
||||
else if (dhcph->op == BOOTREPLY) {
|
||||
BR_INPUT_SKB_CB(skb)->dhcp_rep = 1;
|
||||
}
|
||||
else {
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (!type || type->len != 1)
|
||||
return -EINVAL;
|
||||
|
||||
struct opt *eopt = find_opt(opts, end, 255);
|
||||
if (!eopt)
|
||||
return -EINVAL;
|
||||
|
||||
if (type->value[0] == DHCP_DISCOVER || type->value[0] == DHCP_REQUEST ||
|
||||
type->value[0] == DHCP_RELEASE) {
|
||||
struct opt *agent = find_opt(opts, end, DHCP_RELAY_AGENT);
|
||||
if (!(port->flags & BR_TRUSTED_PORT) && agent)
|
||||
return -EINVAL;
|
||||
|
||||
BR_INPUT_SKB_CB(skb)->dhcp_req = 1;
|
||||
|
||||
if (br->add_info_option && !agent) {
|
||||
struct net_dhcp_info_opt *info;
|
||||
info = rcu_dereference(port->info_option);
|
||||
if (info) {
|
||||
ret = br_add_info_opt(skb, info, dhcph, eopt, vid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
br_checksum_udp(skb, skb->len);
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
} else if (type->value[0] == DHCP_OFFER || type->value[0] == DHCP_ACK) {
|
||||
BR_INPUT_SKB_CB(skb)->dhcp_rep = 1;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sk_buff *br_dhcp_remove_agent_info(struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
|
||||
if (!skb2) {
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
skb = skb2;
|
||||
|
||||
struct dhcphdr *dhcph = (struct dhcphdr *)
|
||||
(skb_transport_header(skb) + sizeof(struct udphdr));
|
||||
unsigned char *end = skb_tail_pointer(skb);
|
||||
unsigned char *opts = dhcph->options;
|
||||
opts += 4;
|
||||
|
||||
struct opt *agent = find_opt(opts, end, DHCP_RELAY_AGENT);
|
||||
if (!agent)
|
||||
return skb;
|
||||
|
||||
unsigned char *ptr = (unsigned char *) agent;
|
||||
unsigned agent_len = sizeof(struct opt) + agent->len;
|
||||
unsigned pkt_len = end - (unsigned char *) dhcph;
|
||||
memmove(ptr, ptr + agent_len, end - ptr - agent_len);
|
||||
struct opt *eopt = find_opt(opts, end, 255);
|
||||
if (eopt) {
|
||||
ptr = (unsigned char *) eopt;
|
||||
++ptr;
|
||||
if (ptr >= end) {
|
||||
goto out;
|
||||
}
|
||||
if (pkt_len > 300 && pkt_len - agent_len < 300) {
|
||||
/* trim to minimum dhcp packet size */
|
||||
skb_trim(skb, skb->len - (pkt_len - 300));
|
||||
end = skb_tail_pointer(skb);
|
||||
}
|
||||
if (ptr < end) {
|
||||
memset(ptr, 0, end - ptr);
|
||||
}
|
||||
}
|
||||
out:
|
||||
br_checksum_udp(skb2, end - skb_transport_header(skb));
|
||||
return skb2;
|
||||
}
|
||||
|
||||
int br_dhcp_rcv(struct net_bridge *br, struct net_bridge_port *port,
|
||||
struct sk_buff *skb, u16 vid)
|
||||
{
|
||||
struct sk_buff *skb2 = skb;
|
||||
struct iphdr *iph;
|
||||
int len;
|
||||
unsigned offset;
|
||||
int ret;
|
||||
|
||||
BR_INPUT_SKB_CB(skb)->dhcp_req = 0;
|
||||
BR_INPUT_SKB_CB(skb)->dhcp_rep = 0;
|
||||
|
||||
if (!br->dhcp_snooping)
|
||||
return 0;
|
||||
|
||||
if (skb->protocol != htons(ETH_P_IP))
|
||||
return 0;
|
||||
|
||||
/* We treat OOM as packet loss for now. */
|
||||
if (!pskb_may_pull(skb, sizeof(*iph)))
|
||||
return -EINVAL;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
|
||||
if (iph->ihl < 5 || iph->version != 4)
|
||||
return -EINVAL;
|
||||
|
||||
if (!pskb_may_pull(skb, ip_hdrlen(skb)))
|
||||
return -EINVAL;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
|
||||
if (unlikely(ip_fast_csum(iph, iph->ihl)))
|
||||
return -EINVAL;
|
||||
|
||||
if (iph->protocol != IPPROTO_UDP)
|
||||
return 0;
|
||||
|
||||
len = ntohs(iph->tot_len);
|
||||
if (skb->len < len || len < ip_hdrlen(skb))
|
||||
return -EINVAL;
|
||||
|
||||
if (skb->len > len) {
|
||||
skb2 = skb_clone(skb, GFP_ATOMIC);
|
||||
if (!skb2)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = pskb_trim_rcsum(skb2, len);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
len -= ip_hdrlen(skb2);
|
||||
offset = skb_network_offset(skb2) + ip_hdrlen(skb2);
|
||||
__skb_pull(skb2, offset);
|
||||
skb_reset_transport_header(skb2);
|
||||
|
||||
ret = br_check_udp(br, port, skb2, vid);
|
||||
|
||||
__skb_push(skb2, offset);
|
||||
err_out:
|
||||
if (skb2 != skb)
|
||||
kfree_skb(skb2);
|
||||
return ret;
|
||||
}
|
||||
1237
2025-03-19/bridge2/br_fdb.c
Normal file
1237
2025-03-19/bridge2/br_fdb.c
Normal file
File diff suppressed because it is too large
Load diff
438
2025-03-19/bridge2/br_forward.c
Normal file
438
2025-03-19/bridge2/br_forward.c
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Forwarding decision
|
||||
* Linux ethernet bridge
|
||||
*
|
||||
* Authors:
|
||||
* Lennert Buytenhek <buytenh@gnu.org>
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netpoll.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include <linux/switch.h>
|
||||
#include "br_private.h"
|
||||
#include "../mesh/mesh.h"
|
||||
|
||||
DECLARE_PER_CPU(unsigned, per_cpu_xmit_switched);
|
||||
|
||||
static inline bool is_hw_pkt(const struct sk_buff *skb,
|
||||
const struct net_bridge_port *p)
|
||||
{
|
||||
return !br_multicast_igmp_type(skb) &&
|
||||
!BR_INPUT_SKB_CB(skb)->dhcp_req &&
|
||||
!BR_INPUT_SKB_CB(skb)->dhcp_rep &&
|
||||
!(BR_INPUT_SKB_CB(skb)->ll_mc && hlist_unhashed(&p->rlist));
|
||||
}
|
||||
|
||||
static inline int check_hw(const struct sk_buff *skb,
|
||||
const struct net_bridge_port *p,
|
||||
unsigned from_switch_group,
|
||||
unsigned *switches)
|
||||
{
|
||||
if (p->switch_group == BR_NOSWITCH)
|
||||
return true;
|
||||
if (!is_hw_pkt(skb, p))
|
||||
return true;
|
||||
if (!switches && p->switch_group != from_switch_group)
|
||||
return true;
|
||||
if (switches && !(*switches & BIT(p->switch_group)) &&
|
||||
p->switch_group != from_switch_group) {
|
||||
*switches |= BIT(p->switch_group);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Don't forward packets to originating port or forwarding disabled */
|
||||
static inline int should_deliver(const struct net_bridge_port *p,
|
||||
const struct sk_buff *skb, unsigned horizon)
|
||||
{
|
||||
struct net_bridge_vlan_group *vg;
|
||||
|
||||
vg = nbp_vlan_group_rcu(p);
|
||||
return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
|
||||
p->state == BR_STATE_FORWARDING && br_allowed_egress(vg, skb) &&
|
||||
nbp_switchdev_allowed_egress(p, skb) &&
|
||||
!br_skb_isolated(p, skb) && (horizon == BR_NOHORIZON || horizon != p->horizon)
|
||||
&& (BR_INPUT_SKB_CB(skb)->src_port_peer_link
|
||||
? !(p->flags & BR_MLAG_DUAL_LINK) : true);
|
||||
}
|
||||
|
||||
static inline unsigned packet_length(const struct sk_buff *skb)
|
||||
{
|
||||
if (skb->protocol == htons(MESH_ENCAP_PROTO)) return 0;
|
||||
|
||||
return skb->len - (ANY_VLAN_PROTO_N(skb->protocol) ? VLAN_HLEN : 0);
|
||||
}
|
||||
|
||||
static inline void set_priority(struct sk_buff *skb)
|
||||
{
|
||||
if (ANY_VLAN_PROTO_N(skb->protocol)) {
|
||||
struct vlan_ethhdr *v = (struct vlan_ethhdr *)(skb->data - ETH_HLEN);
|
||||
unsigned tci = ntohs(v->h_vlan_TCI);
|
||||
|
||||
tci = (tci & ~(7 << 13)) | ((skb->priority & 0x7) << 13);
|
||||
v->h_vlan_TCI = htons(tci);
|
||||
}
|
||||
}
|
||||
|
||||
int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct net_bridge_port *port = br_port_get_rcu(skb->dev);
|
||||
|
||||
#if 0 // is_skb_forwardable is handled below - IFF_UP check and our l2mtu, mtu checks
|
||||
if (!is_skb_forwardable(skb->dev, skb))
|
||||
goto drop;
|
||||
#endif
|
||||
if (!(skb->dev->flags & IFF_UP))
|
||||
goto drop;
|
||||
|
||||
/* drop mtu oversized packets except gso */
|
||||
if (skb->dev->l2mtu) {
|
||||
unsigned len = skb->len + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
|
||||
if (skb->dev->l2mtu < len && !skb_is_gso(skb))
|
||||
goto drop;
|
||||
}
|
||||
else if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb)) {
|
||||
goto drop;
|
||||
}
|
||||
|
||||
set_priority(skb);
|
||||
skb_push(skb, ETH_HLEN);
|
||||
br_drop_fake_rtable(skb);
|
||||
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL &&
|
||||
(skb->protocol == htons(ETH_P_8021Q) ||
|
||||
skb->protocol == htons(ETH_P_8021AD))) {
|
||||
int depth;
|
||||
|
||||
if (!__vlan_get_protocol(skb, skb->protocol, &depth))
|
||||
goto drop;
|
||||
|
||||
skb_set_network_header(skb, depth);
|
||||
}
|
||||
|
||||
if (port && port->switch_group != BR_NOSWITCH && is_hw_pkt(skb, port)) {
|
||||
skb = br_handle_vlan_switch(port->br, skb);
|
||||
if (!skb)
|
||||
return 0;
|
||||
|
||||
// This should get reset in the switch port xmit
|
||||
*raw_cpu_ptr(&per_cpu_xmit_switched) = 1;
|
||||
}
|
||||
|
||||
if (dev_queue_xmit(skb)) {
|
||||
*raw_cpu_ptr(&per_cpu_xmit_switched) = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit);
|
||||
|
||||
int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
skb->tstamp = 0;
|
||||
return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING,
|
||||
net, sk, skb, NULL, skb->dev,
|
||||
br_dev_queue_push_xmit);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(br_forward_finish);
|
||||
|
||||
static void __br_forward(const struct net_bridge_port *to,
|
||||
struct sk_buff *skb, bool local_orig)
|
||||
{
|
||||
struct net_bridge_vlan_group *vg;
|
||||
struct net_device *indev;
|
||||
struct net *net;
|
||||
int br_hook;
|
||||
|
||||
if (BR_INPUT_SKB_CB(skb)->dhcp_req && !(to->flags & BR_TRUSTED_PORT)) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_hw_pkt(skb, to) || to->switch_group == BR_NOSWITCH) {
|
||||
vg = nbp_vlan_group_rcu(to);
|
||||
skb = br_handle_vlan(to->br, to, vg, skb);
|
||||
if (!skb)
|
||||
return;
|
||||
}
|
||||
|
||||
if (to->br->add_info_option && !(to->flags & BR_TRUSTED_PORT) &&
|
||||
BR_INPUT_SKB_CB(skb)->dhcp_rep) {
|
||||
skb = br_dhcp_remove_agent_info(skb);
|
||||
if (!skb)
|
||||
return;
|
||||
}
|
||||
|
||||
indev = skb->dev;
|
||||
skb->dev = to->dev;
|
||||
if (!local_orig) {
|
||||
if (skb_warn_if_lro(skb)) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
br_hook = NF_BR_FORWARD;
|
||||
skb_forward_csum(skb);
|
||||
net = dev_net(indev);
|
||||
} else {
|
||||
#if 0
|
||||
if (unlikely(netpoll_tx_running(to->br->dev))) {
|
||||
if (!is_skb_forwardable(skb->dev, skb)) {
|
||||
kfree_skb(skb);
|
||||
} else {
|
||||
skb_push(skb, ETH_HLEN);
|
||||
br_netpoll_send_skb(to, skb);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
br_hook = NF_BR_LOCAL_OUT;
|
||||
net = dev_net(skb->dev);
|
||||
indev = NULL;
|
||||
}
|
||||
|
||||
NF_HOOK(NFPROTO_BRIDGE, br_hook,
|
||||
net, NULL, skb, indev, skb->dev,
|
||||
br_forward_finish);
|
||||
}
|
||||
|
||||
static int deliver_clone(const struct net_bridge_port *prev,
|
||||
struct sk_buff *skb, bool local_orig)
|
||||
{
|
||||
struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
|
||||
|
||||
skb = skb_clone(skb, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
dev->stats.tx_dropped++;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
__br_forward(prev, skb, local_orig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* br_forward - forward a packet to a specific port
|
||||
* @to: destination port
|
||||
* @skb: packet being forwarded
|
||||
* @local_rcv: packet will be received locally after forwarding
|
||||
* @local_orig: packet is locally originated
|
||||
*
|
||||
* Should be called with rcu_read_lock.
|
||||
*/
|
||||
void br_forward(const struct net_bridge_port *to,
|
||||
struct sk_buff *skb, bool local_rcv, bool local_orig,
|
||||
unsigned horizon, unsigned switch_group)
|
||||
{
|
||||
if (unlikely(!to))
|
||||
goto out;
|
||||
|
||||
/* redirect to backup link if the destination port is down */
|
||||
if (rcu_access_pointer(to->backup_port) && !netif_carrier_ok(to->dev)) {
|
||||
struct net_bridge_port *backup_port;
|
||||
|
||||
backup_port = rcu_dereference(to->backup_port);
|
||||
if (unlikely(!backup_port))
|
||||
goto out;
|
||||
to = backup_port;
|
||||
}
|
||||
|
||||
if (should_deliver(to, skb, horizon) &&
|
||||
check_hw(skb, to, switch_group, NULL)) {
|
||||
if (local_rcv)
|
||||
deliver_clone(to, skb, local_orig);
|
||||
else
|
||||
__br_forward(to, skb, local_orig);
|
||||
return;
|
||||
}
|
||||
|
||||
out:
|
||||
if (!local_rcv)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(br_forward);
|
||||
|
||||
static struct net_bridge_port *maybe_deliver(
|
||||
struct net_bridge_port *prev, struct net_bridge_port *p,
|
||||
struct sk_buff *skb, bool local_orig,
|
||||
unsigned horizon, unsigned from_switch_group, unsigned *switches)
|
||||
{
|
||||
u8 igmp_type = br_multicast_igmp_type(skb);
|
||||
int err;
|
||||
|
||||
if (!should_deliver(p, skb, horizon))
|
||||
return prev;
|
||||
|
||||
if (BR_INPUT_SKB_CB(skb)->dhcp_req && !(p->flags & BR_TRUSTED_PORT))
|
||||
return prev;
|
||||
|
||||
if (!check_hw(skb, p, from_switch_group, switches))
|
||||
return prev;
|
||||
|
||||
if (!prev)
|
||||
goto out;
|
||||
|
||||
err = deliver_clone(prev, skb, local_orig);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
out:
|
||||
br_multicast_count(p->br, p, skb, igmp_type, BR_MCAST_DIR_TX);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* called under rcu_read_lock */
|
||||
void br_flood(struct net_bridge *br, struct sk_buff *skb,
|
||||
enum br_pkt_type pkt_type, bool local_rcv, bool local_orig,
|
||||
unsigned horizon, unsigned switch_group)
|
||||
{
|
||||
struct net_bridge_port *prev = NULL;
|
||||
struct net_bridge_port *p;
|
||||
unsigned switches = 0;
|
||||
|
||||
list_for_each_entry_rcu(p, &br->port_list, list) {
|
||||
/* Do not flood unicast traffic to ports that turn it off, nor
|
||||
* other traffic if flood off, except for traffic we originate
|
||||
*/
|
||||
switch (pkt_type) {
|
||||
case BR_PKT_UNICAST:
|
||||
if (!(p->flags & BR_FLOOD))
|
||||
continue;
|
||||
break;
|
||||
case BR_PKT_MULTICAST:
|
||||
if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev)
|
||||
continue;
|
||||
break;
|
||||
case BR_PKT_BROADCAST:
|
||||
if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
// /* Do not flood to ports that enable proxy ARP */
|
||||
// if (p->flags & BR_PROXYARP)
|
||||
// continue;
|
||||
// if ((p->flags & (BR_PROXYARP_WIFI | BR_NEIGH_SUPPRESS)) &&
|
||||
// BR_INPUT_SKB_CB(skb)->proxyarp_replied)
|
||||
// continue;
|
||||
|
||||
prev = maybe_deliver(prev, p, skb, local_orig, horizon, switch_group, &switches);
|
||||
if (IS_ERR(prev))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!prev)
|
||||
goto out;
|
||||
|
||||
if (local_rcv)
|
||||
deliver_clone(prev, skb, local_orig);
|
||||
else
|
||||
__br_forward(prev, skb, local_orig);
|
||||
return;
|
||||
|
||||
out:
|
||||
if (!local_rcv)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
|
||||
const unsigned char *addr, bool local_orig,
|
||||
unsigned horizon, unsigned from_switch_group,
|
||||
unsigned *switches)
|
||||
{
|
||||
struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
|
||||
const unsigned char *src = eth_hdr(skb)->h_source;
|
||||
|
||||
if (!should_deliver(p, skb, horizon))
|
||||
return;
|
||||
|
||||
if (!check_hw(skb, p, from_switch_group, switches))
|
||||
return;
|
||||
|
||||
/* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
|
||||
if (skb->dev == p->dev && ether_addr_equal(src, addr))
|
||||
return;
|
||||
|
||||
skb = skb_copy(skb, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
dev->stats.tx_dropped++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_broadcast_ether_addr(addr))
|
||||
memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
|
||||
|
||||
__br_forward(p, skb, local_orig);
|
||||
}
|
||||
|
||||
/* called with rcu_read_lock */
|
||||
void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
|
||||
struct sk_buff *skb,
|
||||
bool local_rcv, bool local_orig,
|
||||
unsigned horizon, unsigned switch_group)
|
||||
{
|
||||
struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
struct net_bridge_port *prev = NULL;
|
||||
struct net_bridge_port_group *p;
|
||||
struct hlist_node *rp;
|
||||
unsigned switches = 0;
|
||||
|
||||
rp = rcu_dereference(hlist_first_rcu(&br->router_list));
|
||||
p = mdst ? rcu_dereference(mdst->ports) : NULL;
|
||||
while (p || rp) {
|
||||
struct net_bridge_port *port, *lport, *rport;
|
||||
|
||||
lport = p ? p->port : NULL;
|
||||
rport = hlist_entry_safe(rp, struct net_bridge_port, rlist);
|
||||
|
||||
if ((unsigned long)lport > (unsigned long)rport) {
|
||||
port = lport;
|
||||
|
||||
if (port->flags & BR_MULTICAST_TO_UNICAST) {
|
||||
maybe_deliver_addr(lport, skb, p->eth_addr,
|
||||
local_orig,
|
||||
horizon, switch_group, &switches);
|
||||
goto delivered;
|
||||
}
|
||||
} else {
|
||||
port = rport;
|
||||
}
|
||||
|
||||
prev = maybe_deliver(prev, port, skb, local_orig,
|
||||
horizon, switch_group, &switches);
|
||||
if (IS_ERR(prev))
|
||||
goto out;
|
||||
delivered:
|
||||
if ((unsigned long)lport >= (unsigned long)port)
|
||||
p = rcu_dereference(p->next);
|
||||
if ((unsigned long)rport >= (unsigned long)port)
|
||||
rp = rcu_dereference(hlist_next_rcu(rp));
|
||||
}
|
||||
|
||||
if (!prev)
|
||||
goto out;
|
||||
|
||||
if (local_rcv)
|
||||
deliver_clone(prev, skb, local_orig);
|
||||
else
|
||||
__br_forward(prev, skb, local_orig);
|
||||
return;
|
||||
|
||||
out:
|
||||
if (!local_rcv)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
#endif
|
||||
850
2025-03-19/bridge2/br_if.c
Normal file
850
2025-03-19/bridge2/br_if.c
Normal file
|
|
@ -0,0 +1,850 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Userspace interface
|
||||
* Linux ethernet bridge
|
||||
*
|
||||
* Authors:
|
||||
* Lennert Buytenhek <buytenh@gnu.org>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/netpoll.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/dsa.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <net/switchdev.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <linux/packet_hook.h>
|
||||
|
||||
#include "br_private.h"
|
||||
|
||||
extern struct fast_path bridge_fast_path;
|
||||
extern struct fast_path bridge_fast_forward;
|
||||
|
||||
///*
|
||||
// * Determine initial path cost based on speed.
|
||||
// * using recommendations from 802.1d standard
|
||||
// *
|
||||
// * Since driver might sleep need to not be holding any locks.
|
||||
// */
|
||||
//static int port_cost(struct net_device *dev)
|
||||
//{
|
||||
// struct ethtool_link_ksettings ecmd;
|
||||
|
||||
// if (!__ethtool_get_link_ksettings(dev, &ecmd)) {
|
||||
// switch (ecmd.base.speed) {
|
||||
// case SPEED_10000:
|
||||
// return 2;
|
||||
// case SPEED_1000:
|
||||
// return 4;
|
||||
// case SPEED_100:
|
||||
// return 19;
|
||||
// case SPEED_10:
|
||||
// return 100;
|
||||
// }
|
||||
// }
|
||||
|
||||
// /* Old silly heuristics based on name */
|
||||
// if (!strncmp(dev->name, "lec", 3))
|
||||
// return 7;
|
||||
|
||||
// if (!strncmp(dev->name, "plip", 4))
|
||||
// return 2500;
|
||||
|
||||
// return 100; /* assume old 10Mbps */
|
||||
//}
|
||||
|
||||
|
||||
///* Check for port carrier transitions. */
|
||||
//void br_port_carrier_check(struct net_bridge_port *p, bool *notified)
|
||||
//{
|
||||
// struct net_device *dev = p->dev;
|
||||
// struct net_bridge *br = p->br;
|
||||
|
||||
// if (!(p->flags & BR_ADMIN_COST) &&
|
||||
// netif_running(dev) && netif_oper_up(dev))
|
||||
// p->path_cost = port_cost(dev);
|
||||
|
||||
// *notified = false;
|
||||
// if (!netif_running(br->dev))
|
||||
// return;
|
||||
|
||||
// spin_lock_bh(&br->lock);
|
||||
// if (netif_running(dev) && netif_oper_up(dev)) {
|
||||
// if (p->state == BR_STATE_DISABLED) {
|
||||
// br_stp_enable_port(p);
|
||||
// *notified = true;
|
||||
// }
|
||||
// } else {
|
||||
// if (p->state != BR_STATE_DISABLED) {
|
||||
// br_stp_disable_port(p);
|
||||
// *notified = true;
|
||||
// }
|
||||
// }
|
||||
// spin_unlock_bh(&br->lock);
|
||||
//}
|
||||
|
||||
static void br_port_set_promisc(struct net_bridge_port *p)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (br_promisc_port(p))
|
||||
return;
|
||||
|
||||
err = dev_set_promiscuity(p->dev, 1);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
br_fdb_unsync_static(p->br, p);
|
||||
p->flags |= BR_PROMISC;
|
||||
}
|
||||
|
||||
static void br_port_clear_promisc(struct net_bridge_port *p)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Check if the port is already non-promisc or if it doesn't
|
||||
* support UNICAST filtering. Without unicast filtering support
|
||||
* we'll end up re-enabling promisc mode anyway, so just check for
|
||||
* it here.
|
||||
*/
|
||||
if (!br_promisc_port(p) || !(p->dev->priv_flags & IFF_UNICAST_FLT))
|
||||
return;
|
||||
|
||||
/* Since we'll be clearing the promisc mode, program the port
|
||||
* first so that we don't have interruption in traffic.
|
||||
*/
|
||||
err = br_fdb_sync_static(p->br, p);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
dev_set_promiscuity(p->dev, -1);
|
||||
p->flags &= ~BR_PROMISC;
|
||||
}
|
||||
|
||||
/* When a port is added or removed or when certain port flags
|
||||
* change, this function is called to automatically manage
|
||||
* promiscuity setting of all the bridge ports. We are always called
|
||||
* under RTNL so can skip using rcu primitives.
|
||||
*/
|
||||
void br_manage_promisc(struct net_bridge *br)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
bool set_all = false;
|
||||
|
||||
/* If vlan filtering is disabled or bridge interface is placed
|
||||
* into promiscuous mode, place all ports in promiscuous mode.
|
||||
*/
|
||||
if ((br->dev->flags & IFF_PROMISC) || !br_vlan_enabled(br->dev))
|
||||
set_all = true;
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (set_all) {
|
||||
br_port_set_promisc(p);
|
||||
} else {
|
||||
/* If the number of auto-ports is <= 1, then all other
|
||||
* ports will have their output configuration
|
||||
* statically specified through fdbs. Since ingress
|
||||
* on the auto-port becomes forwarding/egress to other
|
||||
* ports and egress configuration is statically known,
|
||||
* we can say that ingress configuration of the
|
||||
* auto-port is also statically known.
|
||||
* This lets us disable promiscuous mode and write
|
||||
* this config to hw.
|
||||
*/
|
||||
if (br->auto_cnt == 0 ||
|
||||
(br->auto_cnt == 1 && br_auto_port(p)))
|
||||
br_port_clear_promisc(p);
|
||||
else
|
||||
br_port_set_promisc(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nbp_backup_change(struct net_bridge_port *p,
|
||||
struct net_device *backup_dev)
|
||||
{
|
||||
struct net_bridge_port *old_backup = rtnl_dereference(p->backup_port);
|
||||
struct net_bridge_port *backup_p = NULL;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (backup_dev) {
|
||||
if (!netif_is_bridge_port(backup_dev))
|
||||
return -ENOENT;
|
||||
|
||||
backup_p = br_port_get_rtnl(backup_dev);
|
||||
if (backup_p->br != p->br)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (p == backup_p)
|
||||
return -EINVAL;
|
||||
|
||||
if (old_backup == backup_p)
|
||||
return 0;
|
||||
|
||||
/* if the backup link is already set, clear it */
|
||||
if (old_backup)
|
||||
old_backup->backup_redirected_cnt--;
|
||||
|
||||
if (backup_p)
|
||||
backup_p->backup_redirected_cnt++;
|
||||
rcu_assign_pointer(p->backup_port, backup_p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nbp_backup_clear(struct net_bridge_port *p)
|
||||
{
|
||||
nbp_backup_change(p, NULL);
|
||||
if (p->backup_redirected_cnt) {
|
||||
struct net_bridge_port *cur_p;
|
||||
|
||||
list_for_each_entry(cur_p, &p->br->port_list, list) {
|
||||
struct net_bridge_port *backup_p;
|
||||
|
||||
backup_p = rtnl_dereference(cur_p->backup_port);
|
||||
if (backup_p == p)
|
||||
nbp_backup_change(cur_p, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
WARN_ON(rcu_access_pointer(p->backup_port) || p->backup_redirected_cnt);
|
||||
}
|
||||
|
||||
static void nbp_update_port_count(struct net_bridge *br)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
u32 cnt = 0;
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (br_auto_port(p))
|
||||
cnt++;
|
||||
}
|
||||
if (br->auto_cnt != cnt) {
|
||||
br->auto_cnt = cnt;
|
||||
br_manage_promisc(br);
|
||||
}
|
||||
}
|
||||
|
||||
static void nbp_delete_promisc(struct net_bridge_port *p)
|
||||
{
|
||||
/* If port is currently promiscuous, unset promiscuity.
|
||||
* Otherwise, it is a static port so remove all addresses
|
||||
* from it.
|
||||
*/
|
||||
dev_set_allmulti(p->dev, -1);
|
||||
if (br_promisc_port(p))
|
||||
dev_set_promiscuity(p->dev, -1);
|
||||
else
|
||||
br_fdb_unsync_static(p->br, p);
|
||||
}
|
||||
|
||||
//static void release_nbp(struct kobject *kobj)
|
||||
//{
|
||||
// struct net_bridge_port *p
|
||||
// = container_of(kobj, struct net_bridge_port, kobj);
|
||||
// kfree(p);
|
||||
//}
|
||||
|
||||
//static void brport_get_ownership(struct kobject *kobj, kuid_t *uid, kgid_t *gid)
|
||||
//{
|
||||
// struct net_bridge_port *p = kobj_to_brport(kobj);
|
||||
|
||||
// net_ns_get_ownership(dev_net(p->dev), uid, gid);
|
||||
//}
|
||||
|
||||
//static struct kobj_type brport_ktype = {
|
||||
//#ifdef CONFIG_SYSFS
|
||||
// .sysfs_ops = &brport_sysfs_ops,
|
||||
//#endif
|
||||
// .release = release_nbp,
|
||||
// .get_ownership = brport_get_ownership,
|
||||
//};
|
||||
|
||||
static void destroy_nbp(struct net_bridge_port *p)
|
||||
{
|
||||
struct net_device *dev = p->dev;
|
||||
|
||||
p->br = NULL;
|
||||
p->dev = NULL;
|
||||
dev_put(dev);
|
||||
|
||||
// kobject_put(&p->kobj);
|
||||
}
|
||||
|
||||
static void destroy_nbp_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct net_bridge_port *p =
|
||||
container_of(head, struct net_bridge_port, rcu);
|
||||
destroy_nbp(p);
|
||||
}
|
||||
|
||||
static unsigned get_max_headroom(struct net_bridge *br)
|
||||
{
|
||||
unsigned max_headroom = 0;
|
||||
struct net_bridge_port *p;
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
unsigned dev_headroom = netdev_get_fwd_headroom(p->dev);
|
||||
|
||||
if (dev_headroom > max_headroom)
|
||||
max_headroom = dev_headroom;
|
||||
}
|
||||
|
||||
return max_headroom;
|
||||
}
|
||||
|
||||
static void update_headroom(struct net_bridge *br, int new_hr)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list)
|
||||
netdev_set_rx_headroom(p->dev, new_hr);
|
||||
|
||||
br->dev->needed_headroom = new_hr;
|
||||
}
|
||||
|
||||
/* Delete port(interface) from bridge is done in two steps.
|
||||
* via RCU. First step, marks device as down. That deletes
|
||||
* all the timers and stops new packets from flowing through.
|
||||
*
|
||||
* Final cleanup doesn't occur until after all CPU's finished
|
||||
* processing packets.
|
||||
*
|
||||
* Protected from multiple admin operations by RTNL mutex
|
||||
*/
|
||||
static void del_nbp(struct net_bridge_port *p)
|
||||
{
|
||||
struct net_bridge *br = p->br;
|
||||
struct net_device *dev = p->dev;
|
||||
struct net_dhcp_info_opt *opt;
|
||||
|
||||
// sysfs_remove_link(br->ifobj, p->dev->name);
|
||||
|
||||
--br->port_count;
|
||||
if (br->fast_forward) {
|
||||
unregister_fast_path(&bridge_fast_forward, dev);
|
||||
}
|
||||
unregister_fast_path(&bridge_fast_path, dev);
|
||||
|
||||
nbp_delete_promisc(p);
|
||||
|
||||
spin_lock_bh(&br->lock);
|
||||
// br_stp_disable_port(p);
|
||||
{
|
||||
p->state = BR_STATE_DISABLED;
|
||||
p->vlan_def_state = BR_STATE_DISABLED;
|
||||
br_multicast_disable_port(p);
|
||||
}
|
||||
spin_unlock_bh(&br->lock);
|
||||
|
||||
br_ifinfo_notify(RTM_DELLINK, NULL, p);
|
||||
|
||||
list_del_rcu(&p->list);
|
||||
if (netdev_get_fwd_headroom(dev) == br->dev->needed_headroom)
|
||||
update_headroom(br, get_max_headroom(br));
|
||||
netdev_reset_rx_headroom(dev);
|
||||
|
||||
nbp_vlan_flush(p);
|
||||
br_fdb_delete_by_port(br, p, 0, 1);
|
||||
switchdev_deferred_process();
|
||||
nbp_backup_clear(p);
|
||||
|
||||
nbp_update_port_count(br);
|
||||
|
||||
netdev_upper_dev_unlink(dev, br->dev);
|
||||
|
||||
dev->priv_flags &= ~IFF_BRIDGE_PORT;
|
||||
|
||||
rcu_assign_pointer(dev->master_dev, NULL);
|
||||
netdev_rx_handler_unregister(dev);
|
||||
|
||||
br_multicast_del_port(p);
|
||||
|
||||
// kobject_uevent(&p->kobj, KOBJ_REMOVE);
|
||||
// kobject_del(&p->kobj);
|
||||
|
||||
// br_netpoll_disable(p);
|
||||
|
||||
opt = rcu_dereference(p->info_option);
|
||||
if (opt) {
|
||||
call_rcu(&opt->rcu, destroy_info_opt);
|
||||
rcu_assign_pointer(p->info_option, NULL);
|
||||
}
|
||||
|
||||
call_rcu(&p->rcu, destroy_nbp_rcu);
|
||||
|
||||
br_update_fast_forward(br);
|
||||
}
|
||||
|
||||
/* Delete bridge device */
|
||||
void br_dev_delete(struct net_device *dev, struct list_head *head)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
struct net_bridge_port *p, *n;
|
||||
|
||||
list_for_each_entry_safe(p, n, &br->port_list, list) {
|
||||
del_nbp(p);
|
||||
}
|
||||
|
||||
// br_recalculate_neigh_suppress_enabled(br);
|
||||
|
||||
br_fdb_delete_by_port(br, NULL, 0, 1);
|
||||
|
||||
cancel_delayed_work_sync(&br->gc_work);
|
||||
|
||||
// br_sysfs_delbr(br->dev);
|
||||
unregister_netdevice_queue(br->dev, head);
|
||||
}
|
||||
|
||||
/* find an available port number */
|
||||
static int find_portno(struct net_bridge *br)
|
||||
{
|
||||
int index;
|
||||
struct net_bridge_port *p;
|
||||
unsigned long *inuse;
|
||||
|
||||
inuse = bitmap_zalloc(BR_MAX_PORTS, GFP_KERNEL);
|
||||
if (!inuse)
|
||||
return -ENOMEM;
|
||||
|
||||
set_bit(0, inuse); /* zero is reserved */
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
set_bit(p->port_no, inuse);
|
||||
}
|
||||
index = find_first_zero_bit(inuse, BR_MAX_PORTS);
|
||||
bitmap_free(inuse);
|
||||
|
||||
return (index >= BR_MAX_PORTS) ? -EXFULL : index;
|
||||
}
|
||||
|
||||
/* called with RTNL but without bridge lock */
|
||||
static struct net_bridge_port *new_nbp(struct net_bridge *br,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
int index, err;
|
||||
|
||||
index = find_portno(br);
|
||||
if (index < 0)
|
||||
return ERR_PTR(index);
|
||||
|
||||
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (p == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
p->br = br;
|
||||
dev_hold(dev);
|
||||
p->dev = dev;
|
||||
// p->path_cost = port_cost(dev);
|
||||
// p->priority = 0x8000 >> BR_PORT_BITS;
|
||||
p->port_no = index;
|
||||
p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
|
||||
// br_init_port(p);
|
||||
// br_set_state(p, BR_STATE_DISABLED);
|
||||
// br_stp_port_timer_init(p);
|
||||
p->state = BR_STATE_DISABLED;
|
||||
p->vlan_def_state = BR_STATE_DISABLED;
|
||||
p->horizon = BR_NOHORIZON;
|
||||
p->switch_group = BR_NOSWITCH;
|
||||
err = br_multicast_add_port(p);
|
||||
if (err) {
|
||||
dev_put(dev);
|
||||
kfree(p);
|
||||
p = ERR_PTR(err);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int br_add_bridge(struct net *net, const char *name)
|
||||
{
|
||||
struct net_device *dev;
|
||||
int res;
|
||||
|
||||
dev = alloc_netdev(sizeof(struct net_bridge), name, NET_NAME_UNKNOWN,
|
||||
br_dev_setup);
|
||||
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_net_set(dev, net);
|
||||
dev->rtnl_link_ops = &br_link_ops;
|
||||
|
||||
res = register_netdev(dev);
|
||||
if (res)
|
||||
free_netdev(dev);
|
||||
return res;
|
||||
}
|
||||
|
||||
int br_del_bridge(struct net *net, const char *name)
|
||||
{
|
||||
struct net_device *dev;
|
||||
int ret = 0;
|
||||
|
||||
rtnl_lock();
|
||||
dev = __dev_get_by_name(net, name);
|
||||
if (dev == NULL)
|
||||
ret = -ENXIO; /* Could not find device */
|
||||
|
||||
else if (!(dev->priv_flags & IFF_EBRIDGE)) {
|
||||
/* Attempt to delete non bridge device! */
|
||||
ret = -EPERM;
|
||||
}
|
||||
|
||||
else if (dev->flags & IFF_UP) {
|
||||
/* Not shutdown yet. */
|
||||
ret = -EBUSY;
|
||||
}
|
||||
|
||||
else
|
||||
br_dev_delete(dev, NULL);
|
||||
|
||||
rtnl_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */
|
||||
static int br_mtu_min(const struct net_bridge *br)
|
||||
{
|
||||
const struct net_bridge_port *p;
|
||||
int ret_mtu = 0;
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
int dm = p->dev->l2mtu;
|
||||
if (!dm) dm = p->dev->mtu;
|
||||
if (!ret_mtu || ret_mtu > dm)
|
||||
ret_mtu = dm;
|
||||
}
|
||||
|
||||
return ret_mtu ? ret_mtu : ETH_DATA_LEN;
|
||||
}
|
||||
|
||||
void br_mtu_auto_adjust(struct net_bridge *br)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
/* if the bridge MTU was manually configured don't mess with it */
|
||||
if (br_opt_get(br, BROPT_MTU_SET_BY_USER))
|
||||
return;
|
||||
|
||||
/* change to the minimum MTU and clear the flag which was set by
|
||||
* the bridge ndo_change_mtu callback
|
||||
*/
|
||||
dev_set_mtu(br->dev, br_mtu_min(br));
|
||||
br_opt_toggle(br, BROPT_MTU_SET_BY_USER, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void br_set_gso_limits(struct net_bridge *br)
|
||||
{
|
||||
unsigned int gso_max_size = GSO_MAX_SIZE;
|
||||
u16 gso_max_segs = GSO_MAX_SEGS;
|
||||
const struct net_bridge_port *p;
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
gso_max_size = min(gso_max_size, p->dev->gso_max_size);
|
||||
gso_max_segs = min(gso_max_segs, p->dev->gso_max_segs);
|
||||
}
|
||||
br->dev->gso_max_size = gso_max_size;
|
||||
br->dev->gso_max_segs = gso_max_segs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recomputes features using slave's features
|
||||
*/
|
||||
netdev_features_t br_features_recompute(struct net_bridge *br,
|
||||
netdev_features_t features)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
netdev_features_t mask;
|
||||
|
||||
if (list_empty(&br->port_list))
|
||||
return features;
|
||||
|
||||
mask = features;
|
||||
features &= ~NETIF_F_ONE_FOR_ALL;
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
features = netdev_increment_features(features,
|
||||
p->dev->features, mask);
|
||||
}
|
||||
features = netdev_add_tso_features(features, mask);
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
/* called with RTNL */
|
||||
int br_add_if(struct net_bridge *br, struct net_device *dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
int err = 0;
|
||||
unsigned br_hr, dev_hr;
|
||||
// bool changed_addr;
|
||||
|
||||
/* Don't allow bridging non-ethernet like devices, or DSA-enabled
|
||||
* master network devices since the bridge layer rx_handler prevents
|
||||
* the DSA fake ethertype handler to be invoked, so we do not strip off
|
||||
* the DSA switch tag protocol header and the bridge layer just return
|
||||
* RX_HANDLER_CONSUMED, stopping RX processing for these frames.
|
||||
*/
|
||||
if ((dev->flags & IFF_LOOPBACK) ||
|
||||
(dev->type != ARPHRD_ETHER && dev->type != ARPHRD_PPP) ||
|
||||
netdev_uses_dsa(dev))
|
||||
return -EINVAL;
|
||||
|
||||
/* No bridging of bridges */
|
||||
if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Can not enslave a bridge to a bridge");
|
||||
return -ELOOP;
|
||||
}
|
||||
|
||||
/* Device has master upper dev */
|
||||
if (netdev_master_upper_dev_get(dev))
|
||||
return -EBUSY;
|
||||
|
||||
/* No bridging devices that dislike that (e.g. wireless) */
|
||||
if (dev->priv_flags & IFF_DONT_BRIDGE) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Device does not allow enslaving to a bridge");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
p = new_nbp(br, dev);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
|
||||
call_netdevice_notifiers(NETDEV_JOIN, dev);
|
||||
|
||||
err = dev_set_allmulti(dev, 1);
|
||||
if (err) {
|
||||
kfree(p); /* kobject not yet init'd, manually free */
|
||||
goto err1;
|
||||
}
|
||||
|
||||
// err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
|
||||
// SYSFS_BRIDGE_PORT_ATTR);
|
||||
// if (err)
|
||||
// goto err2;
|
||||
|
||||
// err = br_sysfs_addif(p);
|
||||
// if (err)
|
||||
// goto err2;
|
||||
|
||||
// err = br_netpoll_enable(p);
|
||||
// if (err)
|
||||
// goto err3;
|
||||
|
||||
err = netdev_rx_handler_register(dev, br_handle_frame, p);
|
||||
if (err)
|
||||
goto err4;
|
||||
|
||||
dev->priv_flags |= IFF_BRIDGE_PORT;
|
||||
|
||||
err = netdev_master_upper_dev_link(dev, br->dev, NULL, NULL, extack);
|
||||
if (err)
|
||||
goto err5;
|
||||
|
||||
err = nbp_switchdev_mark_set(p);
|
||||
if (err)
|
||||
goto err6;
|
||||
|
||||
dev_disable_lro(dev);
|
||||
|
||||
list_add_rcu(&p->list, &br->port_list);
|
||||
|
||||
nbp_update_port_count(br);
|
||||
|
||||
netdev_update_features(br->dev);
|
||||
|
||||
br_hr = br->dev->needed_headroom;
|
||||
dev_hr = netdev_get_fwd_headroom(dev);
|
||||
if (br_hr < dev_hr)
|
||||
update_headroom(br, dev_hr);
|
||||
else
|
||||
netdev_set_rx_headroom(dev, br_hr);
|
||||
|
||||
if (dev->type == ARPHRD_ETHER && br_fdb_insert(br, p, dev->dev_addr, 0))
|
||||
netdev_err(dev, "failed insert local address bridge forwarding table\n");
|
||||
|
||||
if (br->dev->addr_assign_type != NET_ADDR_SET) {
|
||||
/* Ask for permission to use this MAC address now, even if we
|
||||
* don't end up choosing it below.
|
||||
*/
|
||||
err = dev_pre_changeaddr_notify(br->dev, dev->dev_addr, extack);
|
||||
if (err)
|
||||
goto err7;
|
||||
}
|
||||
|
||||
err = nbp_vlan_init(p, extack);
|
||||
if (err) {
|
||||
netdev_err(dev, "failed to initialize vlan filtering on this port\n");
|
||||
goto err7;
|
||||
}
|
||||
|
||||
// spin_lock_bh(&br->lock);
|
||||
// changed_addr = br_stp_recalculate_bridge_id(br);
|
||||
|
||||
// if (netif_running(dev) && netif_oper_up(dev) &&
|
||||
// (br->dev->flags & IFF_UP))
|
||||
// br_stp_enable_port(p);
|
||||
// spin_unlock_bh(&br->lock);
|
||||
|
||||
br_ifinfo_notify(RTM_NEWLINK, NULL, p);
|
||||
|
||||
// if (changed_addr)
|
||||
// call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
|
||||
|
||||
#if 0 // do not change bridge MTU under the hood
|
||||
br_mtu_auto_adjust(br);
|
||||
#endif
|
||||
br_set_gso_limits(br);
|
||||
|
||||
// kobject_uevent(&p->kobj, KOBJ_ADD);
|
||||
|
||||
rcu_assign_pointer(dev->master_dev, br->dev);
|
||||
|
||||
++br->port_count;
|
||||
register_fast_path(&bridge_fast_path, dev);
|
||||
br_update_fast_forward(br);
|
||||
|
||||
return 0;
|
||||
|
||||
err7:
|
||||
list_del_rcu(&p->list);
|
||||
br_fdb_delete_by_port(br, p, 0, 1);
|
||||
nbp_update_port_count(br);
|
||||
err6:
|
||||
netdev_upper_dev_unlink(dev, br->dev);
|
||||
err5:
|
||||
dev->priv_flags &= ~IFF_BRIDGE_PORT;
|
||||
netdev_rx_handler_unregister(dev);
|
||||
err4:
|
||||
// br_netpoll_disable(p);
|
||||
//err3:
|
||||
// sysfs_remove_link(br->ifobj, p->dev->name);
|
||||
//err2:
|
||||
// kobject_put(&p->kobj);
|
||||
dev_set_allmulti(dev, -1);
|
||||
err1:
|
||||
dev_put(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* called with RTNL */
|
||||
int br_del_if(struct net_bridge *br, struct net_device *dev)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
// bool changed_addr;
|
||||
|
||||
p = br_port_get_rtnl(dev);
|
||||
if (!p || p->br != br)
|
||||
return -EINVAL;
|
||||
|
||||
/* Since more than one interface can be attached to a bridge,
|
||||
* there still maybe an alternate path for netconsole to use;
|
||||
* therefore there is no reason for a NETDEV_RELEASE event.
|
||||
*/
|
||||
del_nbp(p);
|
||||
|
||||
#if 0 // do not change bridge MTU under the hood
|
||||
br_mtu_auto_adjust(br);
|
||||
#endif
|
||||
br_set_gso_limits(br);
|
||||
|
||||
// spin_lock_bh(&br->lock);
|
||||
// changed_addr = br_stp_recalculate_bridge_id(br);
|
||||
// spin_unlock_bh(&br->lock);
|
||||
|
||||
// if (changed_addr)
|
||||
// call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
|
||||
|
||||
netdev_update_features(br->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void br_port_flags_change(struct net_bridge_port *p, unsigned long mask)
|
||||
{
|
||||
struct net_bridge *br = p->br;
|
||||
|
||||
if (mask & BR_AUTO_MASK)
|
||||
nbp_update_port_count(br);
|
||||
|
||||
// if (mask & BR_NEIGH_SUPPRESS)
|
||||
// br_recalculate_neigh_suppress_enabled(br);
|
||||
}
|
||||
|
||||
bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
|
||||
p = br_port_get_rtnl_rcu(dev);
|
||||
if (!p)
|
||||
return false;
|
||||
|
||||
return p->flags & flag;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(br_port_flag_is_set);
|
||||
|
||||
void br_update_fast_forward(struct net_bridge *br) {
|
||||
struct net_bridge_port *p;
|
||||
bool ff = br->allow_fast_forward && br->port_count == 2
|
||||
&& !(br->dev->flags & IFF_PROMISC) && !br_opt_get(br, BROPT_VLAN_ENABLED)
|
||||
&& !br->dhcp_snooping;
|
||||
if (ff) {
|
||||
struct net_bridge_port *p1 = list_entry(br->port_list.next, struct net_bridge_port, list);
|
||||
struct net_bridge_port *p2 = list_entry(br->port_list.prev, struct net_bridge_port, list);
|
||||
if (!ether_addr_equal(p1->dev->dev_addr, br->dev->dev_addr)
|
||||
&& !ether_addr_equal(p2->dev->dev_addr, br->dev->dev_addr)) {
|
||||
ff = false;
|
||||
}
|
||||
else if (p1->state != BR_STATE_FORWARDING || p2->state != BR_STATE_FORWARDING) {
|
||||
ff = false;
|
||||
}
|
||||
else if (p1->switch_group != BR_NOSWITCH
|
||||
|| p2->switch_group != BR_NOSWITCH) {
|
||||
ff = false;
|
||||
}
|
||||
else if (!(p1->flags & BR_FLOOD) || !(p2->flags & BR_FLOOD)) {
|
||||
ff = false;
|
||||
}
|
||||
else if (p1->horizon != BR_NOHORIZON
|
||||
|| p2->horizon != BR_NOHORIZON) {
|
||||
ff = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ff == br->fast_forward) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ff) {
|
||||
struct net_bridge_port *p1 = list_entry(br->port_list.next, struct net_bridge_port, list);
|
||||
struct net_bridge_port *p2 = list_entry(br->port_list.prev, struct net_bridge_port, list);
|
||||
p1->dev->fp.forward_dev = p2->dev;
|
||||
p2->dev->fp.forward_dev = p1->dev;
|
||||
register_fast_path(&bridge_fast_forward, p1->dev);
|
||||
register_fast_path(&bridge_fast_forward, p2->dev);
|
||||
}
|
||||
else {
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
unregister_fast_path(&bridge_fast_forward, p->dev);
|
||||
}
|
||||
}
|
||||
br->fast_forward = ff;
|
||||
}
|
||||
390
2025-03-19/bridge2/br_input.c
Normal file
390
2025-03-19/bridge2/br_input.c
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Handle incoming frames
|
||||
* Linux ethernet bridge
|
||||
*
|
||||
* Authors:
|
||||
* Lennert Buytenhek <buytenh@gnu.org>
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
|
||||
#include <net/netfilter/nf_queue.h>
|
||||
#endif
|
||||
#include <linux/neighbour.h>
|
||||
#include <net/arp.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/rculist.h>
|
||||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
#include <linux/packet_hook.h>
|
||||
|
||||
DECLARE_PER_CPU(struct net_device *, per_cpu_port);
|
||||
|
||||
static int
|
||||
br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
br_drop_fake_rtable(skb);
|
||||
return netif_receive_skb(skb);
|
||||
}
|
||||
|
||||
static int br_pass_frame_up(struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
|
||||
struct net_bridge *br = netdev_priv(brdev);
|
||||
struct net_bridge_vlan_group *vg;
|
||||
|
||||
vg = br_vlan_group_rcu(br);
|
||||
/* Bridge is just like any other port. Make sure the
|
||||
* packet is allowed except in promisc modue when someone
|
||||
* may be running packet capture.
|
||||
*/
|
||||
if (!(brdev->flags & IFF_PROMISC) &&
|
||||
!br_allowed_egress(vg, skb)) {
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
indev = skb->dev;
|
||||
skb->dev = brdev;
|
||||
skb = br_handle_vlan(br, NULL, vg, skb);
|
||||
if (!skb)
|
||||
return NET_RX_DROP;
|
||||
/* update the multicast stats if the packet is IGMP/MLD */
|
||||
br_multicast_count(br, NULL, skb, br_multicast_igmp_type(skb),
|
||||
BR_MCAST_DIR_TX);
|
||||
|
||||
fast_path_sp_rx_inc(br->dev, skb->len);
|
||||
|
||||
if (likely(!get_cpu_var(per_cpu_port))) {
|
||||
get_cpu_var(per_cpu_port) = indev;
|
||||
}
|
||||
int ret = NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
|
||||
dev_net(indev), NULL, skb, indev, NULL,
|
||||
br_netif_receive_skb);
|
||||
get_cpu_var(per_cpu_port) = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* note: already called with rcu_read_lock (preempt_disabled) */
|
||||
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
|
||||
enum br_pkt_type pkt_type = BR_PKT_UNICAST;
|
||||
struct net_bridge_fdb_entry *dst = NULL;
|
||||
struct net_bridge_mdb_entry *mdst;
|
||||
bool local_rcv, mcast_hit = false;
|
||||
struct net_bridge *br;
|
||||
u16 vid = 0;
|
||||
u8 state;
|
||||
|
||||
if (!p || p->state == BR_STATE_DISABLED)
|
||||
goto drop;
|
||||
|
||||
BR_INPUT_SKB_CB(skb)->src_port_hw_switched = p->switch_group != BR_NOSWITCH;
|
||||
state = p->vlan_def_state;
|
||||
if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), p->vlan_ingress, skb, &vid,
|
||||
&state))
|
||||
goto out;
|
||||
|
||||
nbp_switchdev_frame_mark(p, skb);
|
||||
|
||||
/* insert into forwarding database after filtering to avoid spoofing */
|
||||
br = p->br;
|
||||
if (p->flags & BR_LEARNING)
|
||||
br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, 0);
|
||||
|
||||
local_rcv = !!(br->dev->flags & IFF_PROMISC);
|
||||
if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) {
|
||||
/* by definition the broadcast is also a multicast address */
|
||||
if (is_broadcast_ether_addr(eth_hdr(skb)->h_dest)) {
|
||||
pkt_type = BR_PKT_BROADCAST;
|
||||
local_rcv = true;
|
||||
} else {
|
||||
pkt_type = BR_PKT_MULTICAST;
|
||||
if (br_multicast_rcv(br, p, skb, vid, false))
|
||||
goto drop;
|
||||
}
|
||||
}
|
||||
|
||||
if (br_dhcp_rcv(br, p, skb, vid))
|
||||
goto drop;
|
||||
|
||||
if (state == BR_STATE_LEARNING)
|
||||
goto drop;
|
||||
|
||||
BR_INPUT_SKB_CB(skb)->brdev = br->dev;
|
||||
BR_INPUT_SKB_CB(skb)->src_port_isolated = !!(p->flags & BR_ISOLATED);
|
||||
BR_INPUT_SKB_CB(skb)->src_port_peer_link = !!(p->flags & BR_MLAG_PEER_LINK);
|
||||
|
||||
// if (IS_ENABLED(CONFIG_INET) &&
|
||||
// (skb->protocol == htons(ETH_P_ARP) ||
|
||||
// skb->protocol == htons(ETH_P_RARP))) {
|
||||
// br_do_proxy_suppress_arp(skb, br, vid, p);
|
||||
// } else if (IS_ENABLED(CONFIG_IPV6) &&
|
||||
// skb->protocol == htons(ETH_P_IPV6) &&
|
||||
// br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) &&
|
||||
// pskb_may_pull(skb, sizeof(struct ipv6hdr) +
|
||||
// sizeof(struct nd_msg)) &&
|
||||
// ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
|
||||
// struct nd_msg *msg, _msg;
|
||||
|
||||
// msg = br_is_nd_neigh_msg(skb, &_msg);
|
||||
// if (msg)
|
||||
// br_do_suppress_nd(skb, br, vid, p, msg);
|
||||
// }
|
||||
|
||||
switch (pkt_type) {
|
||||
case BR_PKT_MULTICAST:
|
||||
mdst = br_mdb_get(br, skb, vid);
|
||||
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
|
||||
br_multicast_querier_exists(br, eth_hdr(skb))) {
|
||||
if ((mdst && mdst->host_joined) ||
|
||||
br_multicast_is_router(br)) {
|
||||
local_rcv = true;
|
||||
br->dev->stats.multicast++;
|
||||
}
|
||||
mcast_hit = true;
|
||||
} else {
|
||||
local_rcv = true;
|
||||
br->dev->stats.multicast++;
|
||||
}
|
||||
break;
|
||||
case BR_PKT_UNICAST:
|
||||
dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dst) {
|
||||
unsigned long now = jiffies;
|
||||
|
||||
if (test_bit(BR_FDB_LOCAL, &dst->flags))
|
||||
return br_pass_frame_up(skb);
|
||||
|
||||
if (now != dst->used)
|
||||
dst->used = now;
|
||||
br_forward(dst->dst, skb, local_rcv, false, p->horizon, p->switch_group);
|
||||
} else {
|
||||
if (!mcast_hit)
|
||||
br_flood(br, skb, pkt_type, local_rcv, false, p->horizon, p->switch_group);
|
||||
else
|
||||
br_multicast_flood(mdst, skb, local_rcv, false, p->horizon, p->switch_group);
|
||||
}
|
||||
|
||||
if (local_rcv)
|
||||
return br_pass_frame_up(skb);
|
||||
|
||||
out:
|
||||
return 0;
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
goto out;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(br_handle_frame_finish);
|
||||
|
||||
static void __br_handle_local_finish(struct sk_buff *skb)
|
||||
{
|
||||
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
|
||||
u16 vid = 0;
|
||||
|
||||
/* check if vlan is allowed, to avoid spoofing */
|
||||
if ((p->flags & BR_LEARNING) &&
|
||||
nbp_state_should_learn(p) &&
|
||||
!br_opt_get(p->br, BROPT_NO_LL_LEARN) &&
|
||||
br_should_learn(p, skb, &vid))
|
||||
br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, 0);
|
||||
}
|
||||
|
||||
/* note: already called with rcu_read_lock */
|
||||
static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
__br_handle_local_finish(skb);
|
||||
|
||||
/* return 1 to signal the okfn() was called so it's ok to use the skb */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nf_hook_bridge_pre(struct sk_buff *skb, struct sk_buff **pskb)
|
||||
{
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
|
||||
struct nf_hook_entries *e = NULL;
|
||||
struct nf_hook_state state;
|
||||
unsigned int verdict, i;
|
||||
struct net *net;
|
||||
int ret;
|
||||
|
||||
net = dev_net(skb->dev);
|
||||
#ifdef CONFIG_JUMP_LABEL
|
||||
if (!static_key_false(&nf_hooks_needed[NFPROTO_BRIDGE][NF_BR_PRE_ROUTING]))
|
||||
goto frame_finish;
|
||||
#endif
|
||||
|
||||
e = rcu_dereference(net->nf.hooks_bridge[NF_BR_PRE_ROUTING]);
|
||||
if (!e)
|
||||
goto frame_finish;
|
||||
|
||||
nf_hook_state_init(&state, NF_BR_PRE_ROUTING,
|
||||
NFPROTO_BRIDGE, skb->dev, NULL, NULL,
|
||||
net, br_handle_frame_finish);
|
||||
|
||||
for (i = 0; i < e->num_hook_entries; i++) {
|
||||
verdict = nf_hook_entry_hookfn(&e->hooks[i], skb, &state);
|
||||
switch (verdict & NF_VERDICT_MASK) {
|
||||
case NF_ACCEPT:
|
||||
if (BR_INPUT_SKB_CB(skb)->br_netfilter_broute) {
|
||||
*pskb = skb;
|
||||
return RX_HANDLER_PASS;
|
||||
}
|
||||
break;
|
||||
case NF_DROP:
|
||||
kfree_skb(skb);
|
||||
return RX_HANDLER_CONSUMED;
|
||||
case NF_QUEUE:
|
||||
ret = nf_queue(skb, &state, i, verdict);
|
||||
if (ret == 1)
|
||||
continue;
|
||||
return RX_HANDLER_CONSUMED;
|
||||
default: /* STOLEN */
|
||||
return RX_HANDLER_CONSUMED;
|
||||
}
|
||||
}
|
||||
frame_finish:
|
||||
net = dev_net(skb->dev);
|
||||
br_handle_frame_finish(net, NULL, skb);
|
||||
#else
|
||||
br_handle_frame_finish(dev_net(skb->dev), NULL, skb);
|
||||
#endif
|
||||
return RX_HANDLER_CONSUMED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return NULL if skb is handled
|
||||
* note: already called with rcu_read_lock
|
||||
*/
|
||||
rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
struct sk_buff *skb = *pskb;
|
||||
const unsigned char *dest = eth_hdr(skb)->h_dest;
|
||||
|
||||
if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
|
||||
return RX_HANDLER_PASS;
|
||||
|
||||
/* do not bridge regular ip packets without ethernet header */
|
||||
if (skb_mac_header(skb) == skb->data)
|
||||
return RX_HANDLER_PASS;
|
||||
|
||||
if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
|
||||
goto drop;
|
||||
|
||||
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return RX_HANDLER_CONSUMED;
|
||||
|
||||
memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
|
||||
|
||||
p = br_port_get_rcu(skb->dev);
|
||||
if (p->flags & BR_VLAN_TUNNEL) {
|
||||
if (br_handle_ingress_vlan_tunnel(skb, p,
|
||||
nbp_vlan_group_rcu(p)))
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (unlikely(is_link_local_ether_addr(dest))) {
|
||||
u16 fwd_mask = p->br->group_fwd_mask_required;
|
||||
|
||||
/*
|
||||
* See IEEE 802.1D Table 7-10 Reserved addresses
|
||||
*
|
||||
* Assignment Value
|
||||
* Bridge Group Address 01-80-C2-00-00-00
|
||||
* (MAC Control) 802.3 01-80-C2-00-00-01
|
||||
* (Link Aggregation) 802.3 01-80-C2-00-00-02
|
||||
* 802.1X PAE address 01-80-C2-00-00-03
|
||||
*
|
||||
* 802.1AB LLDP 01-80-C2-00-00-0E
|
||||
*
|
||||
* Others reserved for future standardization
|
||||
*/
|
||||
switch (dest[5]) {
|
||||
case 0x00: /* Bridge Group Address */
|
||||
case 0x08:
|
||||
/* If STP is turned off,
|
||||
then must forward to keep loop detection */
|
||||
if (p->br->stp_enabled == BR_NO_STP ||
|
||||
fwd_mask & (1u << dest[5]))
|
||||
goto forward;
|
||||
*pskb = skb;
|
||||
__br_handle_local_finish(skb);
|
||||
return RX_HANDLER_PASS;
|
||||
|
||||
case 0x01: /* IEEE MAC (Pause) */
|
||||
goto drop;
|
||||
|
||||
case 0x03:
|
||||
case 0x0E:
|
||||
if (p->br->stp_enabled == BR_NO_STP)
|
||||
goto forward;
|
||||
*pskb = skb;
|
||||
__br_handle_local_finish(skb);
|
||||
return RX_HANDLER_PASS;
|
||||
|
||||
default:
|
||||
/* Allow selective forwarding for most other protocols */
|
||||
fwd_mask |= p->br->group_fwd_mask;
|
||||
if (fwd_mask & (1u << dest[5]))
|
||||
goto forward;
|
||||
}
|
||||
|
||||
/* The else clause should be hit when nf_hook():
|
||||
* - returns < 0 (drop/error)
|
||||
* - returns = 0 (stolen/nf_queue)
|
||||
* Thus return 1 from the okfn() to signal the skb is ok to pass
|
||||
*/
|
||||
if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
|
||||
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
|
||||
br_handle_local_finish) == 1) {
|
||||
return RX_HANDLER_PASS;
|
||||
} else {
|
||||
return RX_HANDLER_CONSUMED;
|
||||
}
|
||||
}
|
||||
|
||||
forward:
|
||||
switch (p->state) {
|
||||
case BR_STATE_FORWARDING:
|
||||
case BR_STATE_LEARNING:
|
||||
if (ether_addr_equal(p->br->dev->dev_addr, dest))
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
|
||||
return nf_hook_bridge_pre(skb, pskb);
|
||||
default:
|
||||
{
|
||||
// XXX: original goal for this for detnet to be able to receive dhcp server
|
||||
// offer/ack response and arp packets early to classify port as wan before any lan
|
||||
// packets begin leaking into actual wan port
|
||||
u16 vid = 0;
|
||||
u8 state = BR_STATE_FORWARDING;
|
||||
BR_INPUT_SKB_CB(skb)->src_port_hw_switched = p->switch_group != BR_NOSWITCH;
|
||||
if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), p->vlan_ingress, skb, &vid,
|
||||
&state))
|
||||
goto out;
|
||||
|
||||
if (eth_hdr(skb)->h_proto == __constant_htons(ETH_P_IP)) {
|
||||
custom_packet_hook_rx(skb);
|
||||
}
|
||||
else if (eth_hdr(skb)->h_proto == __constant_htons(ETH_P_ARP)) {
|
||||
packet_hook_send(PACKET_HOOK_ARP, skb->dev->ifindex, skb);
|
||||
}
|
||||
}
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
out:
|
||||
return RX_HANDLER_CONSUMED;
|
||||
}
|
||||
712
2025-03-19/bridge2/br_ioctl.c
Normal file
712
2025-03-19/bridge2/br_ioctl.c
Normal file
|
|
@ -0,0 +1,712 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Ioctl handler
|
||||
* Linux ethernet bridge
|
||||
*
|
||||
* Authors:
|
||||
* Lennert Buytenhek <buytenh@gnu.org>
|
||||
*/
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/times.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include "br_private.h"
|
||||
|
||||
/* called with RTNL */
|
||||
static int get_bridge_ifindices(struct net *net, int *indices, int num)
|
||||
{
|
||||
struct net_device *dev;
|
||||
int i = 0;
|
||||
|
||||
for_each_netdev(net, dev) {
|
||||
if (i >= num)
|
||||
break;
|
||||
if (dev->priv_flags & IFF_EBRIDGE)
|
||||
indices[i++] = dev->ifindex;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* called with RTNL */
|
||||
static void get_port_ifindices(struct net_bridge *br, int *ifindices, int num)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
int i = 0;
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
ifindices[i++] = p->dev->ifindex;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Format up to a page worth of forwarding table entries
|
||||
* userbuf -- where to copy result
|
||||
* maxnum -- maximum number of entries desired
|
||||
* (limited to a page for sanity)
|
||||
* offset -- number of records to skip
|
||||
*/
|
||||
static int get_fdb_entries(struct net_bridge *br, void __user *userbuf,
|
||||
unsigned long maxnum, unsigned long offset)
|
||||
{
|
||||
int num;
|
||||
void *buf;
|
||||
size_t size;
|
||||
|
||||
/* Clamp size to PAGE_SIZE, test maxnum to avoid overflow */
|
||||
if (maxnum > PAGE_SIZE/sizeof(struct abrctl_fdb_entry))
|
||||
maxnum = PAGE_SIZE/sizeof(struct abrctl_fdb_entry);
|
||||
|
||||
size = maxnum * sizeof(struct abrctl_fdb_entry);
|
||||
|
||||
buf = kmalloc(size, GFP_USER);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
num = br_fdb_fillbuf(br, buf, maxnum, offset);
|
||||
if (num > 0) {
|
||||
if (copy_to_user(userbuf, buf, num*sizeof(struct abrctl_fdb_entry)))
|
||||
num = -EFAULT;
|
||||
}
|
||||
kfree(buf);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static int add_del_if(struct net_bridge *br, int ifindex, int isadd)
|
||||
{
|
||||
struct net *net = dev_net(br->dev);
|
||||
struct net_device *dev;
|
||||
int ret;
|
||||
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
dev = __dev_get_by_index(net, ifindex);
|
||||
if (dev == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (isadd)
|
||||
ret = br_add_if(br, dev, NULL);
|
||||
else
|
||||
ret = br_del_if(br, dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct net_bridge_port *find_port(struct net_bridge *br, int ifindex)
|
||||
{
|
||||
struct net_bridge_port *p = NULL;
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (p->dev->ifindex == ifindex) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy ioctl's through SIOCDEVPRIVATE
|
||||
* This interface is deprecated because it was too difficult to
|
||||
* to do the translation for 32/64bit ioctl compatability.
|
||||
*/
|
||||
static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
#ifdef CONFIG_64BIT
|
||||
// XXX: 32bit compatibility for tile. 64bit userspace not supported
|
||||
unsigned args_small[4];
|
||||
unsigned long args[4];
|
||||
if (copy_from_user(args_small, rq->ifr_data, sizeof(args_small)))
|
||||
return -EFAULT;
|
||||
args[0] = args_small[0];
|
||||
args[1] = args_small[1];
|
||||
args[2] = args_small[2];
|
||||
args[3] = args_small[3];
|
||||
switch (args[0]) {
|
||||
case BRCTL_GET_BRIDGE_INFO:
|
||||
case BRCTL_GET_PORT_LIST:
|
||||
case BRCTL_GET_FDB_ENTRIES:
|
||||
case ABRCTL_SET_MC_OPTS:
|
||||
args[1] = (unsigned long)compat_ptr(args_small[1]);
|
||||
break;
|
||||
case ABRCTL_SET_INFO_OPT:
|
||||
args[1] = (unsigned long)compat_ptr(args_small[1]);
|
||||
args[2] = (unsigned long)compat_ptr(args_small[2]);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
unsigned long args[4];
|
||||
if (copy_from_user(args, rq->ifr_data, sizeof(args)))
|
||||
return -EFAULT;
|
||||
#endif
|
||||
|
||||
switch (args[0]) {
|
||||
case BRCTL_ADD_IF:
|
||||
case BRCTL_DEL_IF:
|
||||
return add_del_if(br, args[1], args[0] == BRCTL_ADD_IF);
|
||||
|
||||
case BRCTL_GET_BRIDGE_INFO:
|
||||
{
|
||||
struct __bridge_info b;
|
||||
|
||||
memset(&b, 0, sizeof(struct __bridge_info));
|
||||
rcu_read_lock();
|
||||
/*
|
||||
memcpy(&b.designated_root, &br->designated_root, 8);
|
||||
memcpy(&b.bridge_id, &br->bridge_id, 8);
|
||||
b.root_path_cost = br->root_path_cost;
|
||||
b.max_age = jiffies_to_clock_t(br->max_age);
|
||||
b.hello_time = jiffies_to_clock_t(br->hello_time);
|
||||
b.forward_delay = br->forward_delay;
|
||||
b.bridge_max_age = br->bridge_max_age;
|
||||
b.bridge_hello_time = br->bridge_hello_time;
|
||||
b.bridge_forward_delay = jiffies_to_clock_t(br->bridge_forward_delay);
|
||||
b.topology_change = br->topology_change;
|
||||
b.topology_change_detected = br->topology_change_detected;
|
||||
b.root_port = br->root_port;
|
||||
b.stp_enabled = br->stp_enabled;
|
||||
*/
|
||||
b.ageing_time = jiffies_to_clock_t(br->ageing_time);
|
||||
/*
|
||||
b.hello_timer_value = br_timer_value(&br->hello_timer);
|
||||
b.tcn_timer_value = br_timer_value(&br->tcn_timer);
|
||||
b.topology_change_timer_value = br_timer_value(&br->topology_change_timer);
|
||||
*/
|
||||
rcu_read_unlock();
|
||||
|
||||
if (copy_to_user((void __user *)args[1], &b, sizeof(b)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case BRCTL_GET_PORT_LIST:
|
||||
{
|
||||
int num, *indices;
|
||||
|
||||
num = args[2];
|
||||
if (num < 0)
|
||||
return -EINVAL;
|
||||
if (num == 0)
|
||||
num = 256;
|
||||
if (num > BR_MAX_PORTS)
|
||||
num = BR_MAX_PORTS;
|
||||
|
||||
indices = kcalloc(num, sizeof(int), GFP_KERNEL);
|
||||
if (indices == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
get_port_ifindices(br, indices, num);
|
||||
if (copy_to_user((void __user *)args[1], indices, num*sizeof(int)))
|
||||
num = -EFAULT;
|
||||
kfree(indices);
|
||||
return num;
|
||||
}
|
||||
|
||||
case BRCTL_SET_AGEING_TIME:
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
br->ageing_time = args[1];
|
||||
return 0;
|
||||
|
||||
case BRCTL_SET_BRIDGE_STP_STATE:
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
br->stp_enabled = args[1] & 3 ? BR_USER_STP : BR_NO_STP;
|
||||
if (br->stp_enabled == BR_NO_STP) {
|
||||
br->group_fwd_mask = 0xffff;
|
||||
}
|
||||
br->allow_fast_forward = !!(args[1] & 4);
|
||||
br_multicast_toggle(br, !!(args[1] & 8));
|
||||
br_vlan_filter_toggle(br, !!(args[1] & 0x10));
|
||||
br_vlan_set_proto(br, args[2]);
|
||||
br->dhcp_snooping = !!(args[1] & 0x20);
|
||||
br->add_info_option = !!(args[1] & 0x40);
|
||||
|
||||
return 0;
|
||||
|
||||
case BRCTL_GET_FDB_ENTRIES:
|
||||
return get_fdb_entries(br, (void __user *)args[1],
|
||||
args[2], args[3]);
|
||||
|
||||
case ABRCTL_GET_MC_ROUTER: {
|
||||
struct net_bridge_port *p;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_bh(&br->multicast_lock);
|
||||
if (args[1] == 0) {
|
||||
ret = br_multicast_is_router(br);
|
||||
}
|
||||
else {
|
||||
hlist_for_each_entry(p, &br->router_list, rlist) {
|
||||
if (p->dev->ifindex == args[1]) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&br->multicast_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
case ABRCTL_FDB_FLUSH: {
|
||||
struct net_bridge_port *p = NULL;
|
||||
unsigned portidx = args[1];
|
||||
unsigned vid = args[2];
|
||||
// unsigned external = args[3];
|
||||
int ret = 0;
|
||||
spin_lock_bh(&br->lock);
|
||||
|
||||
if (portidx != 0) {
|
||||
p = find_port(br, portidx);
|
||||
if (!p) {
|
||||
ret = -ENODEV;
|
||||
goto out_delete;
|
||||
}
|
||||
}
|
||||
// if (external) {
|
||||
// br_fdb_flush_ext(br);
|
||||
// } else {
|
||||
br_fdb_delete_by_port(br, p, vid, 0);
|
||||
// }
|
||||
out_delete:
|
||||
spin_unlock_bh(&br->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
case ABRCTL_SET_PORTHORIZON: {
|
||||
int ret = -ENODEV;
|
||||
struct net_bridge_port *p;
|
||||
|
||||
spin_lock_bh(&br->lock);
|
||||
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (p->dev->ifindex == args[1]) {
|
||||
br_debug(br, "update %s horizon from 0x%x to 0x%x\n",
|
||||
p->dev->name, p->horizon, (unsigned)args[2]);
|
||||
p->horizon = args[2];
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_bh(&br->lock);
|
||||
br_update_fast_forward(br);
|
||||
return ret;
|
||||
}
|
||||
|
||||
case ABRCTL_SET_SWITCH_GROUP: {
|
||||
int ret = -ENODEV;
|
||||
struct net_bridge_port *p;
|
||||
unsigned old = BR_NOSWITCH;
|
||||
|
||||
spin_lock_bh(&br->lock);
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (p->dev->ifindex == args[1]) {
|
||||
old = p->switch_group;
|
||||
p->switch_group = args[2];
|
||||
ret = 0;
|
||||
br_debug(p->br, "set group %s %u\n",
|
||||
p->dev->name, p->switch_group);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&br->lock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (old != p->switch_group) {
|
||||
int type;
|
||||
if (p->switch_group == BR_NOSWITCH) {
|
||||
br_multicast_offload(p, false);
|
||||
type = RTM_DELNEIGH;
|
||||
}
|
||||
else {
|
||||
br_multicast_offload(p, true);
|
||||
type = RTM_NEWNEIGH;
|
||||
}
|
||||
|
||||
/* If port removed from hw then notify to remove all user entries. Otherwise
|
||||
* install them. */
|
||||
struct net_bridge_fdb_entry *f;
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
|
||||
if (test_bit(BR_FDB_ADDED_BY_USER, &f->flags) && f->dst == p) {
|
||||
br_switchdev_fdb_notify(f, type);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
br_update_fast_forward(br);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case ABRCTL_ADD_VLAN: {
|
||||
unsigned ret = -ENODEV;
|
||||
unsigned portidx = args[1];
|
||||
unsigned vid = args[2];
|
||||
unsigned flags = args[3];
|
||||
struct net_bridge_port *p = NULL;
|
||||
|
||||
if (vid >= VLAN_N_VID)
|
||||
return -EINVAL;
|
||||
if (!br_opt_get(br, BROPT_VLAN_ENABLED))
|
||||
return -EFAULT;
|
||||
|
||||
br_debug(br, "add vlan %d on %d flags %08x\n",
|
||||
vid, portidx, flags);
|
||||
|
||||
bool changed;
|
||||
if (portidx) {
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (p->dev->ifindex == portidx) {
|
||||
ret = nbp_vlan_add(p, vid, flags, &changed, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
flags |= BRIDGE_VLAN_INFO_BRENTRY;
|
||||
ret = br_vlan_add(br, vid, flags, &changed, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
case ABRCTL_DEL_VLAN: {
|
||||
unsigned ret = -ENODEV;
|
||||
unsigned portidx = args[1];
|
||||
unsigned vid = args[2];
|
||||
struct net_bridge_port *p = NULL;
|
||||
|
||||
if (vid >= VLAN_N_VID)
|
||||
return -EINVAL;
|
||||
if (!br_opt_get(br, BROPT_VLAN_ENABLED))
|
||||
return -EFAULT;
|
||||
|
||||
br_debug(br, "del vlan %d on %d\n", vid, portidx);
|
||||
|
||||
if (portidx) {
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (p->dev->ifindex == portidx) {
|
||||
ret = nbp_vlan_delete(p, vid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = br_vlan_delete(br, vid);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
case ABRCTL_SET_VLAN_OPTS: {
|
||||
unsigned ret = -ENODEV;
|
||||
unsigned portidx = args[1];
|
||||
unsigned vlan_ingress = args[2];
|
||||
struct net_bridge_port *p = NULL;
|
||||
|
||||
if (!br_opt_get(br, BROPT_VLAN_ENABLED))
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_bh(&br->lock);
|
||||
|
||||
br_debug(br, "set vlan opts on %u opts %u %lu %lu\n",
|
||||
portidx,
|
||||
vlan_ingress & BR_IN_FRAME_TYPES,
|
||||
vlan_ingress & BR_IN_FILTERING,
|
||||
vlan_ingress & BR_IN_TAG_STACKING);
|
||||
|
||||
if (portidx) {
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (p->dev->ifindex == portidx) {
|
||||
p->vlan_ingress = vlan_ingress;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
br->vlan_ingress = vlan_ingress;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&br->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
case ABRCTL_SET_PORT_OPTS: {
|
||||
unsigned ret = -ENODEV;
|
||||
unsigned portidx = args[1];
|
||||
unsigned flags = args[2];
|
||||
struct net_bridge_port *p = NULL;
|
||||
|
||||
spin_lock_bh(&br->lock);
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (p->dev->ifindex == portidx) {
|
||||
br_debug(br, "set port %s flag %08x\n",
|
||||
p->dev->name, flags);
|
||||
p->flags = flags;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&br->lock);
|
||||
br_update_fast_forward(br);
|
||||
return ret;
|
||||
}
|
||||
|
||||
case ABRCTL_SET_INFO_OPT: {
|
||||
unsigned ret = 0;
|
||||
unsigned portidx = args[1];
|
||||
struct bridge_info_opt req;
|
||||
struct net_bridge_port *p = NULL;
|
||||
struct net_dhcp_info_opt *old_info, *new_info;
|
||||
|
||||
if (copy_from_user(&req, (void __user *)args[2], sizeof(req)))
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_bh(&br->lock);
|
||||
|
||||
p = find_port(br, portidx);
|
||||
if (!p) {
|
||||
ret = -ENODEV;
|
||||
goto out_info_opt1;
|
||||
}
|
||||
|
||||
new_info = kzalloc(sizeof(*new_info), GFP_KERNEL);
|
||||
if (!new_info) {
|
||||
ret = -ENOMEM;
|
||||
goto out_info_opt1;
|
||||
}
|
||||
|
||||
new_info->circuit_id = kzalloc(req.circuit_id_size, GFP_KERNEL);
|
||||
if (!new_info->circuit_id) {
|
||||
ret = -ENOMEM;
|
||||
goto out_info_opt2;
|
||||
}
|
||||
|
||||
new_info->remote_id = kzalloc(req.remote_id_size, GFP_KERNEL);
|
||||
if (!new_info->remote_id) {
|
||||
ret = -ENOMEM;
|
||||
goto out_info_opt3;
|
||||
}
|
||||
|
||||
if (copy_from_user(new_info->circuit_id,
|
||||
compat_ptr(req.circuit_id),
|
||||
req.circuit_id_size)) {
|
||||
ret = -EFAULT;
|
||||
goto out_info_opt4;
|
||||
}
|
||||
if (copy_from_user(new_info->remote_id,
|
||||
compat_ptr(req.remote_id),
|
||||
req.remote_id_size)) {
|
||||
ret = -EFAULT;
|
||||
goto out_info_opt4;
|
||||
}
|
||||
|
||||
old_info = rcu_dereference(p->info_option);
|
||||
rcu_assign_pointer(p->info_option, new_info);
|
||||
|
||||
spin_unlock_bh(&br->lock);
|
||||
|
||||
if (old_info) {
|
||||
call_rcu(&old_info->rcu, destroy_info_opt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_info_opt4:
|
||||
kfree(new_info->remote_id);
|
||||
out_info_opt3:
|
||||
kfree(new_info->circuit_id);
|
||||
out_info_opt2:
|
||||
kfree(new_info);
|
||||
out_info_opt1:
|
||||
spin_unlock_bh(&br->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
case ABRCTL_SET_MC_ROUTER: {
|
||||
unsigned ret = -ENODEV;
|
||||
unsigned portidx = args[1];
|
||||
unsigned val = args[2];
|
||||
struct net_bridge_port *p = NULL;
|
||||
|
||||
spin_lock_bh(&br->lock);
|
||||
if (portidx) {
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (p->dev->ifindex == portidx) {
|
||||
local_bh_disable();
|
||||
br_multicast_set_port_router(p, val);
|
||||
local_bh_enable();
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
br_multicast_set_router(br, val);
|
||||
ret = 0;
|
||||
}
|
||||
spin_unlock_bh(&br->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
case ABRCTL_SET_MC_OPTS: {
|
||||
struct abrctl_mc_opts x;
|
||||
if (copy_from_user(&x, (void __user *)args[1], sizeof(x)) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_bh(&br->multicast_lock);
|
||||
br->multicast_last_member_count = x.last_member_count;
|
||||
br->multicast_startup_query_count = x.startup_query_count;
|
||||
br->multicast_last_member_interval = x.last_member_interval;
|
||||
br->multicast_membership_interval = x.membership_interval;
|
||||
br->multicast_querier_interval = x.querier_interval;
|
||||
br->multicast_query_interval = x.query_interval;
|
||||
br->multicast_query_response_interval = x.query_response_interval;
|
||||
br->multicast_startup_query_interval = x.startup_query_interval;
|
||||
br->multicast_igmp_version = x.igmp_version;
|
||||
br->multicast_mld_version = x.mld_version;
|
||||
spin_unlock_bh(&br->multicast_lock);
|
||||
br_multicast_set_querier(br, x.querier);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case ABRCTL_GET_FAST_FORWARD: {
|
||||
return br->fast_forward;
|
||||
}
|
||||
|
||||
case ABRCTL_GET_MC_QUERIER: {
|
||||
struct abrctl_mc_querier queriers[2] = {};
|
||||
struct net_bridge_port *port;
|
||||
|
||||
spin_lock_bh(&br->multicast_lock);
|
||||
|
||||
port = rcu_dereference(br->ip4_querier.port);
|
||||
queriers[0].portidx = port ? port->dev->ifindex : 0;
|
||||
queriers[0].addr.u.ip4 = br->ip4_querier.addr.u.ip4;
|
||||
port = rcu_dereference(br->ip6_querier.port);
|
||||
queriers[1].portidx = port ? port->dev->ifindex : 0;
|
||||
queriers[1].addr.u.ip6 = br->ip6_querier.addr.u.ip6;
|
||||
|
||||
if (copy_to_user((void __user *)args[1], &queriers, sizeof(queriers)))
|
||||
return -EFAULT;
|
||||
|
||||
spin_unlock_bh(&br->multicast_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int old_deviceless(struct net *net, void __user *uarg)
|
||||
{
|
||||
unsigned long args[3];
|
||||
|
||||
if (copy_from_user(args, uarg, sizeof(args)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (args[0]) {
|
||||
case BRCTL_GET_VERSION:
|
||||
return BRCTL_VERSION;
|
||||
|
||||
case BRCTL_GET_BRIDGES:
|
||||
{
|
||||
int *indices;
|
||||
int ret = 0;
|
||||
|
||||
if (args[2] >= 2048)
|
||||
return -ENOMEM;
|
||||
indices = kcalloc(args[2], sizeof(int), GFP_KERNEL);
|
||||
if (indices == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
args[2] = get_bridge_ifindices(net, indices, args[2]);
|
||||
|
||||
ret = copy_to_user((void __user *)args[1], indices, args[2]*sizeof(int))
|
||||
? -EFAULT : args[2];
|
||||
|
||||
kfree(indices);
|
||||
return ret;
|
||||
}
|
||||
|
||||
case BRCTL_ADD_BRIDGE:
|
||||
case BRCTL_DEL_BRIDGE:
|
||||
{
|
||||
char buf[IFNAMSIZ];
|
||||
|
||||
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(buf, (void __user *)args[1], IFNAMSIZ))
|
||||
return -EFAULT;
|
||||
|
||||
buf[IFNAMSIZ-1] = 0;
|
||||
|
||||
if (args[0] == BRCTL_ADD_BRIDGE)
|
||||
return br_add_bridge(net, buf);
|
||||
|
||||
return br_del_bridge(net, buf);
|
||||
}
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case SIOCGIFBR:
|
||||
case SIOCSIFBR:
|
||||
return old_deviceless(net, uarg);
|
||||
|
||||
case SIOCBRADDBR:
|
||||
case SIOCBRDELBR:
|
||||
{
|
||||
char buf[IFNAMSIZ];
|
||||
|
||||
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(buf, uarg, IFNAMSIZ))
|
||||
return -EFAULT;
|
||||
|
||||
buf[IFNAMSIZ-1] = 0;
|
||||
if (cmd == SIOCBRADDBR)
|
||||
return br_add_bridge(net, buf);
|
||||
|
||||
return br_del_bridge(net, buf);
|
||||
}
|
||||
}
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
{
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCDEVPRIVATE:
|
||||
return old_dev_ioctl(dev, rq, cmd);
|
||||
|
||||
case SIOCBRADDIF:
|
||||
case SIOCBRDELIF:
|
||||
return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);
|
||||
|
||||
}
|
||||
|
||||
br_debug(br, "Bridge does not support ioctl 0x%x\n", cmd);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
1019
2025-03-19/bridge2/br_mdb.c
Normal file
1019
2025-03-19/bridge2/br_mdb.c
Normal file
File diff suppressed because it is too large
Load diff
2412
2025-03-19/bridge2/br_multicast.c
Normal file
2412
2025-03-19/bridge2/br_multicast.c
Normal file
File diff suppressed because it is too large
Load diff
1195
2025-03-19/bridge2/br_netfilter_hooks.c
Normal file
1195
2025-03-19/bridge2/br_netfilter_hooks.c
Normal file
File diff suppressed because it is too large
Load diff
241
2025-03-19/bridge2/br_netfilter_ipv6.c
Normal file
241
2025-03-19/bridge2/br_netfilter_ipv6.c
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Handle firewalling
|
||||
* Linux ethernet bridge
|
||||
*
|
||||
* Authors:
|
||||
* Lennert Buytenhek <buytenh@gnu.org>
|
||||
* Bart De Schuymer <bdschuym@pandora.be>
|
||||
*
|
||||
* Lennert dedicates this file to Kerstin Wurdinger.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/if_pppox.h>
|
||||
#include <linux/ppp_defs.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <linux/netfilter_arp.h>
|
||||
#include <linux/in_route.h>
|
||||
#include <linux/inetdevice.h>
|
||||
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/addrconf.h>
|
||||
#include <net/route.h>
|
||||
#include <net/netfilter/br_netfilter.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include "br_private.h"
|
||||
#ifdef CONFIG_SYSCTL
|
||||
#include <linux/sysctl.h>
|
||||
#endif
|
||||
|
||||
/* We only check the length. A bridge shouldn't do any hop-by-hop stuff
|
||||
* anyway
|
||||
*/
|
||||
static int br_nf_check_hbh_len(struct sk_buff *skb)
|
||||
{
|
||||
unsigned char *raw = (u8 *)(ipv6_hdr(skb) + 1);
|
||||
u32 pkt_len;
|
||||
const unsigned char *nh = skb_network_header(skb);
|
||||
int off = raw - nh;
|
||||
int len = (raw[1] + 1) << 3;
|
||||
|
||||
if ((raw + len) - skb->data > skb_headlen(skb))
|
||||
goto bad;
|
||||
|
||||
off += 2;
|
||||
len -= 2;
|
||||
|
||||
while (len > 0) {
|
||||
int optlen = nh[off + 1] + 2;
|
||||
|
||||
switch (nh[off]) {
|
||||
case IPV6_TLV_PAD1:
|
||||
optlen = 1;
|
||||
break;
|
||||
|
||||
case IPV6_TLV_PADN:
|
||||
break;
|
||||
|
||||
case IPV6_TLV_JUMBO:
|
||||
if (nh[off + 1] != 4 || (off & 3) != 2)
|
||||
goto bad;
|
||||
pkt_len = ntohl(*(__be32 *)(nh + off + 2));
|
||||
if (pkt_len <= IPV6_MAXPLEN ||
|
||||
ipv6_hdr(skb)->payload_len)
|
||||
goto bad;
|
||||
if (pkt_len > skb->len - sizeof(struct ipv6hdr))
|
||||
goto bad;
|
||||
if (pskb_trim_rcsum(skb,
|
||||
pkt_len + sizeof(struct ipv6hdr)))
|
||||
goto bad;
|
||||
nh = skb_network_header(skb);
|
||||
break;
|
||||
default:
|
||||
if (optlen > len)
|
||||
goto bad;
|
||||
break;
|
||||
}
|
||||
off += optlen;
|
||||
len -= optlen;
|
||||
}
|
||||
if (len == 0)
|
||||
return 0;
|
||||
bad:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int br_validate_ipv6(struct net *net, struct sk_buff *skb)
|
||||
{
|
||||
const struct ipv6hdr *hdr;
|
||||
struct inet6_dev *idev = __in6_dev_get(skb->dev);
|
||||
u32 pkt_len;
|
||||
u8 ip6h_len = sizeof(struct ipv6hdr);
|
||||
|
||||
if (!pskb_may_pull(skb, ip6h_len))
|
||||
goto inhdr_error;
|
||||
|
||||
if (skb->len < ip6h_len)
|
||||
goto drop;
|
||||
|
||||
hdr = ipv6_hdr(skb);
|
||||
|
||||
if (hdr->version != 6)
|
||||
goto inhdr_error;
|
||||
|
||||
pkt_len = ntohs(hdr->payload_len);
|
||||
|
||||
if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
|
||||
if (pkt_len + ip6h_len > skb->len) {
|
||||
__IP6_INC_STATS(net, idev,
|
||||
IPSTATS_MIB_INTRUNCATEDPKTS);
|
||||
goto drop;
|
||||
}
|
||||
if (pskb_trim_rcsum(skb, pkt_len + ip6h_len)) {
|
||||
__IP6_INC_STATS(net, idev,
|
||||
IPSTATS_MIB_INDISCARDS);
|
||||
goto drop;
|
||||
}
|
||||
hdr = ipv6_hdr(skb);
|
||||
}
|
||||
if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb))
|
||||
goto drop;
|
||||
|
||||
memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
|
||||
/* No IP options in IPv6 header; however it should be
|
||||
* checked if some next headers need special treatment
|
||||
*/
|
||||
return 0;
|
||||
|
||||
inhdr_error:
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
drop:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
br_nf_ipv6_daddr_was_changed(const struct sk_buff *skb,
|
||||
const struct nf_bridge_info *nf_bridge)
|
||||
{
|
||||
return memcmp(&nf_bridge->ipv6_daddr, &ipv6_hdr(skb)->daddr,
|
||||
sizeof(ipv6_hdr(skb)->daddr)) != 0;
|
||||
}
|
||||
|
||||
/* PF_BRIDGE/PRE_ROUTING: Undo the changes made for ip6tables
|
||||
* PREROUTING and continue the bridge PRE_ROUTING hook. See comment
|
||||
* for br_nf_pre_routing_finish(), same logic is used here but
|
||||
* equivalent IPv6 function ip6_route_input() called indirectly.
|
||||
*/
|
||||
static int br_nf_pre_routing_finish_ipv6(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
|
||||
struct rtable *rt;
|
||||
struct net_device *dev = skb->dev;
|
||||
const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
|
||||
|
||||
nf_bridge->frag_max_size = IP6CB(skb)->frag_max_size;
|
||||
|
||||
if (nf_bridge->pkt_otherhost) {
|
||||
skb->pkt_type = PACKET_OTHERHOST;
|
||||
nf_bridge->pkt_otherhost = false;
|
||||
}
|
||||
nf_bridge->in_prerouting = 0;
|
||||
if (br_nf_ipv6_daddr_was_changed(skb, nf_bridge)) {
|
||||
skb_dst_drop(skb);
|
||||
v6ops->route_input(skb);
|
||||
|
||||
if (skb_dst(skb)->error) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (skb_dst(skb)->dev == dev) {
|
||||
skb->dev = nf_bridge->physindev;
|
||||
nf_bridge_update_protocol(skb);
|
||||
nf_bridge_push_encap_header(skb);
|
||||
br_nf_hook_thresh(NF_BR_PRE_ROUTING,
|
||||
net, sk, skb, skb->dev, NULL,
|
||||
br_nf_pre_routing_finish_bridge);
|
||||
return 0;
|
||||
}
|
||||
ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
} else {
|
||||
rt = bridge_parent_rtable(nf_bridge->physindev);
|
||||
if (!rt) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
skb_dst_set_noref(skb, &rt->dst);
|
||||
}
|
||||
|
||||
skb->dev = nf_bridge->physindev;
|
||||
nf_bridge_update_protocol(skb);
|
||||
nf_bridge_push_encap_header(skb);
|
||||
br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb,
|
||||
skb->dev, NULL, br_handle_frame_finish);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Replicate the checks that IPv6 does on packet reception and pass the packet
|
||||
* to ip6tables.
|
||||
*/
|
||||
unsigned int br_nf_pre_routing_ipv6(void *priv,
|
||||
struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
{
|
||||
struct nf_bridge_info *nf_bridge;
|
||||
|
||||
if (br_validate_ipv6(state->net, skb))
|
||||
return NF_DROP;
|
||||
|
||||
nf_bridge = nf_bridge_alloc(skb);
|
||||
if (!nf_bridge)
|
||||
return NF_DROP;
|
||||
if (!setup_pre_routing(skb, state->net))
|
||||
return NF_DROP;
|
||||
|
||||
nf_bridge = nf_bridge_info_get(skb);
|
||||
nf_bridge->ipv6_daddr = ipv6_hdr(skb)->daddr;
|
||||
|
||||
skb->protocol = htons(ETH_P_IPV6);
|
||||
skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
|
||||
|
||||
NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, state->net, state->sk, skb,
|
||||
skb->dev, NULL,
|
||||
br_nf_pre_routing_finish_ipv6);
|
||||
|
||||
return NF_STOLEN;
|
||||
}
|
||||
1731
2025-03-19/bridge2/br_netlink.c
Normal file
1731
2025-03-19/bridge2/br_netlink.c
Normal file
File diff suppressed because it is too large
Load diff
294
2025-03-19/bridge2/br_netlink_tunnel.c
Normal file
294
2025-03-19/bridge2/br_netlink_tunnel.c
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Bridge per vlan tunnel port dst_metadata netlink control interface
|
||||
*
|
||||
* Authors:
|
||||
* Roopa Prabhu <roopa@cumulusnetworks.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/sock.h>
|
||||
#include <uapi/linux/if_bridge.h>
|
||||
#include <net/dst_metadata.h>
|
||||
|
||||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
|
||||
static size_t __get_vlan_tinfo_size(void)
|
||||
{
|
||||
return nla_total_size(0) + /* nest IFLA_BRIDGE_VLAN_TUNNEL_INFO */
|
||||
nla_total_size(sizeof(u32)) + /* IFLA_BRIDGE_VLAN_TUNNEL_ID */
|
||||
nla_total_size(sizeof(u16)) + /* IFLA_BRIDGE_VLAN_TUNNEL_VID */
|
||||
nla_total_size(sizeof(u16)); /* IFLA_BRIDGE_VLAN_TUNNEL_FLAGS */
|
||||
}
|
||||
|
||||
static bool vlan_tunid_inrange(struct net_bridge_vlan *v_curr,
|
||||
struct net_bridge_vlan *v_last)
|
||||
{
|
||||
__be32 tunid_curr = tunnel_id_to_key32(v_curr->tinfo.tunnel_id);
|
||||
__be32 tunid_last = tunnel_id_to_key32(v_last->tinfo.tunnel_id);
|
||||
|
||||
return (be32_to_cpu(tunid_curr) - be32_to_cpu(tunid_last)) == 1;
|
||||
}
|
||||
|
||||
static int __get_num_vlan_tunnel_infos(struct net_bridge_vlan_group *vg)
|
||||
{
|
||||
struct net_bridge_vlan *v, *vtbegin = NULL, *vtend = NULL;
|
||||
int num_tinfos = 0;
|
||||
|
||||
/* Count number of vlan infos */
|
||||
list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
|
||||
/* only a context, bridge vlan not activated */
|
||||
if (!br_vlan_should_use(v) || !v->tinfo.tunnel_id)
|
||||
continue;
|
||||
|
||||
if (!vtbegin) {
|
||||
goto initvars;
|
||||
} else if ((v->vid - vtend->vid) == 1 &&
|
||||
vlan_tunid_inrange(v, vtend)) {
|
||||
vtend = v;
|
||||
continue;
|
||||
} else {
|
||||
if ((vtend->vid - vtbegin->vid) > 0)
|
||||
num_tinfos += 2;
|
||||
else
|
||||
num_tinfos += 1;
|
||||
}
|
||||
initvars:
|
||||
vtbegin = v;
|
||||
vtend = v;
|
||||
}
|
||||
|
||||
if (vtbegin && vtend) {
|
||||
if ((vtend->vid - vtbegin->vid) > 0)
|
||||
num_tinfos += 2;
|
||||
else
|
||||
num_tinfos += 1;
|
||||
}
|
||||
|
||||
return num_tinfos;
|
||||
}
|
||||
|
||||
int br_get_vlan_tunnel_info_size(struct net_bridge_vlan_group *vg)
|
||||
{
|
||||
int num_tinfos;
|
||||
|
||||
if (!vg)
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
num_tinfos = __get_num_vlan_tunnel_infos(vg);
|
||||
rcu_read_unlock();
|
||||
|
||||
return num_tinfos * __get_vlan_tinfo_size();
|
||||
}
|
||||
|
||||
static int br_fill_vlan_tinfo(struct sk_buff *skb, u16 vid,
|
||||
__be64 tunnel_id, u16 flags)
|
||||
{
|
||||
__be32 tid = tunnel_id_to_key32(tunnel_id);
|
||||
struct nlattr *tmap;
|
||||
|
||||
tmap = nla_nest_start_noflag(skb, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
|
||||
if (!tmap)
|
||||
return -EMSGSIZE;
|
||||
if (nla_put_u32(skb, IFLA_BRIDGE_VLAN_TUNNEL_ID,
|
||||
be32_to_cpu(tid)))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_VID,
|
||||
vid))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_u16(skb, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS,
|
||||
flags))
|
||||
goto nla_put_failure;
|
||||
nla_nest_end(skb, tmap);
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, tmap);
|
||||
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int br_fill_vlan_tinfo_range(struct sk_buff *skb,
|
||||
struct net_bridge_vlan *vtbegin,
|
||||
struct net_bridge_vlan *vtend)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (vtend && (vtend->vid - vtbegin->vid) > 0) {
|
||||
/* add range to skb */
|
||||
err = br_fill_vlan_tinfo(skb, vtbegin->vid,
|
||||
vtbegin->tinfo.tunnel_id,
|
||||
BRIDGE_VLAN_INFO_RANGE_BEGIN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = br_fill_vlan_tinfo(skb, vtend->vid,
|
||||
vtend->tinfo.tunnel_id,
|
||||
BRIDGE_VLAN_INFO_RANGE_END);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
err = br_fill_vlan_tinfo(skb, vtbegin->vid,
|
||||
vtbegin->tinfo.tunnel_id,
|
||||
0);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int br_fill_vlan_tunnel_info(struct sk_buff *skb,
|
||||
struct net_bridge_vlan_group *vg)
|
||||
{
|
||||
struct net_bridge_vlan *vtbegin = NULL;
|
||||
struct net_bridge_vlan *vtend = NULL;
|
||||
struct net_bridge_vlan *v;
|
||||
int err;
|
||||
|
||||
/* Count number of vlan infos */
|
||||
list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
|
||||
/* only a context, bridge vlan not activated */
|
||||
if (!br_vlan_should_use(v))
|
||||
continue;
|
||||
|
||||
if (!v->tinfo.tunnel_dst)
|
||||
continue;
|
||||
|
||||
if (!vtbegin) {
|
||||
goto initvars;
|
||||
} else if ((v->vid - vtend->vid) == 1 &&
|
||||
vlan_tunid_inrange(v, vtend)) {
|
||||
vtend = v;
|
||||
continue;
|
||||
} else {
|
||||
err = br_fill_vlan_tinfo_range(skb, vtbegin, vtend);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
initvars:
|
||||
vtbegin = v;
|
||||
vtend = v;
|
||||
}
|
||||
|
||||
if (vtbegin) {
|
||||
err = br_fill_vlan_tinfo_range(skb, vtbegin, vtend);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nla_policy vlan_tunnel_policy[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1] = {
|
||||
[IFLA_BRIDGE_VLAN_TUNNEL_ID] = { .type = NLA_U32 },
|
||||
[IFLA_BRIDGE_VLAN_TUNNEL_VID] = { .type = NLA_U16 },
|
||||
[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS] = { .type = NLA_U16 },
|
||||
};
|
||||
|
||||
static int br_vlan_tunnel_info(struct net_bridge_port *p, int cmd,
|
||||
u16 vid, u32 tun_id, bool *changed)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case RTM_SETLINK:
|
||||
err = nbp_vlan_tunnel_info_add(p, vid, tun_id);
|
||||
if (!err)
|
||||
*changed = true;
|
||||
break;
|
||||
case RTM_DELLINK:
|
||||
if (!nbp_vlan_tunnel_info_delete(p, vid))
|
||||
*changed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int br_parse_vlan_tunnel_info(struct nlattr *attr,
|
||||
struct vtunnel_info *tinfo)
|
||||
{
|
||||
struct nlattr *tb[IFLA_BRIDGE_VLAN_TUNNEL_MAX + 1];
|
||||
u32 tun_id;
|
||||
u16 vid, flags = 0;
|
||||
int err;
|
||||
|
||||
memset(tinfo, 0, sizeof(*tinfo));
|
||||
|
||||
err = nla_parse_nested_deprecated(tb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
|
||||
attr, vlan_tunnel_policy, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (!tb[IFLA_BRIDGE_VLAN_TUNNEL_ID] ||
|
||||
!tb[IFLA_BRIDGE_VLAN_TUNNEL_VID])
|
||||
return -EINVAL;
|
||||
|
||||
tun_id = nla_get_u32(tb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
|
||||
vid = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_VID]);
|
||||
if (vid >= VLAN_VID_MASK)
|
||||
return -ERANGE;
|
||||
|
||||
if (tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS])
|
||||
flags = nla_get_u16(tb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]);
|
||||
|
||||
tinfo->tunid = tun_id;
|
||||
tinfo->vid = vid;
|
||||
tinfo->flags = flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int br_process_vlan_tunnel_info(struct net_bridge *br,
|
||||
struct net_bridge_port *p, int cmd,
|
||||
struct vtunnel_info *tinfo_curr,
|
||||
struct vtunnel_info *tinfo_last,
|
||||
bool *changed)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
|
||||
if (tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
|
||||
return -EINVAL;
|
||||
memcpy(tinfo_last, tinfo_curr, sizeof(struct vtunnel_info));
|
||||
} else if (tinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_END) {
|
||||
int t, v;
|
||||
|
||||
if (!(tinfo_last->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN))
|
||||
return -EINVAL;
|
||||
if ((tinfo_curr->vid - tinfo_last->vid) !=
|
||||
(tinfo_curr->tunid - tinfo_last->tunid))
|
||||
return -EINVAL;
|
||||
t = tinfo_last->tunid;
|
||||
for (v = tinfo_last->vid; v <= tinfo_curr->vid; v++) {
|
||||
err = br_vlan_tunnel_info(p, cmd, v, t, changed);
|
||||
if (err)
|
||||
return err;
|
||||
t++;
|
||||
}
|
||||
memset(tinfo_last, 0, sizeof(struct vtunnel_info));
|
||||
memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
|
||||
} else {
|
||||
if (tinfo_last->flags)
|
||||
return -EINVAL;
|
||||
err = br_vlan_tunnel_info(p, cmd, tinfo_curr->vid,
|
||||
tinfo_curr->tunid, changed);
|
||||
if (err)
|
||||
return err;
|
||||
memset(tinfo_last, 0, sizeof(struct vtunnel_info));
|
||||
memset(tinfo_curr, 0, sizeof(struct vtunnel_info));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
91
2025-03-19/bridge2/br_nf_core.c
Normal file
91
2025-03-19/bridge2/br_nf_core.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Handle firewalling core
|
||||
* Linux ethernet bridge
|
||||
*
|
||||
* Authors:
|
||||
* Lennert Buytenhek <buytenh@gnu.org>
|
||||
* Bart De Schuymer <bdschuym@pandora.be>
|
||||
*
|
||||
* Lennert dedicates this file to Kerstin Wurdinger.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/in_route.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include "br_private.h"
|
||||
#ifdef CONFIG_SYSCTL
|
||||
#include <linux/sysctl.h>
|
||||
#endif
|
||||
|
||||
static void fake_update_pmtu(struct dst_entry *dst, struct sock *sk,
|
||||
struct sk_buff *skb, u32 mtu,
|
||||
bool confirm_neigh)
|
||||
{
|
||||
}
|
||||
|
||||
static void fake_redirect(struct dst_entry *dst, struct sock *sk,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
}
|
||||
|
||||
static u32 *fake_cow_metrics(struct dst_entry *dst, unsigned long old)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct neighbour *fake_neigh_lookup(const struct dst_entry *dst,
|
||||
struct sk_buff *skb,
|
||||
const void *daddr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int fake_mtu(const struct dst_entry *dst)
|
||||
{
|
||||
return dst->dev->mtu;
|
||||
}
|
||||
|
||||
static struct dst_ops fake_dst_ops = {
|
||||
.family = AF_INET,
|
||||
.update_pmtu = fake_update_pmtu,
|
||||
.redirect = fake_redirect,
|
||||
.cow_metrics = fake_cow_metrics,
|
||||
.neigh_lookup = fake_neigh_lookup,
|
||||
.mtu = fake_mtu,
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize bogus route table used to keep netfilter happy.
|
||||
* Currently, we fill in the PMTU entry because netfilter
|
||||
* refragmentation needs it, and the rt_flags entry because
|
||||
* ipt_REJECT needs it. Future netfilter modules might
|
||||
* require us to fill additional fields.
|
||||
*/
|
||||
static const u32 br_dst_default_metrics[RTAX_MAX] = {
|
||||
[RTAX_MTU - 1] = 1500,
|
||||
};
|
||||
|
||||
void br_netfilter_rtable_init(struct net_bridge *br)
|
||||
{
|
||||
struct rtable *rt = &br->fake_rtable;
|
||||
|
||||
atomic_set(&rt->dst.__refcnt, 1);
|
||||
rt->dst.dev = br->dev;
|
||||
dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
|
||||
rt->dst.flags = DST_NOXFRM | DST_FAKE_RTABLE;
|
||||
rt->dst.ops = &fake_dst_ops;
|
||||
}
|
||||
|
||||
int __init br_nf_core_init(void)
|
||||
{
|
||||
return dst_entries_init(&fake_dst_ops);
|
||||
}
|
||||
|
||||
void br_nf_core_fini(void)
|
||||
{
|
||||
dst_entries_destroy(&fake_dst_ops);
|
||||
}
|
||||
1076
2025-03-19/bridge2/br_private.h
Normal file
1076
2025-03-19/bridge2/br_private.h
Normal file
File diff suppressed because it is too large
Load diff
47
2025-03-19/bridge2/br_private_tunnel.h
Normal file
47
2025-03-19/bridge2/br_private_tunnel.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Bridge per vlan tunnels
|
||||
*
|
||||
* Authors:
|
||||
* Roopa Prabhu <roopa@cumulusnetworks.com>
|
||||
*/
|
||||
|
||||
#ifndef _BR_PRIVATE_TUNNEL_H
|
||||
#define _BR_PRIVATE_TUNNEL_H
|
||||
|
||||
struct vtunnel_info {
|
||||
u32 tunid;
|
||||
u16 vid;
|
||||
u16 flags;
|
||||
};
|
||||
|
||||
/* br_netlink_tunnel.c */
|
||||
int br_parse_vlan_tunnel_info(struct nlattr *attr,
|
||||
struct vtunnel_info *tinfo);
|
||||
int br_process_vlan_tunnel_info(struct net_bridge *br,
|
||||
struct net_bridge_port *p,
|
||||
int cmd,
|
||||
struct vtunnel_info *tinfo_curr,
|
||||
struct vtunnel_info *tinfo_last,
|
||||
bool *changed);
|
||||
int br_get_vlan_tunnel_info_size(struct net_bridge_vlan_group *vg);
|
||||
int br_fill_vlan_tunnel_info(struct sk_buff *skb,
|
||||
struct net_bridge_vlan_group *vg);
|
||||
|
||||
#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
/* br_vlan_tunnel.c */
|
||||
int vlan_tunnel_init(struct net_bridge_vlan_group *vg);
|
||||
void vlan_tunnel_deinit(struct net_bridge_vlan_group *vg);
|
||||
int nbp_vlan_tunnel_info_delete(struct net_bridge_port *port, u16 vid);
|
||||
int nbp_vlan_tunnel_info_add(struct net_bridge_port *port, u16 vid, u32 tun_id);
|
||||
void nbp_vlan_tunnel_info_flush(struct net_bridge_port *port);
|
||||
void vlan_tunnel_info_del(struct net_bridge_vlan_group *vg,
|
||||
struct net_bridge_vlan *vlan);
|
||||
int br_handle_ingress_vlan_tunnel(struct sk_buff *skb,
|
||||
struct net_bridge_port *p,
|
||||
struct net_bridge_vlan_group *vg);
|
||||
int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
|
||||
struct net_bridge_vlan *vlan);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
172
2025-03-19/bridge2/br_switchdev.c
Normal file
172
2025-03-19/bridge2/br_switchdev.c
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "br_private.h"
|
||||
|
||||
static int br_switchdev_mark_get(struct net_bridge *br, struct net_device *dev)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
|
||||
/* dev is yet to be added to the port list. */
|
||||
list_for_each_entry(p, &br->port_list, list) {
|
||||
if (netdev_port_same_parent_id(dev, p->dev))
|
||||
return p->offload_fwd_mark;
|
||||
}
|
||||
|
||||
return ++br->offload_fwd_mark;
|
||||
}
|
||||
|
||||
int nbp_switchdev_mark_set(struct net_bridge_port *p)
|
||||
{
|
||||
struct netdev_phys_item_id ppid = { };
|
||||
int err;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
err = dev_get_port_parent_id(p->dev, &ppid, true);
|
||||
if (err) {
|
||||
if (err == -EOPNOTSUPP)
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
p->offload_fwd_mark = br_switchdev_mark_get(p->br, p->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nbp_switchdev_frame_mark(const struct net_bridge_port *p,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
if (skb->offload_fwd_mark && !WARN_ON_ONCE(!p->offload_fwd_mark))
|
||||
BR_INPUT_SKB_CB(skb)->offload_fwd_mark = p->offload_fwd_mark;
|
||||
}
|
||||
|
||||
bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
return !skb->offload_fwd_mark ||
|
||||
BR_INPUT_SKB_CB(skb)->offload_fwd_mark != p->offload_fwd_mark;
|
||||
}
|
||||
|
||||
/* Flags that can be offloaded to hardware */
|
||||
#define BR_PORT_FLAGS_HW_OFFLOAD (BR_LEARNING | BR_FLOOD | \
|
||||
BR_MCAST_FLOOD | BR_BCAST_FLOOD)
|
||||
|
||||
int br_switchdev_set_port_flag(struct net_bridge_port *p,
|
||||
unsigned long flags,
|
||||
unsigned long mask)
|
||||
{
|
||||
struct switchdev_attr attr = {
|
||||
.orig_dev = p->dev,
|
||||
.id = SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS,
|
||||
.u.brport_flags = mask,
|
||||
};
|
||||
struct switchdev_notifier_port_attr_info info = {
|
||||
.attr = &attr,
|
||||
};
|
||||
int err;
|
||||
|
||||
if (mask & ~BR_PORT_FLAGS_HW_OFFLOAD)
|
||||
return 0;
|
||||
|
||||
/* We run from atomic context here */
|
||||
err = call_switchdev_notifiers(SWITCHDEV_PORT_ATTR_SET, p->dev,
|
||||
&info.info, NULL);
|
||||
err = notifier_to_errno(err);
|
||||
if (err == -EOPNOTSUPP)
|
||||
return 0;
|
||||
|
||||
if (err) {
|
||||
br_warn(p->br, "bridge flag offload is not supported %u(%s)\n",
|
||||
(unsigned int)p->port_no, p->dev->name);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
attr.id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS;
|
||||
attr.flags = SWITCHDEV_F_DEFER;
|
||||
attr.u.brport_flags = flags;
|
||||
|
||||
err = switchdev_port_attr_set(p->dev, &attr);
|
||||
if (err) {
|
||||
br_warn(p->br, "error setting offload flag on port %u(%s)\n",
|
||||
(unsigned int)p->port_no, p->dev->name);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac,
|
||||
u16 vid, struct net_device *dev,
|
||||
bool added_by_user, bool offloaded)
|
||||
{
|
||||
struct switchdev_notifier_fdb_info info;
|
||||
unsigned long notifier_type;
|
||||
info.addr = mac;
|
||||
info.vid = vid;
|
||||
info.added_by_user = added_by_user;
|
||||
info.offloaded = offloaded;
|
||||
notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_DEVICE : SWITCHDEV_FDB_DEL_TO_DEVICE;
|
||||
call_switchdev_notifiers(notifier_type, dev, &info.info, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
|
||||
{
|
||||
if (!fdb->dst)
|
||||
return;
|
||||
|
||||
switch (type) {
|
||||
case RTM_DELNEIGH:
|
||||
br_switchdev_fdb_call_notifiers(false, fdb->key.addr.addr,
|
||||
fdb->key.vlan_id,
|
||||
fdb->dst->dev,
|
||||
test_bit(BR_FDB_ADDED_BY_USER,
|
||||
&fdb->flags),
|
||||
test_bit(BR_FDB_OFFLOADED,
|
||||
&fdb->flags));
|
||||
break;
|
||||
case RTM_NEWNEIGH:
|
||||
br_switchdev_fdb_call_notifiers(true, fdb->key.addr.addr,
|
||||
fdb->key.vlan_id,
|
||||
fdb->dst->dev,
|
||||
test_bit(BR_FDB_ADDED_BY_USER,
|
||||
&fdb->flags),
|
||||
test_bit(BR_FDB_OFFLOADED,
|
||||
&fdb->flags));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct switchdev_obj_port_vlan v = {
|
||||
.obj.orig_dev = dev,
|
||||
.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
|
||||
.flags = flags,
|
||||
.vid_begin = vid,
|
||||
.vid_end = vid,
|
||||
};
|
||||
|
||||
return switchdev_port_obj_add(dev, &v.obj, extack);
|
||||
}
|
||||
|
||||
int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid)
|
||||
{
|
||||
struct switchdev_obj_port_vlan v = {
|
||||
.obj.orig_dev = dev,
|
||||
.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
|
||||
.vid_begin = vid,
|
||||
.vid_end = vid,
|
||||
};
|
||||
|
||||
return switchdev_port_obj_del(dev, &v.obj);
|
||||
}
|
||||
2045
2025-03-19/bridge2/br_vlan.c
Normal file
2045
2025-03-19/bridge2/br_vlan.c
Normal file
File diff suppressed because it is too large
Load diff
160
2025-03-19/bridge2/br_vlan_options.c
Normal file
160
2025-03-19/bridge2/br_vlan_options.c
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2020, Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "br_private.h"
|
||||
|
||||
/* check if the options between two vlans are equal */
|
||||
bool br_vlan_opts_eq(const struct net_bridge_vlan *v1,
|
||||
const struct net_bridge_vlan *v2)
|
||||
{
|
||||
return v1->state == v2->state;
|
||||
}
|
||||
|
||||
bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v)
|
||||
{
|
||||
return !nla_put_u8(skb, BRIDGE_VLANDB_ENTRY_STATE,
|
||||
br_vlan_get_state(v));
|
||||
}
|
||||
|
||||
size_t br_vlan_opts_nl_size(void)
|
||||
{
|
||||
return nla_total_size(sizeof(u8)); /* BRIDGE_VLANDB_ENTRY_STATE */
|
||||
}
|
||||
|
||||
static int br_vlan_modify_state(struct net_bridge_vlan_group *vg,
|
||||
struct net_bridge_vlan *v,
|
||||
u8 state,
|
||||
bool *changed,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net_bridge *br;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (state > BR_STATE_BLOCKING) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Invalid vlan state");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (br_vlan_is_brentry(v))
|
||||
br = v->br;
|
||||
else
|
||||
br = v->port->br;
|
||||
|
||||
// if (br->stp_enabled == BR_KERNEL_STP) {
|
||||
// NL_SET_ERR_MSG_MOD(extack, "Can't modify vlan state when using kernel STP");
|
||||
// return -EBUSY;
|
||||
// }
|
||||
|
||||
if (v->state == state)
|
||||
return 0;
|
||||
|
||||
if (v->vid == br_get_pvid(vg))
|
||||
br_vlan_set_pvid_state(vg, state);
|
||||
|
||||
br_vlan_set_state(v, state);
|
||||
*changed = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int br_vlan_process_one_opts(const struct net_bridge *br,
|
||||
const struct net_bridge_port *p,
|
||||
struct net_bridge_vlan_group *vg,
|
||||
struct net_bridge_vlan *v,
|
||||
struct nlattr **tb,
|
||||
bool *changed,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int err;
|
||||
|
||||
*changed = false;
|
||||
if (tb[BRIDGE_VLANDB_ENTRY_STATE]) {
|
||||
u8 state = nla_get_u8(tb[BRIDGE_VLANDB_ENTRY_STATE]);
|
||||
|
||||
err = br_vlan_modify_state(vg, v, state, changed, extack);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int br_vlan_process_options(const struct net_bridge *br,
|
||||
const struct net_bridge_port *p,
|
||||
struct net_bridge_vlan *range_start,
|
||||
struct net_bridge_vlan *range_end,
|
||||
struct nlattr **tb,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct net_bridge_vlan *v, *curr_start = NULL, *curr_end = NULL;
|
||||
struct net_bridge_vlan_group *vg;
|
||||
int vid, err = 0;
|
||||
u16 pvid;
|
||||
|
||||
if (p)
|
||||
vg = nbp_vlan_group(p);
|
||||
else
|
||||
vg = br_vlan_group(br);
|
||||
|
||||
if (!range_start || !br_vlan_should_use(range_start)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Vlan range start doesn't exist, can't process options");
|
||||
return -ENOENT;
|
||||
}
|
||||
if (!range_end || !br_vlan_should_use(range_end)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Vlan range end doesn't exist, can't process options");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
pvid = br_get_pvid(vg);
|
||||
for (vid = range_start->vid; vid <= range_end->vid; vid++) {
|
||||
bool changed = false;
|
||||
|
||||
v = br_vlan_find(vg, vid);
|
||||
if (!v || !br_vlan_should_use(v)) {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Vlan in range doesn't exist, can't process options");
|
||||
err = -ENOENT;
|
||||
break;
|
||||
}
|
||||
|
||||
err = br_vlan_process_one_opts(br, p, vg, v, tb, &changed,
|
||||
extack);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
if (changed) {
|
||||
/* vlan options changed, check for range */
|
||||
if (!curr_start) {
|
||||
curr_start = v;
|
||||
curr_end = v;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (v->vid == pvid ||
|
||||
!br_vlan_can_enter_range(v, curr_end)) {
|
||||
br_vlan_notify(br, p, curr_start->vid,
|
||||
curr_end->vid, RTM_NEWVLAN);
|
||||
curr_start = v;
|
||||
}
|
||||
curr_end = v;
|
||||
} else {
|
||||
/* nothing changed and nothing to notify yet */
|
||||
if (!curr_start)
|
||||
continue;
|
||||
|
||||
br_vlan_notify(br, p, curr_start->vid, curr_end->vid,
|
||||
RTM_NEWVLAN);
|
||||
curr_start = NULL;
|
||||
curr_end = NULL;
|
||||
}
|
||||
}
|
||||
if (curr_start)
|
||||
br_vlan_notify(br, p, curr_start->vid, curr_end->vid,
|
||||
RTM_NEWVLAN);
|
||||
|
||||
return err;
|
||||
}
|
||||
200
2025-03-19/bridge2/br_vlan_tunnel.c
Normal file
200
2025-03-19/bridge2/br_vlan_tunnel.c
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Bridge per vlan tunnel port dst_metadata handling code
|
||||
*
|
||||
* Authors:
|
||||
* Roopa Prabhu <roopa@cumulusnetworks.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/switchdev.h>
|
||||
#include <net/dst_metadata.h>
|
||||
|
||||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
|
||||
static inline int br_vlan_tunid_cmp(struct rhashtable_compare_arg *arg,
|
||||
const void *ptr)
|
||||
{
|
||||
const struct net_bridge_vlan *vle = ptr;
|
||||
__be64 tunid = *(__be64 *)arg->key;
|
||||
|
||||
return vle->tinfo.tunnel_id != tunid;
|
||||
}
|
||||
|
||||
static const struct rhashtable_params br_vlan_tunnel_rht_params = {
|
||||
.head_offset = offsetof(struct net_bridge_vlan, tnode),
|
||||
.key_offset = offsetof(struct net_bridge_vlan, tinfo.tunnel_id),
|
||||
.key_len = sizeof(__be64),
|
||||
.nelem_hint = 3,
|
||||
.obj_cmpfn = br_vlan_tunid_cmp,
|
||||
.automatic_shrinking = true,
|
||||
};
|
||||
|
||||
static struct net_bridge_vlan *br_vlan_tunnel_lookup(struct rhashtable *tbl,
|
||||
u64 tunnel_id)
|
||||
{
|
||||
return rhashtable_lookup_fast(tbl, &tunnel_id,
|
||||
br_vlan_tunnel_rht_params);
|
||||
}
|
||||
|
||||
void vlan_tunnel_info_del(struct net_bridge_vlan_group *vg,
|
||||
struct net_bridge_vlan *vlan)
|
||||
{
|
||||
if (!vlan->tinfo.tunnel_dst)
|
||||
return;
|
||||
rhashtable_remove_fast(&vg->tunnel_hash, &vlan->tnode,
|
||||
br_vlan_tunnel_rht_params);
|
||||
vlan->tinfo.tunnel_id = 0;
|
||||
dst_release(&vlan->tinfo.tunnel_dst->dst);
|
||||
vlan->tinfo.tunnel_dst = NULL;
|
||||
}
|
||||
|
||||
static int __vlan_tunnel_info_add(struct net_bridge_vlan_group *vg,
|
||||
struct net_bridge_vlan *vlan, u32 tun_id)
|
||||
{
|
||||
struct metadata_dst *metadata = NULL;
|
||||
__be64 key = key32_to_tunnel_id(cpu_to_be32(tun_id));
|
||||
int err;
|
||||
|
||||
if (vlan->tinfo.tunnel_dst)
|
||||
return -EEXIST;
|
||||
|
||||
metadata = __ip_tun_set_dst(0, 0, 0, 0, 0, TUNNEL_KEY,
|
||||
key, 0);
|
||||
if (!metadata)
|
||||
return -EINVAL;
|
||||
|
||||
metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_BRIDGE;
|
||||
vlan->tinfo.tunnel_dst = metadata;
|
||||
vlan->tinfo.tunnel_id = key;
|
||||
|
||||
err = rhashtable_lookup_insert_fast(&vg->tunnel_hash, &vlan->tnode,
|
||||
br_vlan_tunnel_rht_params);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
dst_release(&vlan->tinfo.tunnel_dst->dst);
|
||||
vlan->tinfo.tunnel_dst = NULL;
|
||||
vlan->tinfo.tunnel_id = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Must be protected by RTNL.
|
||||
* Must be called with vid in range from 1 to 4094 inclusive.
|
||||
*/
|
||||
int nbp_vlan_tunnel_info_add(struct net_bridge_port *port, u16 vid, u32 tun_id)
|
||||
{
|
||||
struct net_bridge_vlan_group *vg;
|
||||
struct net_bridge_vlan *vlan;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
vg = nbp_vlan_group(port);
|
||||
vlan = br_vlan_find(vg, vid);
|
||||
if (!vlan)
|
||||
return -EINVAL;
|
||||
|
||||
return __vlan_tunnel_info_add(vg, vlan, tun_id);
|
||||
}
|
||||
|
||||
/* Must be protected by RTNL.
|
||||
* Must be called with vid in range from 1 to 4094 inclusive.
|
||||
*/
|
||||
int nbp_vlan_tunnel_info_delete(struct net_bridge_port *port, u16 vid)
|
||||
{
|
||||
struct net_bridge_vlan_group *vg;
|
||||
struct net_bridge_vlan *v;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
vg = nbp_vlan_group(port);
|
||||
v = br_vlan_find(vg, vid);
|
||||
if (!v)
|
||||
return -ENOENT;
|
||||
|
||||
vlan_tunnel_info_del(vg, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __vlan_tunnel_info_flush(struct net_bridge_vlan_group *vg)
|
||||
{
|
||||
struct net_bridge_vlan *vlan, *tmp;
|
||||
|
||||
list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist)
|
||||
vlan_tunnel_info_del(vg, vlan);
|
||||
}
|
||||
|
||||
void nbp_vlan_tunnel_info_flush(struct net_bridge_port *port)
|
||||
{
|
||||
struct net_bridge_vlan_group *vg;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
vg = nbp_vlan_group(port);
|
||||
__vlan_tunnel_info_flush(vg);
|
||||
}
|
||||
|
||||
int vlan_tunnel_init(struct net_bridge_vlan_group *vg)
|
||||
{
|
||||
return rhashtable_init(&vg->tunnel_hash, &br_vlan_tunnel_rht_params);
|
||||
}
|
||||
|
||||
void vlan_tunnel_deinit(struct net_bridge_vlan_group *vg)
|
||||
{
|
||||
rhashtable_destroy(&vg->tunnel_hash);
|
||||
}
|
||||
|
||||
int br_handle_ingress_vlan_tunnel(struct sk_buff *skb,
|
||||
struct net_bridge_port *p,
|
||||
struct net_bridge_vlan_group *vg)
|
||||
{
|
||||
struct ip_tunnel_info *tinfo = skb_tunnel_info(skb);
|
||||
struct net_bridge_vlan *vlan;
|
||||
|
||||
if (!vg || !tinfo)
|
||||
return 0;
|
||||
|
||||
/* if already tagged, ignore */
|
||||
if (skb_vlan_tagged(skb))
|
||||
return 0;
|
||||
|
||||
/* lookup vid, given tunnel id */
|
||||
vlan = br_vlan_tunnel_lookup(&vg->tunnel_hash, tinfo->key.tun_id);
|
||||
if (!vlan)
|
||||
return 0;
|
||||
|
||||
skb_dst_drop(skb);
|
||||
|
||||
__vlan_hwaccel_put_tag(skb, p->br->vlan_proto, vlan->vid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
|
||||
struct net_bridge_vlan *vlan)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!vlan || !vlan->tinfo.tunnel_id)
|
||||
return 0;
|
||||
|
||||
if (unlikely(!skb_vlan_tag_present(skb)))
|
||||
return 0;
|
||||
|
||||
skb_dst_drop(skb);
|
||||
err = skb_vlan_pop(skb);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
skb_dst_set(skb, dst_clone(&vlan->tinfo.tunnel_dst->dst));
|
||||
|
||||
return 0;
|
||||
}
|
||||
144
2025-03-19/bridge2/ctl.h
Normal file
144
2025-03-19/bridge2/ctl.h
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
#ifndef ADDITIONAL_BRCTL_H
|
||||
#define ADDITIONAL_BRCTL_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#define BIT(x) (1 << (x))
|
||||
#endif
|
||||
|
||||
//#define BR_HAIRPIN_MODE BIT(0)
|
||||
//#define BR_BPDU_GUARD BIT(1)
|
||||
//#define BR_ROOT_BLOCK BIT(2)
|
||||
#define BR_MULTICAST_FAST_LEAVE BIT(3)
|
||||
//#define BR_ADMIN_COST BIT(4)
|
||||
#define BR_LEARNING BIT(5)
|
||||
#define BR_FLOOD BIT(6)
|
||||
#define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING)
|
||||
//#define BR_PROMISC BIT(7)
|
||||
//#define BR_PROXYARP BIT(8)
|
||||
//#define BR_LEARNING_SYNC BIT(9)
|
||||
//#define BR_PROXYARP_WIFI BIT(10)
|
||||
#define BR_MCAST_FLOOD BIT(11)
|
||||
//#define BR_MULTICAST_TO_UNICAST BIT(12)
|
||||
//#define BR_VLAN_TUNNEL BIT(13)
|
||||
#define BR_BCAST_FLOOD BIT(14)
|
||||
#define BR_MLAG_PEER_LINK BIT(29)
|
||||
#define BR_MLAG_DUAL_LINK BIT(30)
|
||||
#define BR_TRUSTED_PORT BIT(31)
|
||||
|
||||
#define BR_DEFAULT (BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD)
|
||||
|
||||
#define BR_NOHORIZON 0
|
||||
#define BR_NOSWITCH -1u
|
||||
|
||||
#define BRFDB_LOCAL 0
|
||||
#define BRFDB_STATIC 10
|
||||
#define BRFDB_LEARNED 20
|
||||
#define BRFDB_ALL 0xffff
|
||||
|
||||
#define BR_IN_FRAME_TYPES_OFF 0
|
||||
#define BR_IN_FRAME_TYPES 0x3
|
||||
#define BR_PORT_FRAME_ADMIT_ALL 0
|
||||
#define BR_PORT_FRAME_ADMIT_TAGGED 1
|
||||
#define BR_PORT_FRAME_ADMIT_UNTAGGED 2
|
||||
#define BR_IN_FILTERING_OFF 2
|
||||
#define BR_IN_FILTERING BIT(BR_IN_FILTERING_OFF)
|
||||
#define BR_IN_TAG_STACKING_OFF 3
|
||||
#define BR_IN_TAG_STACKING BIT(BR_IN_TAG_STACKING_OFF)
|
||||
|
||||
#define ABRCTL_FDB_INSERT 100
|
||||
#define ABRCTL_FDB_DELETE 101
|
||||
#define ABRCTL_SET_STP_STATE 102 // port in arg0, mstid in arg1, state in arg2
|
||||
#define ABRCTL_SET_PORTHORIZON 103 // port in arg0, horizon in arg1
|
||||
#define ABRCTL_SET_SWITCH_GROUP 104 // port in arg0, switch_group in arg1
|
||||
#define ABRCTL_GET_MDB 105
|
||||
#define ABRCTL_GET_MC_ROUTER 106
|
||||
#define ABRCTL_FDB_FLUSH 107 // port in arg0, vid in arg1, dynamic/static in arg1
|
||||
#define ABRCTL_ADD_VLAN 108 // port in arg1, vid in arg2, flags in arg3
|
||||
#define ABRCTL_DEL_VLAN 109 // port in arg1, vid in arg2
|
||||
#define ABRCTL_SET_INSTANCE 110 // abrctl_vlan_range
|
||||
#define ABRCTL_DEL_INSTANCE 111 // mstid in arg1
|
||||
#define ABRCTL_SET_VLAN_OPTS 112 // port in arg1, frameType in arg2, ingFilter in arg3
|
||||
#define ABRCTL_SET_PORT_OPTS 113 // port in arg1, flags in arg2
|
||||
#define ABRCTL_SET_INFO_OPT 114 // port in arg1, bridge_info_opt in arg2
|
||||
#define ABRCTL_SET_MC_ROUTER 115
|
||||
#define ABRCTL_SET_MC_OPTS 116
|
||||
#define ABRCTL_GET_FAST_FORWARD 117
|
||||
#define ABRCTL_GET_MC_QUERIER 118
|
||||
|
||||
struct abrctl_fdb_insert {
|
||||
unsigned char addr[6];
|
||||
unsigned type;
|
||||
unsigned portidx;
|
||||
};
|
||||
|
||||
struct abrctl_fdb_entry {
|
||||
__u8 mac_addr[6];
|
||||
__u8 port_no;
|
||||
__u8 is_local;
|
||||
__u32 ageing_timer_value;
|
||||
__u8 port_hi;
|
||||
__u8 is_static;
|
||||
__u16 vlan_id;
|
||||
};
|
||||
|
||||
// include/uapi/linux/if_bridge.h
|
||||
struct abrctl_mdb_entry {
|
||||
__u32 ifindex;
|
||||
#define MDB_TEMPORARY 0
|
||||
#define MDB_PERMANENT 1
|
||||
//__u8 state;
|
||||
__u16 vid;
|
||||
struct {
|
||||
union {
|
||||
__be32 ip4;
|
||||
struct in6_addr ip6;
|
||||
} u;
|
||||
__be16 proto;
|
||||
} addr;
|
||||
};
|
||||
|
||||
struct abrctl_vlan_range {
|
||||
unsigned arg;
|
||||
unsigned range_count;
|
||||
const unsigned *vlan_ranges;
|
||||
};
|
||||
|
||||
struct bridge_vlan_range {
|
||||
unsigned range_count;
|
||||
__u16 *vlan_ranges;
|
||||
};
|
||||
|
||||
struct bridge_info_opt {
|
||||
unsigned circuit_id_size;
|
||||
unsigned circuit_id;
|
||||
unsigned remote_id_size;
|
||||
unsigned remote_id;
|
||||
};
|
||||
|
||||
struct abrctl_mc_opts {
|
||||
unsigned last_member_count;
|
||||
unsigned startup_query_count;
|
||||
unsigned last_member_interval;
|
||||
unsigned membership_interval;
|
||||
unsigned querier_interval;
|
||||
unsigned query_interval;
|
||||
unsigned query_response_interval;
|
||||
unsigned startup_query_interval;
|
||||
unsigned char querier;
|
||||
unsigned char igmp_version;
|
||||
unsigned char mld_version;
|
||||
};
|
||||
|
||||
struct abrctl_mc_querier {
|
||||
struct {
|
||||
union {
|
||||
__be32 ip4;
|
||||
struct in6_addr ip6;
|
||||
} u;
|
||||
} addr;
|
||||
unsigned portidx;
|
||||
};
|
||||
|
||||
#endif
|
||||
241
2025-03-19/bridge2/fast_path.c
Normal file
241
2025-03-19/bridge2/fast_path.c
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/packet_hook.h>
|
||||
#include <linux/counter.h>
|
||||
#include <net/sch_generic.h>
|
||||
#include "br_private.h"
|
||||
|
||||
static inline int check_hw(const struct net_bridge_port *p,
|
||||
unsigned from_switch_group)
|
||||
{
|
||||
return p->switch_group == BR_NOSWITCH
|
||||
|| p->switch_group != from_switch_group;
|
||||
}
|
||||
|
||||
static inline int should_deliver(const struct net_bridge_port *p,
|
||||
const struct net_device *src, unsigned horizon) {
|
||||
return (src != p->dev
|
||||
&& p->state == BR_STATE_FORWARDING
|
||||
&& (horizon == BR_NOHORIZON || horizon != p->horizon));
|
||||
}
|
||||
|
||||
static int br_dev_fast_path_xmit(struct net_device *dev, struct fp_buf *fpb) {
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
struct net_bridge_fdb_entry *fdb;
|
||||
struct net_device *dst;
|
||||
|
||||
if (is_multicast_ether_addr(fpb_data(fpb))) {
|
||||
goto slow_path;
|
||||
}
|
||||
if (br_opt_get(br, BROPT_VLAN_ENABLED)) {
|
||||
goto slow_path;
|
||||
}
|
||||
fdb = br_fdb_find_rcu(br, fpb_data(fpb), 0);
|
||||
if (!fdb || !fdb->dst) {
|
||||
goto slow_path;
|
||||
}
|
||||
|
||||
if (fdb->dst->state != BR_STATE_FORWARDING) {
|
||||
goto slow_path;
|
||||
}
|
||||
|
||||
dst = fdb->dst->dev;
|
||||
|
||||
if (dst->l2mtu + ETH_HLEN < fpb_len(fpb)) {
|
||||
goto slow_path;
|
||||
}
|
||||
|
||||
fast_path_fp_tx_inc(dev, fpb);
|
||||
return fast_path_tx(dst, fpb);
|
||||
slow_path:
|
||||
return fast_path_tx_slow(dev, fpb);
|
||||
}
|
||||
|
||||
|
||||
static struct net_device *fast_forward_handler(struct net_device *dev, struct fp_buf *fpb) {
|
||||
unsigned char *data = fpb_data(fpb);
|
||||
unsigned x;
|
||||
struct net_device *dst = dev->fp.forward_dev;
|
||||
unsigned a1 = get_unaligned((unsigned *)data);
|
||||
unsigned short a2 = get_unaligned((unsigned short *)&data[4]);
|
||||
if (unlikely(is_multicast_ether_addr(data))) {
|
||||
return NULL;
|
||||
}
|
||||
x = *(unsigned *)dev->fp.dev_addr - a1;
|
||||
x |= *(unsigned short *)&dev->fp.dev_addr[4] - a2;
|
||||
if (unlikely(!x)) {
|
||||
return NULL;
|
||||
}
|
||||
x = *(unsigned *)dst->fp.dev_addr - a1;
|
||||
x |= *(unsigned short *)&dst->fp.dev_addr[4] - a2;
|
||||
if (unlikely(!x)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (unlikely(dst->l2mtu + ETH_HLEN < fpb_len(fpb))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
{
|
||||
struct fast_path_state *fps = &get_cpu_var(per_cpu_fp_state);
|
||||
fps->forward_packets++;
|
||||
fps->forward_bytes += fpb_len(fpb);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static inline void fast_path_bridge_inc(struct fp_buf *fpb) {
|
||||
struct fast_path_state *fps = &get_cpu_var(per_cpu_fp_state);
|
||||
fps->bridge_packets++;
|
||||
fps->bridge_bytes += fpb_len(fpb);
|
||||
}
|
||||
|
||||
DECLARE_PER_CPU(struct net_device *, per_cpu_port);
|
||||
static struct net_device *fast_path_handler(struct net_device *src,
|
||||
struct fp_buf *fpb) {
|
||||
struct ethhdr *eth = (struct ethhdr *)fpb_data(fpb);
|
||||
struct net_device *dst;
|
||||
struct net_bridge_port *src_port;
|
||||
struct net_bridge_port *dst_port;
|
||||
struct net_bridge_fdb_entry *fdb;
|
||||
struct net_bridge *br;
|
||||
// printk("bridge fast path rx %s %u\n", src->name, fpb_len(fpb));
|
||||
// fpb_dump("in", fpb);
|
||||
|
||||
src_port = br_port_get_check_rcu(src);
|
||||
if (!src_port || src_port->state != BR_STATE_FORWARDING) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
br = src_port->br;
|
||||
if (br_opt_get(br, BROPT_VLAN_ENABLED) || br->dhcp_snooping) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fpb_len(fpb) < ETH_HLEN) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (is_multicast_ether_addr(eth->h_dest)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// update src
|
||||
rcu_read_lock();
|
||||
fdb = br_fdb_find_rcu(br, eth->h_source, 0);
|
||||
rcu_read_unlock();
|
||||
if (!fdb) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (test_bit(BR_FDB_LOCAL, &fdb->flags)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fdb->dst != src_port) {
|
||||
fdb->dst = src_port;
|
||||
// Can skip since, fdb is dumped periodically
|
||||
//fdb_notify(br, fdb, RTM_NEWNEIGH);
|
||||
}
|
||||
{
|
||||
unsigned long now = jiffies;
|
||||
if (fdb->updated != now) {
|
||||
fdb->updated = now;
|
||||
}
|
||||
}
|
||||
|
||||
// printk("br rx %s %pM->%pM %pM\n", src->name, eth->h_source, eth->h_dest, br->dev->fp.dev_addr);
|
||||
if (ether_addr_equal(eth->h_dest, br->dev->fp.dev_addr)) {
|
||||
goto rx;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
fdb = br_fdb_find_rcu(br, eth->h_dest, 0);
|
||||
rcu_read_unlock();
|
||||
if (!fdb) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (test_bit(BR_FDB_LOCAL, &fdb->flags)) {
|
||||
rx:
|
||||
if (likely(!*this_cpu_ptr(&per_cpu_port))) {
|
||||
*this_cpu_ptr(&per_cpu_port) = src;
|
||||
}
|
||||
fast_path_rx_noinvalidate(br->dev, fpb);
|
||||
*this_cpu_ptr(&per_cpu_port) = NULL;
|
||||
fast_path_bridge_inc(fpb);
|
||||
return FAST_PATH_CONSUMED;
|
||||
}
|
||||
if (!fdb->dst) {
|
||||
return NULL;
|
||||
}
|
||||
dst_port = fdb->dst;
|
||||
dst = dst_port->dev;
|
||||
|
||||
// final stuff
|
||||
if (!should_deliver(dst_port, src, src_port->horizon)
|
||||
|| !check_hw(dst_port, src_port->switch_group)) {
|
||||
// printk("should not deliver\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dst->l2mtu + ETH_HLEN < fpb_len(fpb)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fast_path_bridge_inc(fpb);
|
||||
// printk("ok %s\n", dst->name);
|
||||
// fpb_dump("ou", fpb);
|
||||
return dst;
|
||||
}
|
||||
|
||||
struct fast_path bridge_fast_path = {
|
||||
.handler = fast_path_handler,
|
||||
.priority = FP_PRIO_BRIDGE,
|
||||
};
|
||||
|
||||
struct fast_path bridge_fast_forward = {
|
||||
.handler = fast_forward_handler,
|
||||
.priority = FP_PRIO_FORWARD,
|
||||
};
|
||||
|
||||
extern struct net_device_ops br_netdev_ops;
|
||||
|
||||
static ssize_t bridge_active_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf) {
|
||||
return sprintf(buf, "%d\n", !bridge_fast_path.suspended);
|
||||
}
|
||||
|
||||
static ssize_t bridge_counter_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf) {
|
||||
return sprintf(buf, "%llu %llu %llu %llu\n",
|
||||
fp_global.bridge_packets, fp_global.bridge_bytes,
|
||||
fp_global.forward_packets, fp_global.forward_bytes);
|
||||
}
|
||||
|
||||
static struct kobj_attribute bridge_active_attribute =
|
||||
__ATTR(fp_bridge_active, 0664, bridge_active_show, NULL);
|
||||
static struct kobj_attribute bridge_counter_attribute =
|
||||
__ATTR(fp_bridge_counter, 0664, bridge_counter_show, NULL);
|
||||
|
||||
static struct attribute *attrs[] = {
|
||||
&bridge_active_attribute.attr,
|
||||
&bridge_counter_attribute.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group attr_group = {
|
||||
.attrs = attrs,
|
||||
};
|
||||
|
||||
int __init bridge_fast_path_init(void) {
|
||||
int ret = sysfs_create_group(kernel_kobj, &attr_group);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
rcu_assign_pointer(br_netdev_ops.ndo_fast_path_xmit, br_dev_fast_path_xmit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit bridge_fast_path_exit(void) {
|
||||
sysfs_remove_group(kernel_kobj, &attr_group);
|
||||
}
|
||||
29
2025-03-19/btest/Makefile
Normal file
29
2025-03-19/btest/Makefile
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
MODULE = btest.ko
|
||||
|
||||
btest_FILES = btest.c
|
||||
btest_PREFIX = misc
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
EXTRA_CFLAGS := $(CFLAGS)
|
||||
|
||||
define moddef
|
||||
obj-m += $(1).o
|
||||
ifneq ($(1).o, $(2))
|
||||
$(1)-y := $(2)
|
||||
EXTRA_CFLAGS += $($(1)_CFLAGS)
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach m, $(MODULE), $(eval $(call moddef,$(m:.ko=),$($(m:.ko=)_FILES:.c=.o))))
|
||||
|
||||
EXTRA_CFLAGS := $(subst -I, -I$(src)/, $(EXTRA_CFLAGS))
|
||||
|
||||
else
|
||||
|
||||
KERNELDIR := /lib/modules/$$(uname -r)/build
|
||||
|
||||
all::
|
||||
$(MAKE) -C $(KERNELDIR) M=$$(pwd) $@
|
||||
|
||||
endif
|
||||
629
2025-03-19/btest/btest.c
Normal file
629
2025-03-19/btest/btest.c
Normal file
|
|
@ -0,0 +1,629 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/udp.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/route.h>
|
||||
#include <net/ip6_route.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/in_route.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/div64.h>
|
||||
#include "btest.h"
|
||||
|
||||
#define BTEST_MASK_LEN 4
|
||||
#define BTEST_BIT_COUNT 32
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
#define STAT_WORK 0
|
||||
#define STAT_TIMER 1
|
||||
#define STAT_XMIT 2
|
||||
#define STAT_XMIT_FAIL 3
|
||||
#define STAT_MAX 4
|
||||
//#define STATS
|
||||
#include <linux/stats.h>
|
||||
#ifdef STATS
|
||||
|
||||
static struct stats_descr stats_btest = {
|
||||
.name = "btest",
|
||||
.interval = HZ,
|
||||
.elements = {
|
||||
{
|
||||
.name = "work",
|
||||
},
|
||||
{
|
||||
.name = "timer",
|
||||
// .no_print = true,
|
||||
// .no_reset = true,
|
||||
},
|
||||
{
|
||||
.name = "xmit",
|
||||
},
|
||||
{
|
||||
.name = "xmit_fail",
|
||||
},
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
static unsigned btest_cpu;
|
||||
struct btest_state {
|
||||
bool started;
|
||||
struct btest_params params;
|
||||
struct btest_info info;
|
||||
unsigned cpu;
|
||||
|
||||
void (*old_data_ready)(struct sock *sk);
|
||||
|
||||
// lost packet stats accounting
|
||||
unsigned first;
|
||||
unsigned unable;
|
||||
unsigned maxseq;
|
||||
unsigned lastseq;
|
||||
unsigned mask[BTEST_MASK_LEN];
|
||||
|
||||
// transmit
|
||||
unsigned packet_nsecs;
|
||||
unsigned seq;
|
||||
u64 next_tx;
|
||||
|
||||
struct socket *socket;
|
||||
struct sock *sk;
|
||||
struct work_struct work;
|
||||
struct hrtimer timer;
|
||||
spinlock_t lock;
|
||||
|
||||
#ifdef STATS
|
||||
struct stats_descr stats;
|
||||
#endif
|
||||
};
|
||||
static atomic_t num_started;
|
||||
|
||||
static struct dst_entry *(*btest_ip6_route_output_flags)(struct net *net,
|
||||
const struct sock *sk, struct flowi6 *fl6, int flags);
|
||||
|
||||
static void btest_account(struct btest_state *state, unsigned seq) {
|
||||
unsigned bit;
|
||||
if (state->first) {
|
||||
state->first = 0;
|
||||
if (seq > 10000) state->unable = 1;
|
||||
state->maxseq = seq;
|
||||
return;
|
||||
}
|
||||
if (state->unable) return;
|
||||
// printk("got seq: %u\n", seq);
|
||||
if (seq > state->maxseq) {
|
||||
unsigned c, i, j;
|
||||
state->lastseq = seq;
|
||||
c = (seq - state->maxseq) / BTEST_BIT_COUNT;
|
||||
if ((seq - state->maxseq) % BTEST_BIT_COUNT) ++c;
|
||||
state->maxseq += c * BTEST_BIT_COUNT;
|
||||
// printk("shift by: %u\n", c * BTEST_BIT_COUNT);
|
||||
if (c > BTEST_MASK_LEN) {
|
||||
state->info.lost += (c - BTEST_MASK_LEN) * BTEST_BIT_COUNT;
|
||||
c = BTEST_MASK_LEN;
|
||||
}
|
||||
|
||||
for (i = 0; i < c; ++i) {
|
||||
for (j = 0; j < BTEST_BIT_COUNT; ++j) {
|
||||
if (!(state->mask[i] & (1 << j))) {
|
||||
++state->info.lost;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < BTEST_MASK_LEN; ++i) {
|
||||
if (i < BTEST_MASK_LEN - c) state->mask[i] = state->mask[i + c];
|
||||
else state->mask[i] = 0;
|
||||
}
|
||||
}
|
||||
bit = state->maxseq - seq;
|
||||
// printk("in range: %u\n", bit);
|
||||
if (bit < BTEST_MASK_LEN * BTEST_BIT_COUNT) {
|
||||
unsigned c = BTEST_MASK_LEN - 1 - bit / BTEST_BIT_COUNT;
|
||||
bit %= BTEST_BIT_COUNT;
|
||||
|
||||
if (state->mask[c] & (1 << bit)) {
|
||||
++state->info.duplicate;
|
||||
}
|
||||
else {
|
||||
state->mask[c] |= (1 << bit);
|
||||
if (seq < state->lastseq) {
|
||||
++state->info.outoforder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void btest_data_ready(struct sock *sk) {
|
||||
struct btest_state *state = (struct btest_state *) sk->sk_user_data;
|
||||
int err;
|
||||
struct sk_buff *skb;
|
||||
unsigned seq;
|
||||
int off;
|
||||
if (!state->started) {
|
||||
return;
|
||||
}
|
||||
// printk("btest_data_ready: %u\n", bytes);
|
||||
|
||||
while ((skb = __skb_recv_udp(sk, 0, 1, &off, &err)) == NULL) {
|
||||
if (err == -EAGAIN) {
|
||||
printk("btest: no data available?!");
|
||||
return;
|
||||
}
|
||||
printk("btest: recvfrom() error %d\n", -err);
|
||||
}
|
||||
|
||||
seq = ntohl(get_unaligned((unsigned *)(udp_hdr(skb) + 1)));
|
||||
// seq = ntohl(get_unaligned((unsigned *)(skb->data + sizeof(udp_hdr))));
|
||||
|
||||
spin_lock_bh(&state->lock);
|
||||
btest_account(state, seq);
|
||||
state->info.received += skb->len;
|
||||
spin_unlock_bh(&state->lock);
|
||||
|
||||
skb_free_datagram(sk, skb);
|
||||
}
|
||||
|
||||
static unsigned x;
|
||||
static void btest_random(void *buf, int len) {
|
||||
unsigned char *data = buf;
|
||||
int i;
|
||||
for (i = 0; i < len; ++i) {
|
||||
x += (x >> 26) | (x << 14);
|
||||
data[i] = x;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int do_ip_send(struct net *net, struct sock *sock, struct sk_buff *skb) {
|
||||
return dst_output(net, sock, skb);
|
||||
// return ip_send(skb);
|
||||
}
|
||||
|
||||
static int btest_send_ipv4(struct sock *sk, unsigned seq, bool random, unsigned size) {
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
int err = 0;
|
||||
struct rtable *rt = NULL;
|
||||
u8 tos = RT_TOS(inet->tos);
|
||||
unsigned headroom;
|
||||
struct sk_buff *skb;
|
||||
struct iphdr *iph;
|
||||
struct udphdr *uh;
|
||||
struct flowi4 fl4;
|
||||
|
||||
rt = (struct rtable*)sk_dst_check(sk, 0);
|
||||
|
||||
if (rt == NULL) {
|
||||
rt = ip_route_output_ports(&init_net, &fl4, NULL,
|
||||
inet->inet_daddr, inet->inet_saddr,
|
||||
inet->inet_dport, inet->inet_sport,
|
||||
sk->sk_protocol,
|
||||
RT_CONN_FLAGS(sk),
|
||||
sk->sk_bound_dev_if);
|
||||
if (IS_ERR(rt)) return PTR_ERR(rt);
|
||||
|
||||
err = -EACCES;
|
||||
if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST)) {
|
||||
goto out;
|
||||
}
|
||||
sk_dst_set(sk, dst_clone(&rt->dst));
|
||||
}
|
||||
|
||||
headroom = LL_RESERVED_SPACE(rt->dst.dev);
|
||||
|
||||
skb = alloc_skb(headroom + size + 31, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_reserve(skb, headroom);
|
||||
|
||||
skb->priority = sk->sk_priority;
|
||||
skb_dst_set(skb, dst_clone(&rt->dst));
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
iph = (struct iphdr *)skb_put(skb, size);
|
||||
iph->version = 4;
|
||||
iph->ihl = sizeof(struct iphdr)>>2;
|
||||
iph->frag_off = 0;
|
||||
iph->ttl = 64;
|
||||
iph->protocol = sk->sk_protocol;
|
||||
iph->tos = tos;
|
||||
iph->daddr = inet->inet_daddr;
|
||||
iph->saddr = inet->inet_saddr;
|
||||
iph->check = 0;
|
||||
iph->tot_len = htons(size);
|
||||
ip_select_ident(&init_net, skb, NULL);
|
||||
ip_send_check(iph);
|
||||
|
||||
skb_set_transport_header(skb, sizeof(struct iphdr));
|
||||
uh = udp_hdr(skb);
|
||||
uh->source = inet->inet_sport;
|
||||
uh->dest = inet->inet_dport;
|
||||
uh->len = htons(size - sizeof(struct iphdr));
|
||||
uh->check = 0;
|
||||
|
||||
if (size >= 32) {
|
||||
put_unaligned(htonl(++seq), (unsigned *)(skb->data + 28));
|
||||
}
|
||||
if (random) {
|
||||
btest_random(skb->data + 32, (int)size - 32);
|
||||
}
|
||||
|
||||
err = NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, &init_net,
|
||||
NULL, skb, NULL, rt->dst.dev, do_ip_send);
|
||||
|
||||
out:
|
||||
ip_rt_put(rt);
|
||||
// if (err < 0) printk("err: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btest_send_ipv6(struct sock *sk, unsigned seq, bool random, unsigned size) {
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
int err = 0;
|
||||
unsigned headroom;
|
||||
struct sk_buff *skb;
|
||||
struct ipv6hdr *iph;
|
||||
struct udphdr *uh;
|
||||
struct dst_entry *dst = sk_dst_check(sk, 0);
|
||||
unsigned udpsize = size - sizeof(struct ipv6hdr);
|
||||
|
||||
if (!dst) {
|
||||
struct flowi6 fl = {};
|
||||
fl.flowi6_oif = sk->sk_bound_dev_if;
|
||||
fl.daddr = sk->sk_v6_daddr;
|
||||
fl.saddr = inet->pinet6->saddr;
|
||||
fl.flowlabel = inet->pinet6->flow_label;
|
||||
fl.flowi6_proto = sk->sk_protocol;
|
||||
fl.fl6_sport = inet->inet_sport;
|
||||
fl.fl6_dport = inet->inet_dport;
|
||||
|
||||
dst = btest_ip6_route_output_flags(&init_net, NULL, &fl, 0);
|
||||
if (dst->error) {
|
||||
dst_release(dst);
|
||||
return -EACCES;
|
||||
}
|
||||
dst = xfrm_lookup(&init_net, dst, flowi6_to_flowi(&fl), NULL, 0);
|
||||
if (IS_ERR(dst)) {
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
sk_dst_set(sk, dst_clone(dst));
|
||||
}
|
||||
|
||||
headroom = (((dst->dev->hard_header_len + 31) & ~31));
|
||||
|
||||
skb = alloc_skb(headroom + size + 31, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
skb_reserve(skb, headroom);
|
||||
|
||||
skb->priority = sk->sk_priority;
|
||||
skb_dst_set(skb, dst_clone(dst));
|
||||
skb->protocol = htons(ETH_P_IPV6);
|
||||
skb->dev = dst->dev;
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
iph = (struct ipv6hdr *)skb_put(skb, size);
|
||||
iph->version = 6;
|
||||
iph->priority = 0;
|
||||
iph->flow_lbl[0] = htonl(inet->pinet6->flow_label) >> 16;
|
||||
iph->flow_lbl[1] = htonl(inet->pinet6->flow_label) >> 8;
|
||||
iph->flow_lbl[2] = htonl(inet->pinet6->flow_label);
|
||||
iph->payload_len = htons(size - sizeof(struct ipv6hdr));
|
||||
iph->nexthdr = sk->sk_protocol;
|
||||
iph->hop_limit = 64;
|
||||
iph->saddr = inet->pinet6->saddr;
|
||||
iph->daddr = sk->sk_v6_daddr;
|
||||
|
||||
skb_set_transport_header(skb, sizeof(struct ipv6hdr));
|
||||
uh = udp_hdr(skb);
|
||||
|
||||
if (size >= 52) {
|
||||
put_unaligned(htonl(++seq), (unsigned *)(skb->data + 48));
|
||||
}
|
||||
if (random) {
|
||||
btest_random(skb->data + 52, (int)size - 52);
|
||||
}
|
||||
|
||||
uh->source = inet->inet_sport;
|
||||
uh->dest = inet->inet_dport;
|
||||
uh->len = htons(udpsize);
|
||||
uh->check = 0;
|
||||
uh->check = csum_ipv6_magic(&iph->saddr, &iph->daddr,
|
||||
udpsize, IPPROTO_UDP,
|
||||
csum_partial(uh, udpsize, 0));
|
||||
|
||||
err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, &init_net,
|
||||
NULL, skb, NULL, dst->dev, do_ip_send);
|
||||
dst_release(dst);
|
||||
// if (err < 0) printk("err: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int btest_send_packet(struct sock *sk, unsigned seq, bool random, unsigned size) {
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
|
||||
if (inet->pinet6) {
|
||||
if (inet->pinet6->saddr.in6_u.u6_addr32[0] ||
|
||||
inet->pinet6->saddr.in6_u.u6_addr32[1] ||
|
||||
inet->pinet6->saddr.in6_u.u6_addr32[2] != ntohl(0xffff)) {
|
||||
return btest_send_ipv6(sk, seq, random, size);
|
||||
}
|
||||
}
|
||||
return btest_send_ipv4(sk, seq, random, size);
|
||||
}
|
||||
|
||||
static inline unsigned btest_get_size(struct btest_state *state) {
|
||||
if (state->params.send_size_from != state->params.send_size_to) {
|
||||
unsigned rnd;
|
||||
get_random_bytes(&rnd, sizeof(rnd));
|
||||
return state->params.send_size_from +
|
||||
(rnd % (state->params.send_size_to -
|
||||
state->params.send_size_from));
|
||||
}
|
||||
else {
|
||||
return state->params.send_size_from;
|
||||
}
|
||||
}
|
||||
|
||||
static void btest_adjust(struct btest_state *state) {
|
||||
unsigned size =
|
||||
(state->params.send_size_from + state->params.send_size_to) / 2;
|
||||
unsigned long long x = state->params.send_rate;
|
||||
do_div(x, size);
|
||||
if (!x) {
|
||||
x = 1;
|
||||
}
|
||||
state->packet_nsecs = 1000000 / (unsigned)x * 1000;
|
||||
state->next_tx = ktime_get_ns();
|
||||
}
|
||||
|
||||
static void btest_tx_task(struct work_struct *w) {
|
||||
struct btest_state *state = container_of(w, struct btest_state, work);
|
||||
u64 start;
|
||||
|
||||
stats_inc(&state->stats, STAT_WORK);
|
||||
start = ktime_get_ns();
|
||||
|
||||
spin_lock_bh(&state->lock);
|
||||
if (!state->started) {
|
||||
spin_unlock_bh(&state->lock);
|
||||
return;
|
||||
}
|
||||
u64 curr;
|
||||
u64 dur;
|
||||
unsigned c = 0;
|
||||
|
||||
struct sock *sk = state->sk;
|
||||
bool random = state->params.send_random;
|
||||
while (start > state->next_tx) {
|
||||
unsigned size = btest_get_size(state);
|
||||
++state->seq;
|
||||
unsigned seq = state->seq;
|
||||
stats_inc(&state->stats, STAT_XMIT);
|
||||
spin_unlock_bh(&state->lock);
|
||||
if (btest_send_packet(sk, seq, random, size)) {
|
||||
stats_inc(&state->stats, STAT_XMIT_FAIL);
|
||||
spin_lock_bh(&state->lock);
|
||||
break;
|
||||
}
|
||||
|
||||
++c;
|
||||
if (c == 10) {
|
||||
c = 0;
|
||||
curr = ktime_get_ns();
|
||||
dur = curr - start;
|
||||
if (dur > 2000000) {
|
||||
spin_lock_bh(&state->lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_bh(&state->lock);
|
||||
state->next_tx += state->packet_nsecs;
|
||||
}
|
||||
unsigned sl = state->packet_nsecs;
|
||||
|
||||
hrtimer_start(&state->timer, ktime_set(0, sl), HRTIMER_MODE_REL);
|
||||
spin_unlock_bh(&state->lock);
|
||||
}
|
||||
|
||||
static enum hrtimer_restart btest_hrtimer(struct hrtimer *t) {
|
||||
struct btest_state *state = container_of(t, struct btest_state, timer);
|
||||
stats_inc(&state->stats, STAT_TIMER);
|
||||
schedule_work_on(state->cpu, &state->work);
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static int btest_start(struct file *file) {
|
||||
struct btest_state *state = (struct btest_state *)file->private_data;
|
||||
struct socket *socket;
|
||||
int err;
|
||||
|
||||
spin_lock_bh(&state->lock);
|
||||
#ifdef STATS
|
||||
memcpy(&state->stats, &stats_btest, sizeof(stats_btest));
|
||||
sprintf(state->stats.name, "btest%u", state->params.fd);
|
||||
#endif
|
||||
|
||||
if (state->started) {
|
||||
spin_unlock_bh(&state->lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
// printk("btest: start file %p\n", file);
|
||||
|
||||
socket = sockfd_lookup(state->params.fd, &err);
|
||||
if (!socket) {
|
||||
spin_unlock_bh(&state->lock);
|
||||
return err;
|
||||
}
|
||||
state->socket = socket;
|
||||
state->sk = socket->sk;
|
||||
sock_hold(state->sk);
|
||||
atomic_inc(&num_started);
|
||||
|
||||
if (state->params.flags & BTEST_RECEIVE) {
|
||||
state->old_data_ready = socket->sk->sk_data_ready;
|
||||
socket->sk->sk_user_data = state;
|
||||
mb();
|
||||
socket->sk->sk_data_ready = btest_data_ready;
|
||||
// socket->file->private_data = state;
|
||||
// printk("btest: recv file %p\n", socket->file);
|
||||
}
|
||||
|
||||
if (state->params.flags & BTEST_SEND) {
|
||||
btest_adjust(state);
|
||||
// printk("btest: size:%u-%u, bytes/sec:%llu, random:%u, packet_nsecs:%u\n",
|
||||
// state->params.send_size_from, state->params.send_size_to,
|
||||
// state->params.send_rate,
|
||||
// state->params.send_random,
|
||||
// state->packet_nsecs);
|
||||
|
||||
state->cpu = btest_cpu;
|
||||
btest_cpu = (btest_cpu + 1) % num_online_cpus();
|
||||
schedule_work_on(state->cpu, &state->work);
|
||||
}
|
||||
state->started = true;
|
||||
spin_unlock_bh(&state->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btest_open(struct inode *inode, struct file *file) {
|
||||
struct btest_state *state;
|
||||
// printk("btest: open\n");
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN)) return -EBUSY;
|
||||
|
||||
state = kmalloc(sizeof(struct btest_state), GFP_KERNEL);
|
||||
if (!state) return -ENOMEM;
|
||||
memset(state, 0, sizeof(struct btest_state));
|
||||
|
||||
state->first = 1;
|
||||
memset(state->mask, 0xFF, sizeof(unsigned) * BTEST_MASK_LEN);
|
||||
|
||||
INIT_WORK(&state->work, btest_tx_task);
|
||||
|
||||
hrtimer_init(&state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
|
||||
state->timer.function = btest_hrtimer;
|
||||
spin_lock_init(&state->lock);
|
||||
|
||||
file->private_data = state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btest_release(struct inode *inode, struct file *file) {
|
||||
struct btest_state *state = (struct btest_state *)file->private_data;
|
||||
// printk("btest: release: %p\n", state);
|
||||
|
||||
if (state->started) {
|
||||
state->started = false;
|
||||
cancel_work_sync(&state->work);
|
||||
spin_lock_bh(&state->lock);
|
||||
hrtimer_cancel(&state->timer);
|
||||
|
||||
if (state->old_data_ready) {
|
||||
state->sk->sk_data_ready = state->old_data_ready;
|
||||
}
|
||||
|
||||
sockfd_put(state->socket);
|
||||
sock_put(state->sk);
|
||||
spin_unlock_bh(&state->lock);
|
||||
atomic_dec(&num_started);
|
||||
}
|
||||
kfree(state);
|
||||
if (!atomic_read(&num_started)) {
|
||||
synchronize_net();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long btest_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long data) {
|
||||
struct btest_state *state = (struct btest_state *)file->private_data;
|
||||
|
||||
// printk("btest_ioctl: %u %lu\n", cmd, data);
|
||||
switch (cmd) {
|
||||
case BTEST_IOCTL_START:
|
||||
if (copy_from_user(&state->params, (void *)data,
|
||||
sizeof(struct btest_params))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return btest_start(file);
|
||||
case BTEST_IOCTL_GET:
|
||||
// printk("state->info.lost: %u\n", state->info.lost);
|
||||
spin_lock_bh(&state->lock);
|
||||
if (copy_to_user((void *)data, &state->info,
|
||||
sizeof(struct btest_info))) {
|
||||
spin_unlock_bh(&state->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(&state->info, 0, sizeof(struct btest_info));
|
||||
spin_unlock_bh(&state->lock);
|
||||
return 0;
|
||||
case BTEST_IOCTL_ADJUST:
|
||||
if (copy_from_user(&state->params.send_rate, (void *)data,
|
||||
sizeof(unsigned long long))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
spin_lock_bh(&state->lock);
|
||||
btest_adjust(state);
|
||||
spin_unlock_bh(&state->lock);
|
||||
// printk("btest: adjust rate: %llu packet_nsecs:%u\n",
|
||||
// state->params.send_rate, state->packet_nsecs);
|
||||
return 0;
|
||||
}
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
static struct file_operations btest_fops = {
|
||||
owner: THIS_MODULE,
|
||||
open: btest_open,
|
||||
release: btest_release,
|
||||
unlocked_ioctl: btest_ioctl,
|
||||
compat_ioctl: btest_ioctl,
|
||||
};
|
||||
|
||||
static struct miscdevice btest_miscdev = {
|
||||
minor: MISC_DYNAMIC_MINOR,
|
||||
name: "btest",
|
||||
fops: &btest_fops,
|
||||
};
|
||||
|
||||
int init_module(void) {
|
||||
int err;
|
||||
btest_ip6_route_output_flags = symbol_get(ip6_route_output_flags);
|
||||
|
||||
err = misc_register(&btest_miscdev);
|
||||
if (err) {
|
||||
printk("btest: failed to register char device\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
get_random_bytes(&x, sizeof(x));
|
||||
atomic_set(&num_started, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_module(void) {
|
||||
misc_deregister(&btest_miscdev);
|
||||
|
||||
if (btest_ip6_route_output_flags) {
|
||||
symbol_put(ip6_route_output_flags);
|
||||
}
|
||||
}
|
||||
32
2025-03-19/btest/btest.h
Normal file
32
2025-03-19/btest/btest.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef _LINUX_BTEST_H_
|
||||
#define _LINUX_BTEST_H_
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
|
||||
#define BTEST_SEND 0x01
|
||||
#define BTEST_RECEIVE 0x02
|
||||
|
||||
struct btest_params {
|
||||
int fd;
|
||||
unsigned flags;
|
||||
unsigned send_size_from;
|
||||
unsigned send_size_to;
|
||||
unsigned long long send_rate;
|
||||
unsigned send_random;
|
||||
unsigned padding;
|
||||
};
|
||||
|
||||
struct btest_info {
|
||||
unsigned long long received;
|
||||
unsigned lost;
|
||||
unsigned outoforder;
|
||||
unsigned duplicate;
|
||||
unsigned padding;
|
||||
};
|
||||
|
||||
#define BTEST_IOCTL_START _IOW('x', 1, struct btest_params)
|
||||
#define BTEST_IOCTL_GET _IOR('x', 2, struct btest_info)
|
||||
#define BTEST_IOCTL_ADJUST _IOW('x', 3, unsigned long long)
|
||||
|
||||
#endif
|
||||
3093
2025-03-19/configs/440.config
Normal file
3093
2025-03-19/configs/440.config
Normal file
File diff suppressed because it is too large
Load diff
4754
2025-03-19/configs/arm.config
Normal file
4754
2025-03-19/configs/arm.config
Normal file
File diff suppressed because it is too large
Load diff
4815
2025-03-19/configs/arm64.config
Normal file
4815
2025-03-19/configs/arm64.config
Normal file
File diff suppressed because it is too large
Load diff
3160
2025-03-19/configs/e500-smp.config
Normal file
3160
2025-03-19/configs/e500-smp.config
Normal file
File diff suppressed because it is too large
Load diff
3233
2025-03-19/configs/e500.config
Normal file
3233
2025-03-19/configs/e500.config
Normal file
File diff suppressed because it is too large
Load diff
3860
2025-03-19/configs/mips.config
Normal file
3860
2025-03-19/configs/mips.config
Normal file
File diff suppressed because it is too large
Load diff
3902
2025-03-19/configs/mmips.config
Normal file
3902
2025-03-19/configs/mmips.config
Normal file
File diff suppressed because it is too large
Load diff
2988
2025-03-19/configs/powerpc.config
Normal file
2988
2025-03-19/configs/powerpc.config
Normal file
File diff suppressed because it is too large
Load diff
3385
2025-03-19/configs/smips.config
Normal file
3385
2025-03-19/configs/smips.config
Normal file
File diff suppressed because it is too large
Load diff
3522
2025-03-19/configs/tile.config
Normal file
3522
2025-03-19/configs/tile.config
Normal file
File diff suppressed because it is too large
Load diff
4380
2025-03-19/configs/x86_64.config
Normal file
4380
2025-03-19/configs/x86_64.config
Normal file
File diff suppressed because it is too large
Load diff
29
2025-03-19/crypto4xx/Makefile
Normal file
29
2025-03-19/crypto4xx/Makefile
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#MODULE = 440/crypto4xx.ko
|
||||
|
||||
crypto4xx_FILES = crypto4xx_core.c crypto4xx_alg.c crypto4xx_sa.c
|
||||
crypto4xx_PREFIX = drivers/crypto
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
EXTRA_CFLAGS := $(CFLAGS)
|
||||
|
||||
define moddef
|
||||
obj-m += $(1).o
|
||||
ifneq ($(1).o, $(2))
|
||||
$(1)-y := $(2)
|
||||
EXTRA_CFLAGS += $($(1)_CFLAGS)
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach m, $(MODULE), $(eval $(call moddef,$(m:.ko=),$($(m:.ko=)_FILES:.c=.o))))
|
||||
|
||||
EXTRA_CFLAGS := $(subst -I, -I$(src)/, $(EXTRA_CFLAGS))
|
||||
|
||||
else
|
||||
|
||||
KERNELDIR := /lib/modules/$$(uname -r)/build
|
||||
|
||||
all::
|
||||
$(MAKE) -C $(KERNELDIR) M=$$(pwd) $@
|
||||
|
||||
endif
|
||||
1354
2025-03-19/crypto4xx/crypto4xx_alg.c
Normal file
1354
2025-03-19/crypto4xx/crypto4xx_alg.c
Normal file
File diff suppressed because it is too large
Load diff
2045
2025-03-19/crypto4xx/crypto4xx_core.c
Normal file
2045
2025-03-19/crypto4xx/crypto4xx_core.c
Normal file
File diff suppressed because it is too large
Load diff
279
2025-03-19/crypto4xx/crypto4xx_core.h
Normal file
279
2025-03-19/crypto4xx/crypto4xx_core.h
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
/**
|
||||
* AMCC SoC PPC4xx Crypto Driver
|
||||
*
|
||||
* Copyright (c) 2008 Applied Micro Circuits Corporation.
|
||||
* All rights reserved. James Hsiao <jhsiao@amcc.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This is the header file for AMCC Crypto offload Linux device driver for
|
||||
* use with Linux CryptoAPI.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __CRYPTO4XX_CORE_H__
|
||||
#define __CRYPTO4XX_CORE_H__
|
||||
|
||||
#include <crypto/internal/hash.h>
|
||||
#include <crypto/aead.h>
|
||||
|
||||
#define PPC460SX_SDR0_SRST 0x201
|
||||
#define PPC405EX_SDR0_SRST 0x200
|
||||
#define PPC460EX_SDR0_SRST 0x201
|
||||
#define PPC460EX_CE_RESET 0x08000000
|
||||
#define PPC460SX_CE_RESET 0x20000000
|
||||
#define PPC405EX_CE_RESET 0x00000008
|
||||
|
||||
#define CRYPTO4XX_CRYPTO_PRIORITY 300
|
||||
#define PPC4XX_LAST_PD 63
|
||||
#define PPC4XX_NUM_PD 64
|
||||
#define PPC4XX_LAST_GD 1023
|
||||
#define PPC4XX_NUM_GD 1024
|
||||
#define PPC4XX_LAST_SD 63
|
||||
#define PPC4XX_NUM_SD 64
|
||||
#define PPC4XX_SD_BUFFER_SIZE 2048
|
||||
|
||||
#define PD_ENTRY_INUSE 1
|
||||
#define PD_ENTRY_FREE 0
|
||||
#define ERING_WAS_FULL 0xffffffff
|
||||
|
||||
#define _4XX_ENABLE_CRYPT 1
|
||||
#define _4XX_ENABLE_HASH 0
|
||||
#define _4XX_ENABLE_AEAD 0
|
||||
|
||||
struct crypto4xx_device;
|
||||
|
||||
struct pd_uinfo {
|
||||
struct crypto4xx_device *dev;
|
||||
u32 state;
|
||||
u32 using_sd;
|
||||
u32 first_gd; /* first gather discriptor
|
||||
used by this packet */
|
||||
u32 num_gd; /* number of gather discriptor
|
||||
used by this packet */
|
||||
u32 first_sd; /* first scatter discriptor
|
||||
used by this packet */
|
||||
u32 num_sd; /* number of scatter discriptors
|
||||
used by this packet */
|
||||
void *sa_va; /* shadow sa, when using cp from ctx->sa */
|
||||
u32 sa_pa;
|
||||
void *sr_va; /* state record for shadow sa */
|
||||
u32 sr_pa;
|
||||
struct scatterlist *dest_va;
|
||||
struct crypto_async_request *async_req; /* base crypto request
|
||||
for this packet */
|
||||
};
|
||||
|
||||
struct crypto4xx_device {
|
||||
struct crypto4xx_core_device *core_dev;
|
||||
char *name;
|
||||
u64 ce_phy_address;
|
||||
void __iomem *ce_base;
|
||||
|
||||
void *pdr; /* base address of packet
|
||||
descriptor ring */
|
||||
dma_addr_t pdr_pa; /* physical address used to
|
||||
program ce pdr_base_register */
|
||||
void *gdr; /* gather descriptor ring */
|
||||
dma_addr_t gdr_pa; /* physical address used to
|
||||
program ce gdr_base_register */
|
||||
void *sdr; /* scatter descriptor ring */
|
||||
dma_addr_t sdr_pa; /* physical address used to
|
||||
program ce sdr_base_register */
|
||||
void *scatter_buffer_va;
|
||||
dma_addr_t scatter_buffer_pa;
|
||||
u32 scatter_buffer_size;
|
||||
|
||||
void *shadow_sa_pool; /* pool of memory for sa in pd_uinfo */
|
||||
dma_addr_t shadow_sa_pool_pa;
|
||||
void *shadow_sr_pool; /* pool of memory for sr in pd_uinfo */
|
||||
dma_addr_t shadow_sr_pool_pa;
|
||||
u32 pdr_tail;
|
||||
u32 pdr_head;
|
||||
u32 gdr_tail;
|
||||
u32 gdr_head;
|
||||
u32 sdr_tail;
|
||||
u32 sdr_head;
|
||||
void *pdr_uinfo;
|
||||
struct list_head alg_list; /* List of algorithm supported
|
||||
by this device */
|
||||
};
|
||||
|
||||
struct crypto4xx_core_device {
|
||||
struct device *device;
|
||||
struct platform_device *ofdev;
|
||||
struct crypto4xx_device *dev;
|
||||
u32 int_status;
|
||||
u32 irq;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct crypto4xx_ctx_base {
|
||||
struct crypto4xx_device *dev;
|
||||
void *sa_in;
|
||||
dma_addr_t sa_in_dma_addr;
|
||||
void *sa_out;
|
||||
dma_addr_t sa_out_dma_addr;
|
||||
void *state_record;
|
||||
dma_addr_t state_record_dma_addr;
|
||||
u32 offset_to_sr_ptr; /* offset to state ptr, in dynamic sa */
|
||||
u32 direction;
|
||||
u32 pd_ctl_len;
|
||||
u32 pd_ctl;
|
||||
u32 is_hash;
|
||||
u32 hash_final;
|
||||
u32 sa_len;
|
||||
// used only for ciphers
|
||||
u32 is_gcm;
|
||||
u32 ctr_aes;
|
||||
u32 bypass;
|
||||
};
|
||||
|
||||
struct crypto4xx_cipher_tfm_ctx {
|
||||
struct crypto4xx_ctx_base base;
|
||||
struct crypto_skcipher *fallback;
|
||||
dma_addr_t arc4_state_record_dma_addr;
|
||||
void *arc4_state_record;
|
||||
u32 append_icv;
|
||||
u32 init_arc4;
|
||||
};
|
||||
|
||||
struct crypto4xx_cipher_req_ctx {
|
||||
};
|
||||
|
||||
struct crypto4xx_ahash_tfm_ctx {
|
||||
struct crypto4xx_device *dev;
|
||||
struct crypto_ahash *fallback;
|
||||
u32 digest_size;
|
||||
u32 block_size;
|
||||
u32 sa_len;
|
||||
u8 hash;
|
||||
u8 hash_mode;
|
||||
u8 iv[2 * 512];
|
||||
};
|
||||
|
||||
struct crypto4xx_ahash_req_ctx {
|
||||
struct crypto4xx_ctx_base base;
|
||||
struct ahash_request fallback_req;
|
||||
};
|
||||
|
||||
struct crypto4xx_alg_common {
|
||||
u32 type;
|
||||
union {
|
||||
struct crypto_alg cipher;
|
||||
struct ahash_alg hash;
|
||||
struct aead_alg aead;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct crypto4xx_alg {
|
||||
struct list_head entry;
|
||||
struct crypto4xx_alg_common alg;
|
||||
struct crypto4xx_device *dev;
|
||||
};
|
||||
|
||||
static inline struct crypto4xx_alg *crypto_alg_to_crypto4xx_alg(
|
||||
struct crypto_alg *x)
|
||||
{
|
||||
switch (x->cra_flags & CRYPTO_ALG_TYPE_MASK) {
|
||||
case CRYPTO_ALG_TYPE_AHASH:
|
||||
return container_of(__crypto_ahash_alg(x),
|
||||
struct crypto4xx_alg, alg.u.hash);
|
||||
}
|
||||
|
||||
return container_of(x, struct crypto4xx_alg, alg.u.cipher);
|
||||
}
|
||||
|
||||
extern int crypto4xx_alloc_sa(struct crypto4xx_ctx_base *ctx, u32 size);
|
||||
extern void crypto4xx_free_sa(struct crypto4xx_ctx_base *ctx);
|
||||
extern u32 crypto4xx_alloc_state_record(struct crypto4xx_ctx_base *ctx);
|
||||
extern u32 get_dynamic_sa_offset_state_ptr_field(struct crypto4xx_ctx_base *ctx);
|
||||
extern u32 get_dynamic_sa_offset_key_field(struct crypto4xx_ctx_base *ctx);
|
||||
extern u32 get_dynamic_sa_iv_size(struct crypto4xx_ctx_base *ctx);
|
||||
extern void crypto4xx_memcpy_le(unsigned int *dst,
|
||||
const unsigned char *buf, int len);
|
||||
extern u32 crypto4xx_build_pd(struct crypto_async_request *req,
|
||||
struct crypto4xx_ctx_base *ctx,
|
||||
struct scatterlist *src,
|
||||
struct scatterlist *dst,
|
||||
unsigned int datalen,
|
||||
u32 aad_len,
|
||||
void *iv, u32 iv_len);
|
||||
extern int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher,
|
||||
const u8 *key, unsigned int keylen);
|
||||
extern int crypto4xx_setkey_3des_cbc(struct crypto_ablkcipher *cipher,
|
||||
const u8 *key, unsigned int keylen);
|
||||
extern int crypto4xx_setkey_3des_ecb(struct crypto_ablkcipher *cipher,
|
||||
const u8 *key, unsigned int keylen);
|
||||
extern int crypto4xx_encrypt(struct ablkcipher_request *req);
|
||||
extern int crypto4xx_decrypt(struct ablkcipher_request *req);
|
||||
|
||||
// hashing
|
||||
extern int crypto4xx_hash_digest(struct ahash_request *req);
|
||||
extern int crypto4xx_hash_final(struct ahash_request *req);
|
||||
extern int crypto4xx_hash_update(struct ahash_request *req);
|
||||
extern int crypto4xx_hash_init(struct ahash_request *req);
|
||||
extern void crypto4xx_hash_alg_exit(struct crypto_tfm *tfm);
|
||||
extern int crypto4xx_md5_alg_init(struct crypto_tfm *tfm);
|
||||
extern int crypto4xx_md5_hmac_init(struct crypto_tfm *tfm);
|
||||
extern int crypto4xx_md5_hmac_setkey(struct crypto_ahash *hash, const u8 *key,
|
||||
unsigned int keylen);
|
||||
extern int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm);
|
||||
extern int crypto4xx_sha1_hmac_init(struct crypto_tfm *tfm);
|
||||
extern int crypto4xx_sha1_hmac_setkey(struct crypto_ahash *hash, const u8 *key,
|
||||
unsigned int keylen);
|
||||
extern int crypto4xx_sha2_alg_init(struct crypto_tfm *tfm);
|
||||
extern int crypto4xx_sha2_hmac_init(struct crypto_tfm *tfm);
|
||||
extern int crypto4xx_sha2_hmac_setkey(struct crypto_ahash *hash,
|
||||
const u8 *key,
|
||||
unsigned int keylen);
|
||||
extern u32 get_dynamic_sa_offset_inner_digest(struct crypto4xx_ctx_base *ctx);
|
||||
extern u32 get_dynamic_sa_offset_outer_digest(struct crypto4xx_ctx_base *ctx);
|
||||
extern int crypto4xx_pre_compute_hmac(struct crypto4xx_ahash_tfm_ctx *ctx,
|
||||
void *key,
|
||||
unsigned int keylen,
|
||||
unsigned int bs,
|
||||
unsigned char ha,
|
||||
unsigned char digs);
|
||||
|
||||
int crypto4xx_setkey_aes_ecb(struct crypto_ablkcipher *cipher,
|
||||
const u8 *key, unsigned int keylen);
|
||||
int crypto4xx_setkey_aes_ofb(struct crypto_ablkcipher *cipher,
|
||||
const u8 *key, unsigned int keylen);
|
||||
int crypto4xx_setkey_aes_cfb(struct crypto_ablkcipher *cipher,
|
||||
const u8 *key, unsigned int keylen);
|
||||
int crypto4xx_setkey_aes_ctr(struct crypto_ablkcipher *cipher,
|
||||
const u8 *key, unsigned int keylen);
|
||||
#if _4XX_ENABLE_AEAD
|
||||
int crypto4xx_setkey_aes_gcm(struct crypto_aead *cipher,
|
||||
const u8 *key, unsigned int keylen);
|
||||
int crypto4xx_setkey_aes_ccm(struct crypto_aead *cipher,
|
||||
const u8 *key, unsigned int keylen);
|
||||
|
||||
int crypto4xx_encrypt_aes_gcm(struct aead_request *req);
|
||||
int crypto4xx_decrypt_aes_gcm(struct aead_request *req);
|
||||
int crypto4xx_encrypt_aes_ccm(struct aead_request *req);
|
||||
int crypto4xx_decrypt_aes_ccm(struct aead_request *req);
|
||||
#endif
|
||||
int crypto4xx_encrypt_ctr(struct ablkcipher_request *req);
|
||||
int crypto4xx_decrypt_ctr(struct ablkcipher_request *req);
|
||||
int crypto4xx_setauthsize_aes(struct crypto_aead *ciper,
|
||||
unsigned int authsize);
|
||||
extern u32 get_dynamic_sa_offset_arc4_state_ptr(struct crypto4xx_ctx_base *ctx);
|
||||
int crypto4xx_setauthsize_aes_ccm(struct crypto_aead *ciper,
|
||||
unsigned int authsize);
|
||||
|
||||
#if _4XX_ENABLE_HASH
|
||||
/* From crypto/md5.c */
|
||||
extern unsigned int crypto4xx_sa_hash_tbl[3][6];
|
||||
#endif
|
||||
|
||||
#endif
|
||||
298
2025-03-19/crypto4xx/crypto4xx_reg_def.h
Normal file
298
2025-03-19/crypto4xx/crypto4xx_reg_def.h
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
/**
|
||||
* AMCC SoC PPC4xx Crypto Driver
|
||||
*
|
||||
* Copyright (c) 2008 Applied Micro Circuits Corporation.
|
||||
* All rights reserved. James Hsiao <jhsiao@amcc.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This filr defines the register set for Security Subsystem
|
||||
*/
|
||||
|
||||
#ifndef __CRYPTO4XX_REG_DEF_H__
|
||||
#define __CRYPTO4XX_REG_DEF_H__
|
||||
|
||||
/* CRYPTO4XX Register offset */
|
||||
#define CRYPTO4XX_DESCRIPTOR 0x00000000
|
||||
#define CRYPTO4XX_CTRL_STAT 0x00000000
|
||||
#define CRYPTO4XX_SOURCE 0x00000004
|
||||
#define CRYPTO4XX_DEST 0x00000008
|
||||
#define CRYPTO4XX_SA 0x0000000C
|
||||
#define CRYPTO4XX_SA_LENGTH 0x00000010
|
||||
#define CRYPTO4XX_LENGTH 0x00000014
|
||||
|
||||
#define CRYPTO4XX_PE_DMA_CFG 0x00000040
|
||||
#define CRYPTO4XX_PE_DMA_STAT 0x00000044
|
||||
#define CRYPTO4XX_PDR_BASE 0x00000048
|
||||
#define CRYPTO4XX_RDR_BASE 0x0000004c
|
||||
#define CRYPTO4XX_RING_SIZE 0x00000050
|
||||
#define CRYPTO4XX_RING_CTRL 0x00000054
|
||||
#define CRYPTO4XX_INT_RING_STAT 0x00000058
|
||||
#define CRYPTO4XX_EXT_RING_STAT 0x0000005c
|
||||
#define CRYPTO4XX_IO_THRESHOLD 0x00000060
|
||||
#define CRYPTO4XX_GATH_RING_BASE 0x00000064
|
||||
#define CRYPTO4XX_SCAT_RING_BASE 0x00000068
|
||||
#define CRYPTO4XX_PART_RING_SIZE 0x0000006c
|
||||
#define CRYPTO4XX_PART_RING_CFG 0x00000070
|
||||
|
||||
#define CRYPTO4XX_PDR_BASE_UADDR 0x00000080
|
||||
#define CRYPTO4XX_RDR_BASE_UADDR 0x00000084
|
||||
#define CRYPTO4XX_PKT_SRC_UADDR 0x00000088
|
||||
#define CRYPTO4XX_PKT_DEST_UADDR 0x0000008c
|
||||
#define CRYPTO4XX_SA_UADDR 0x00000090
|
||||
#define CRYPTO4XX_GATH_RING_BASE_UADDR 0x000000A0
|
||||
#define CRYPTO4XX_SCAT_RING_BASE_UADDR 0x000000A4
|
||||
|
||||
#define CRYPTO4XX_SEQ_RD 0x00000408
|
||||
#define CRYPTO4XX_SEQ_MASK_RD 0x0000040C
|
||||
|
||||
#define CRYPTO4XX_SA_CMD_0 0x00010600
|
||||
#define CRYPTO4XX_SA_CMD_1 0x00010604
|
||||
|
||||
#define CRYPTO4XX_STATE_PTR 0x000106dc
|
||||
#define CRYPTO4XX_STATE_IV 0x00010700
|
||||
#define CRYPTO4XX_STATE_HASH_BYTE_CNT_0 0x00010710
|
||||
#define CRYPTO4XX_STATE_HASH_BYTE_CNT_1 0x00010714
|
||||
|
||||
#define CRYPTO4XX_STATE_IDIGEST_0 0x00010718
|
||||
#define CRYPTO4XX_STATE_IDIGEST_1 0x0001071c
|
||||
|
||||
#define CRYPTO4XX_DATA_IN 0x00018000
|
||||
#define CRYPTO4XX_DATA_OUT 0x0001c000
|
||||
|
||||
#define CRYPTO4XX_INT_UNMASK_STAT 0x000500a0
|
||||
#define CRYPTO4XX_INT_MASK_STAT 0x000500a4
|
||||
#define CRYPTO4XX_INT_EN 0x000500a8
|
||||
|
||||
#define CRYPTO4XX_INT_PKA 0x00000002
|
||||
#define CRYPTO4XX_INT_PDR_DONE 0x00008000
|
||||
#define CRYPTO4XX_INT_MA_WR_ERR 0x00020000
|
||||
#define CRYPTO4XX_INT_MA_RD_ERR 0x00010000
|
||||
#define CRYPTO4XX_INT_PE_ERR 0x00000200
|
||||
#define CRYPTO4XX_INT_USER_DMA_ERR 0x00000040
|
||||
#define CRYPTO4XX_INT_SLAVE_ERR 0x00000010
|
||||
#define CRYPTO4XX_INT_MASTER_ERR 0x00000008
|
||||
#define CRYPTO4XX_INT_ERROR 0x00030258
|
||||
|
||||
#define CRYPTO4XX_INT_CFG 0x000500ac
|
||||
#define CRYPTO4XX_INT_DESCR_RD 0x000500b0
|
||||
#define CRYPTO4XX_INT_DESCR_CNT 0x000500b4
|
||||
#define CRYPTO4XX_INT_TIMEOUT_CNT 0x000500b8
|
||||
|
||||
#define CRYPTO4XX_DEVICE_CTRL 0x00060080
|
||||
#define CRYPTO4XX_DEVICE_ID 0x00060084
|
||||
#define CRYPTO4XX_DEVICE_INFO 0x00060088
|
||||
#define CRYPTO4XX_DMA_USER_SRC 0x00060094
|
||||
#define CRYPTO4XX_DMA_USER_DEST 0x00060098
|
||||
#define CRYPTO4XX_DMA_USER_CMD 0x0006009C
|
||||
|
||||
#define CRYPTO4XX_DMA_CFG 0x000600d4
|
||||
#define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8
|
||||
#define CRYPTO4XX_ENDIAN_CFG 0x000600d8
|
||||
|
||||
#define CRYPTO4XX_PRNG_STAT 0x00070000
|
||||
#define CRYPTO4XX_PRNG_CTRL 0x00070004
|
||||
#define CRYPTO4XX_PRNG_SEED_L 0x00070008
|
||||
#define CRYPTO4XX_PRNG_SEED_H 0x0007000c
|
||||
|
||||
#define CRYPTO4XX_PRNG_RES_0 0x00070020
|
||||
#define CRYPTO4XX_PRNG_RES_1 0x00070024
|
||||
#define CRYPTO4XX_PRNG_RES_2 0x00070028
|
||||
#define CRYPTO4XX_PRNG_RES_3 0x0007002C
|
||||
|
||||
#define CRYPTO4XX_PRNG_LFSR_L 0x00070030
|
||||
#define CRYPTO4XX_PRNG_LFSR_H 0x00070034
|
||||
|
||||
/**
|
||||
* Initilize CRYPTO ENGINE registers, and memory bases.
|
||||
*/
|
||||
#define PPC4XX_PDR_POLL 0x3ff
|
||||
#define PPC4XX_OUTPUT_THRESHOLD 2
|
||||
#define PPC4XX_INPUT_THRESHOLD 2
|
||||
#define PPC4XX_PD_SIZE 6
|
||||
#define PPC4XX_CTX_DONE_INT 0x2000
|
||||
/*
|
||||
* in original kernel source PPC4XX_PD_DONE_INT was 0x8000
|
||||
* and no interrupts were happening, PPC460EX/EXr/GT manual states that
|
||||
* register CRYPTO4XX_INT_EN bit 15 (DESC) is:
|
||||
* "Specified number of Descriptors (1–63) have
|
||||
* completed processing. Also occurs if a Descriptor
|
||||
* has just been processed and there are no more
|
||||
* input Descriptors available.
|
||||
* but bit 14 (DESCRD) is described as:
|
||||
* "Command to the Packet Engine to fetch the next
|
||||
* Packet Descriptor from the PDR."
|
||||
* while for INT MASK/UNMASK registers mnemonics DESC for bit 15
|
||||
* and DESCRD for bit 14 are the same, but the descriptions are swapped
|
||||
* (probably this is copy paste bug in manual)
|
||||
*/
|
||||
#define PPC4XX_PD_DONE_INT 0x4000
|
||||
#define PPC4XX_BYTE_ORDER 0x22222
|
||||
#define PPC4XX_INTERRUPT_CLR 0x3ffff
|
||||
#define PPC4XX_PRNG_CTRL_AUTO_EN 0x3
|
||||
#define PPC4XX_DC_3DES_EN 1
|
||||
#define PPC4XX_INT_DESCR_CNT 1
|
||||
#define PPC4XX_INT_TIMEOUT_CNT 0
|
||||
#define PPC4XX_INT_CFG 1
|
||||
/**
|
||||
* all follow define are ad hoc
|
||||
*/
|
||||
#define PPC4XX_RING_RETRY 100
|
||||
#define PPC4XX_RING_POLL 100
|
||||
#define PPC4XX_SDR_SIZE PPC4XX_NUM_SD
|
||||
#define PPC4XX_GDR_SIZE PPC4XX_NUM_GD
|
||||
|
||||
/**
|
||||
* Generic Security Association (SA) with all possible fields. These will
|
||||
* never likely used except for reference purpose. These structure format
|
||||
* can be not changed as the hardware expects them to be layout as defined.
|
||||
* Field can be removed or reduced but ordering can not be changed.
|
||||
*/
|
||||
#define CRYPTO4XX_DMA_CFG_OFFSET 0x40
|
||||
union ce_pe_dma_cfg {
|
||||
struct {
|
||||
u32 rsv:7;
|
||||
u32 dir_host:1;
|
||||
u32 rsv1:2;
|
||||
u32 bo_td_en:1;
|
||||
u32 dis_pdr_upd:1;
|
||||
u32 bo_sgpd_en:1;
|
||||
u32 bo_data_en:1;
|
||||
u32 bo_sa_en:1;
|
||||
u32 bo_pd_en:1;
|
||||
u32 rsv2:4;
|
||||
u32 dynamic_sa_en:1;
|
||||
u32 pdr_mode:2;
|
||||
u32 pe_mode:1;
|
||||
u32 rsv3:5;
|
||||
u32 reset_sg:1;
|
||||
u32 reset_pdr:1;
|
||||
u32 reset_pe:1;
|
||||
} bf;
|
||||
u32 w;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define CRYPTO4XX_PDR_BASE_OFFSET 0x48
|
||||
#define CRYPTO4XX_RDR_BASE_OFFSET 0x4c
|
||||
#define CRYPTO4XX_RING_SIZE_OFFSET 0x50
|
||||
union ce_ring_size {
|
||||
struct {
|
||||
u32 ring_offset:16;
|
||||
u32 rsv:6;
|
||||
u32 ring_size:10;
|
||||
} bf;
|
||||
u32 w;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define CRYPTO4XX_RING_CONTROL_OFFSET 0x54
|
||||
union ce_ring_contol {
|
||||
struct {
|
||||
u32 continuous:1;
|
||||
u32 rsv:5;
|
||||
u32 ring_retry_divisor:10;
|
||||
u32 rsv1:4;
|
||||
u32 ring_poll_divisor:10;
|
||||
} bf;
|
||||
u32 w;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define CRYPTO4XX_IO_THRESHOLD_OFFSET 0x60
|
||||
union ce_io_threshold {
|
||||
struct {
|
||||
u32 rsv:6;
|
||||
u32 output_threshold:10;
|
||||
u32 rsv1:6;
|
||||
u32 input_threshold:10;
|
||||
} bf;
|
||||
u32 w;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define CRYPTO4XX_GATHER_RING_BASE_OFFSET 0x64
|
||||
#define CRYPTO4XX_SCATTER_RING_BASE_OFFSET 0x68
|
||||
|
||||
union ce_part_ring_size {
|
||||
struct {
|
||||
u32 sdr_size:16;
|
||||
u32 gdr_size:16;
|
||||
} bf;
|
||||
u32 w;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define MAX_BURST_SIZE_32 0
|
||||
#define MAX_BURST_SIZE_64 1
|
||||
#define MAX_BURST_SIZE_128 2
|
||||
#define MAX_BURST_SIZE_256 3
|
||||
|
||||
/* gather descriptor control length */
|
||||
struct gd_ctl_len {
|
||||
u32 len:16;
|
||||
u32 rsv:14;
|
||||
u32 done:1;
|
||||
u32 ready:1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ce_gd {
|
||||
u32 ptr;
|
||||
struct gd_ctl_len ctl_len;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sd_ctl {
|
||||
u32 ctl:30;
|
||||
u32 done:1;
|
||||
u32 rdy:1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ce_sd {
|
||||
u32 ptr;
|
||||
struct sd_ctl ctl;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define PD_PAD_CTL_32 0x10
|
||||
#define PD_PAD_CTL_64 0x20
|
||||
#define PD_PAD_CTL_128 0x40
|
||||
#define PD_PAD_CTL_256 0x80
|
||||
union ce_pd_ctl {
|
||||
struct {
|
||||
u32 pd_pad_ctl:8;
|
||||
u32 status:8;
|
||||
u32 next_hdr:8;
|
||||
u32 rsv:2;
|
||||
u32 cached_sa:1;
|
||||
u32 hash_final:1;
|
||||
u32 init_arc4:1;
|
||||
u32 rsv1:1;
|
||||
u32 pe_done:1;
|
||||
u32 host_ready:1;
|
||||
} bf;
|
||||
u32 w;
|
||||
} __attribute__((packed));
|
||||
|
||||
union ce_pd_ctl_len {
|
||||
struct {
|
||||
u32 bypass:8;
|
||||
u32 pe_done:1;
|
||||
u32 host_ready:1;
|
||||
u32 rsv:2;
|
||||
u32 pkt_len:20;
|
||||
} bf;
|
||||
u32 w;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ce_pd {
|
||||
union ce_pd_ctl pd_ctl;
|
||||
u32 src;
|
||||
u32 dest;
|
||||
u32 sa; /* get from ctx->sa_dma_addr */
|
||||
u32 sa_len; /* only if dynamic sa is used */
|
||||
union ce_pd_ctl_len pd_ctl_len;
|
||||
|
||||
} __attribute__((packed));
|
||||
#endif
|
||||
222
2025-03-19/crypto4xx/crypto4xx_sa.c
Normal file
222
2025-03-19/crypto4xx/crypto4xx_sa.c
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/**
|
||||
* AMCC SoC PPC4xx Crypto Driver
|
||||
*
|
||||
* Copyright (c) 2008 Applied Micro Circuits Corporation.
|
||||
* All rights reserved. James Hsiao <jhsiao@amcc.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @file crypto4xx_sa.c
|
||||
*
|
||||
* This file implements the security context
|
||||
* assoicate format.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock_types.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <crypto/des.h>
|
||||
#include "crypto4xx_reg_def.h"
|
||||
#include "crypto4xx_sa.h"
|
||||
#include "crypto4xx_core.h"
|
||||
|
||||
u32 get_dynamic_sa_offset_iv_field(struct crypto4xx_ctx_base *ctx)
|
||||
{
|
||||
u32 offset;
|
||||
union dynamic_sa_contents cts;
|
||||
|
||||
if (ctx->direction == DIR_INBOUND)
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
|
||||
else
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
|
||||
offset = cts.bf.key_size
|
||||
+ cts.bf.inner_size
|
||||
+ cts.bf.outer_size
|
||||
+ cts.bf.spi
|
||||
+ cts.bf.seq_num0
|
||||
+ cts.bf.seq_num1
|
||||
+ cts.bf.seq_num_mask0
|
||||
+ cts.bf.seq_num_mask1
|
||||
+ cts.bf.seq_num_mask2
|
||||
+ cts.bf.seq_num_mask3;
|
||||
|
||||
return sizeof(struct dynamic_sa_ctl) + offset * 4;
|
||||
}
|
||||
|
||||
u32 get_dynamic_sa_offset_state_ptr_field(struct crypto4xx_ctx_base *ctx)
|
||||
{
|
||||
u32 offset;
|
||||
union dynamic_sa_contents cts;
|
||||
|
||||
if (ctx->direction == DIR_INBOUND)
|
||||
cts.w = ((struct dynamic_sa_ctl *) ctx->sa_in)->sa_contents;
|
||||
else
|
||||
cts.w = ((struct dynamic_sa_ctl *) ctx->sa_out)->sa_contents;
|
||||
offset = cts.bf.key_size
|
||||
+ cts.bf.inner_size
|
||||
+ cts.bf.outer_size
|
||||
+ cts.bf.spi
|
||||
+ cts.bf.seq_num0
|
||||
+ cts.bf.seq_num1
|
||||
+ cts.bf.seq_num_mask0
|
||||
+ cts.bf.seq_num_mask1
|
||||
+ cts.bf.seq_num_mask2
|
||||
+ cts.bf.seq_num_mask3
|
||||
+ cts.bf.iv0
|
||||
+ cts.bf.iv1
|
||||
+ cts.bf.iv2
|
||||
+ cts.bf.iv3;
|
||||
|
||||
return sizeof(struct dynamic_sa_ctl) + offset * 4;
|
||||
}
|
||||
|
||||
u32 get_dynamic_sa_offset_arc4_state_ptr(struct crypto4xx_ctx_base *ctx)
|
||||
{
|
||||
u32 offset;
|
||||
union dynamic_sa_contents cts;
|
||||
|
||||
if (ctx->direction == DIR_INBOUND)
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
|
||||
else
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
|
||||
offset = cts.bf.key_size
|
||||
+ cts.bf.inner_size
|
||||
+ cts.bf.outer_size
|
||||
+ cts.bf.spi
|
||||
+ cts.bf.seq_num0
|
||||
+ cts.bf.seq_num1
|
||||
+ cts.bf.seq_num_mask0
|
||||
+ cts.bf.seq_num_mask1
|
||||
+ cts.bf.seq_num_mask2
|
||||
+ cts.bf.seq_num_mask3
|
||||
+ cts.bf.iv0
|
||||
+ cts.bf.iv1
|
||||
+ cts.bf.iv2
|
||||
+ cts.bf.iv3
|
||||
+ cts.bf.state_ptr
|
||||
+ cts.bf.arc4_ij_ptr;
|
||||
|
||||
return sizeof(struct dynamic_sa_ctl) + offset * 4;
|
||||
}
|
||||
|
||||
u32 get_dynamic_sa_offset_inner_digest(struct crypto4xx_ctx_base *ctx)
|
||||
{
|
||||
u32 offset;
|
||||
union dynamic_sa_contents cts;
|
||||
|
||||
if (ctx->direction == DIR_INBOUND)
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
|
||||
else
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
|
||||
offset = cts.bf.key_size;
|
||||
|
||||
return sizeof(struct dynamic_sa_ctl) + offset * 4;
|
||||
}
|
||||
|
||||
u32 get_dynamic_sa_offset_outer_digest(struct crypto4xx_ctx_base *ctx)
|
||||
{
|
||||
u32 offset;
|
||||
union dynamic_sa_contents cts;
|
||||
|
||||
if (ctx->direction == DIR_INBOUND)
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
|
||||
else
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
|
||||
|
||||
offset = cts.bf.key_size
|
||||
+ cts.bf.inner_size;
|
||||
|
||||
return sizeof(struct dynamic_sa_ctl) + offset * 4;
|
||||
}
|
||||
|
||||
u32 get_dynamic_sa_offset_spi(struct crypto4xx_ctx_base *ctx)
|
||||
{
|
||||
u32 offset;
|
||||
union dynamic_sa_contents cts;
|
||||
|
||||
if (ctx->direction == DIR_INBOUND)
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
|
||||
else
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
|
||||
|
||||
offset = cts.bf.key_size
|
||||
+ cts.bf.inner_size
|
||||
+ cts.bf.outer_size;
|
||||
|
||||
return sizeof(struct dynamic_sa_ctl) + offset * 4;
|
||||
}
|
||||
|
||||
u32 get_dynamic_sa_offset_seq_num(struct crypto4xx_ctx_base *ctx)
|
||||
{
|
||||
u32 offset;
|
||||
union dynamic_sa_contents cts;
|
||||
|
||||
if (ctx->direction == DIR_INBOUND)
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
|
||||
else
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
|
||||
|
||||
offset = cts.bf.key_size
|
||||
+ cts.bf.inner_size
|
||||
+ cts.bf.outer_size
|
||||
+ cts.bf.spi;
|
||||
return sizeof(struct dynamic_sa_ctl) + offset * 4;
|
||||
}
|
||||
|
||||
u32 get_dynamic_sa_offset_seq_num_mask(struct crypto4xx_ctx_base *ctx)
|
||||
{
|
||||
u32 offset;
|
||||
union dynamic_sa_contents cts;
|
||||
|
||||
if (ctx->direction == DIR_INBOUND)
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
|
||||
else
|
||||
cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
|
||||
|
||||
offset = cts.bf.key_size
|
||||
+ cts.bf.inner_size
|
||||
+ cts.bf.outer_size
|
||||
+ cts.bf.spi
|
||||
+ cts.bf.seq_num0
|
||||
+ cts.bf.seq_num1;
|
||||
|
||||
return sizeof(struct dynamic_sa_ctl) + offset * 4;
|
||||
}
|
||||
|
||||
u32 get_dynamic_sa_iv_size(struct crypto4xx_ctx_base *ctx)
|
||||
{
|
||||
union dynamic_sa_contents cts;
|
||||
|
||||
if (ctx->direction == DIR_INBOUND)
|
||||
cts.w = ((struct dynamic_sa_ctl *) ctx->sa_in)->sa_contents;
|
||||
else
|
||||
cts.w = ((struct dynamic_sa_ctl *) ctx->sa_out)->sa_contents;
|
||||
|
||||
return (cts.bf.iv0 + cts.bf.iv1 + cts.bf.iv2 + cts.bf.iv3) * 4;
|
||||
}
|
||||
|
||||
u32 get_dynamic_sa_offset_key_field(struct crypto4xx_ctx_base *ctx)
|
||||
{
|
||||
union dynamic_sa_contents cts;
|
||||
|
||||
if (ctx->direction == DIR_INBOUND)
|
||||
cts.w = ((struct dynamic_sa_ctl *) ctx->sa_in)->sa_contents;
|
||||
else
|
||||
cts.w = ((struct dynamic_sa_ctl *) ctx->sa_out)->sa_contents;
|
||||
|
||||
return sizeof(struct dynamic_sa_ctl);
|
||||
}
|
||||
566
2025-03-19/crypto4xx/crypto4xx_sa.h
Normal file
566
2025-03-19/crypto4xx/crypto4xx_sa.h
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
/**
|
||||
* AMCC SoC PPC4xx Crypto Driver
|
||||
*
|
||||
* Copyright (c) 2008 Applied Micro Circuits Corporation.
|
||||
* All rights reserved. James Hsiao <jhsiao@amcc.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This file defines the security context
|
||||
* assoicate format.
|
||||
*/
|
||||
|
||||
#ifndef __CRYPTO4XX_SA_H__
|
||||
#define __CRYPTO4XX_SA_H__
|
||||
|
||||
#define AES_IV_SIZE 16
|
||||
|
||||
/**
|
||||
* Contents of Dynamic Security Association (SA) with all possible fields
|
||||
*/
|
||||
union dynamic_sa_contents {
|
||||
struct {
|
||||
u32 arc4_state_ptr:1;
|
||||
u32 arc4_ij_ptr:1;
|
||||
u32 state_ptr:1;
|
||||
u32 iv3:1;
|
||||
u32 iv2:1;
|
||||
u32 iv1:1;
|
||||
u32 iv0:1;
|
||||
u32 seq_num_mask3:1;
|
||||
u32 seq_num_mask2:1;
|
||||
u32 seq_num_mask1:1;
|
||||
u32 seq_num_mask0:1;
|
||||
u32 seq_num1:1;
|
||||
u32 seq_num0:1;
|
||||
u32 spi:1;
|
||||
u32 outer_size:5;
|
||||
u32 inner_size:5;
|
||||
u32 key_size:4;
|
||||
u32 cmd_size:4;
|
||||
} bf;
|
||||
u32 w;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SA_OPCODE_ESP 0
|
||||
#define SA_OPCODE_AH 1
|
||||
#define SA_OPCODE_SSL 4
|
||||
#define SA_OPCODE_TLS 5
|
||||
#define SA_OPCODE_SRTP 7
|
||||
#define SA_OPCODE_DTLS 1
|
||||
#define SA_OPCODE_TLS1_1 6
|
||||
|
||||
#define SA_OP_GROUP_BASIC 0
|
||||
#define SA_OP_GROUP_PROTOCOL 1
|
||||
#define SA_OP_GROUP_EXTEND_PROTOCOL 3
|
||||
|
||||
#define SA_OPCODE_EXT_PROT_DTLS 1
|
||||
#define SA_OPCODE_EXT_PROT_MACSEC 2
|
||||
#define SA_OPCODE_EXT_PROT_SSL 4
|
||||
#define SA_OPCODE_EXT_PROT_TLS10 5
|
||||
#define SA_OPCODE_EXT_PROT_TLS11 6
|
||||
|
||||
#define DIR_OUTBOUND 0
|
||||
#define DIR_INBOUND 1
|
||||
#define SA_OPCODE_ENCRYPT 0
|
||||
#define SA_OPCODE_DECRYPT 0
|
||||
#define SA_OPCODE_ENCRYPT_HASH 1
|
||||
#define SA_OPCODE_HASH_DECRYPT 1
|
||||
#define SA_OPCODE_HASH 3
|
||||
#define SA_OPCODE_HASH_ENCRYPT 4
|
||||
#define SA_OPCODE_DECRYPT_HASH 4
|
||||
|
||||
#define SA_OPCODE_ESP 0
|
||||
#define SA_OPCODE_AH 1
|
||||
#define SA_OPCODE_SSL 4
|
||||
#define SA_OPCODE_TLS 5
|
||||
#define SA_OPCODE_SRTP 7
|
||||
#define SA_OPCODE_DTLS 1
|
||||
#define SA_OPCODE_TLS1_1 6
|
||||
|
||||
#define SA_CIPHER_ALG_DES 0
|
||||
#define SA_CIPHER_ALG_3DES 1
|
||||
#define SA_CIPHER_ALG_ARC4 2
|
||||
#define SA_CIPHER_ALG_AES 3
|
||||
#define SA_CIPHER_ALG_KASUMI 4
|
||||
#define SA_CIPHER_ALG_NULL 15
|
||||
|
||||
#define SA_HASH_ALG_MD5 0
|
||||
#define SA_HASH_ALG_SHA1 1
|
||||
#define SA_HASH_ALG_SHA224 2
|
||||
#define SA_HASH_ALG_SHA256 3
|
||||
#define SA_HASH_ALG_SHA384 4
|
||||
#define SA_HASH_ALG_SHA512 5
|
||||
#define HASH_ALG_MAX_CNT 6
|
||||
#define SA_HASH_ALG_AES_XCBC_MAC_128 8
|
||||
#define SA_HASH_ALG_KASUMI_f9 9
|
||||
#define SA_HASH_ALG_GHASH 12
|
||||
#define SA_HASH_ALG_GMAC 13
|
||||
#define SA_HASH_ALG_CBC_MAC 14
|
||||
#define SA_HASH_ALG_NULL 15
|
||||
|
||||
#define SA_LOAD_HASH_FROM_SA 0
|
||||
#define SA_LOAD_HASH_FROM_STATE 2
|
||||
#define SA_NOT_LOAD_HASH 3
|
||||
#define SA_LOAD_IV_FROM_SA 0
|
||||
#define SA_LOAD_IV_FROM_INPUT 1
|
||||
#define SA_LOAD_IV_FROM_STATE 2
|
||||
#define SA_LOAD_IV_GEN_IV 3
|
||||
|
||||
#define SA_PAD_TYPE_CONSTANT 2
|
||||
#define SA_PAD_TYPE_ZERO 3
|
||||
#define SA_PAD_TYPE_TLS 5
|
||||
#define SA_PAD_TYPE_DTLS 5
|
||||
#define SA_NOT_SAVE_HASH 0
|
||||
#define SA_SAVE_HASH 1
|
||||
#define SA_NOT_SAVE_IV 0
|
||||
#define SA_SAVE_IV 1
|
||||
#define SA_HEADER_PROC 1
|
||||
#define SA_NO_HEADER_PROC 0
|
||||
|
||||
#define SA_HASH_ALG_MD5_DIGEST_SIZE 16
|
||||
#define SA_HASH_ALG_SHA1_DIGEST_SIZE 20
|
||||
#define SA_HASH_ALG_SHA224_DIGEST_SIZE 28
|
||||
#define SA_HASH_ALG_SHA256_DIGEST_SIZE 32
|
||||
#define SA_HASH_ALG_SHA384_DIGEST_SIZE 48
|
||||
#define SA_HASH_ALG_SHA512_DIGEST_SIZE 64
|
||||
|
||||
|
||||
#define CRYPTO4XX_MAC_ALGS { "md5", "sha1", \
|
||||
"sha224", "sha256", "sha384", "sha512" }
|
||||
union sa_command_0 {
|
||||
struct {
|
||||
u32 scatter:1;
|
||||
u32 gather:1;
|
||||
u32 save_hash_state:1;
|
||||
u32 save_iv:1;
|
||||
u32 load_hash_state:2;
|
||||
u32 load_iv:2;
|
||||
u32 digest_len:4;
|
||||
u32 hdr_proc:1;
|
||||
u32 extend_pad:1;
|
||||
u32 stream_cipher_pad:1;
|
||||
u32 rsv:1;
|
||||
u32 hash_alg:4;
|
||||
u32 cipher_alg:4;
|
||||
u32 pad_type:2;
|
||||
u32 op_group:2;
|
||||
u32 dir:1;
|
||||
u32 opcode:3;
|
||||
} bf;
|
||||
u32 w;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define CRYPTO_MODE_ECB 0
|
||||
#define CRYPTO_MODE_KASUMI 0
|
||||
#define CRYPTO_MODE_CBC 1
|
||||
#define CRYPTO_MODE_OFB 2
|
||||
#define CRYPTO_MODE_CFB 3
|
||||
#define CRYPTO_MODE_AES_CTR 4
|
||||
#define CRYPTO_MODE_KASUMI_f8 4
|
||||
#define CRYPTO_MODE_AES_ICM 5
|
||||
|
||||
#define CRYPTO_FEEDBACK_MODE_NO_FB 0
|
||||
#define CRYPTO_FEEDBACK_MODE_64BIT_OFB 0
|
||||
#define CRYPTO_FEEDBACK_MODE_8BIT_CFB 1
|
||||
#define CRYPTO_FEEDBACK_MODE_1BIT_CFB 2
|
||||
#define CRYPTO_FEEDBACK_MODE_128BIT_CFB 3
|
||||
|
||||
#define SA_AES_KEY_LEN_128 2
|
||||
#define SA_AES_KEY_LEN_192 3
|
||||
#define SA_AES_KEY_LEN_256 4
|
||||
|
||||
#define SA_REV2 1
|
||||
/*
|
||||
* The follow defines bits sa_command_1
|
||||
* In Basic hash mode this bit define simple hash or hmac.
|
||||
* In IPsec mode, this bit define muting control.
|
||||
*/
|
||||
#define SA_HASH_MODE_HASH 0
|
||||
#define SA_HASH_MODE_HMAC 1
|
||||
#define SA_MC_ENABLE 0
|
||||
#define SA_MC_DISABLE 1
|
||||
#define SA_NOT_COPY_HDR 0
|
||||
#define SA_COPY_HDR 1
|
||||
#define SA_NOT_COPY_PAD 0
|
||||
#define SA_COPY_PAD 1
|
||||
#define SA_NOT_COPY_PAYLOAD 0
|
||||
#define SA_COPY_PAYLOAD 1
|
||||
#define SA_EXTENDED_SN_OFF 0
|
||||
#define SA_EXTENDED_SN_ON 1
|
||||
#define SA_SEQ_MASK_OFF 0
|
||||
#define SA_SEQ_MASK_ON 1
|
||||
|
||||
union sa_command_1 {
|
||||
struct {
|
||||
u32 crypto_mode31:1;
|
||||
u32 save_arc4_state:1;
|
||||
u32 arc4_stateful:1;
|
||||
u32 key_len:5;
|
||||
u32 hash_crypto_offset:8;
|
||||
u32 sa_rev:2;
|
||||
u32 byte_offset:1;
|
||||
u32 hmac_muting:1;
|
||||
u32 feedback_mode:2;
|
||||
u32 crypto_mode9_8:2;
|
||||
u32 extended_seq_num:1;
|
||||
u32 seq_num_mask:1;
|
||||
u32 mutable_bit_proc:1;
|
||||
u32 ip_version:1;
|
||||
u32 copy_pad:1;
|
||||
u32 copy_payload:1;
|
||||
u32 copy_hdr:1;
|
||||
u32 rsv1:1;
|
||||
} bf;
|
||||
u32 w;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dynamic_sa_ctl {
|
||||
u32 sa_contents;
|
||||
union sa_command_0 sa_command_0;
|
||||
union sa_command_1 sa_command_1;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* State Record for Security Association (SA)
|
||||
*/
|
||||
struct sa_state_record {
|
||||
u32 save_iv[4];
|
||||
u32 save_hash_byte_cnt[2];
|
||||
u32 save_digest[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* Arc4 State Record for Security Association (SA)
|
||||
*/
|
||||
struct arc4_sr {
|
||||
u32 arc4_state[64];
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* Security Association (SA) for DES
|
||||
*/
|
||||
struct dynamic_sa_des {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[2];
|
||||
u32 iv[2];
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_DES_LEN (sizeof(struct dynamic_sa_des)/4)
|
||||
#define SA_DES_CONTENTS 0x26000022
|
||||
|
||||
/**
|
||||
* Security Association (SA) for 3DES
|
||||
*/
|
||||
struct dynamic_sa_3des {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[6];
|
||||
u32 iv[2]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_3DES_LEN (sizeof(struct dynamic_sa_3des)/4)
|
||||
#define SA_3DES_CONTENTS 0x26000062
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES128
|
||||
*
|
||||
*/
|
||||
struct dynamic_sa_aes128 {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[4];
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_AES128_LEN (sizeof(struct dynamic_sa_aes128)/4)
|
||||
#define SA_AES128_CONTENTS 0x3e000042
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES192
|
||||
*/
|
||||
struct dynamic_sa_aes192 {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[6];
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_AES192_LEN (sizeof(struct dynamic_sa_aes192)/4)
|
||||
#define SA_AES192_CONTENTS 0x3e000062
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES256
|
||||
*/
|
||||
struct dynamic_sa_aes256 {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[8];
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SA_AES256_LEN (sizeof(struct dynamic_sa_aes256)/4)
|
||||
#define SA_AES256_CONTENTS 0x3e000082
|
||||
#define SA_AES_CONTENTS 0x3e000002
|
||||
|
||||
/**
|
||||
* Security Association (SA) for HASH128: HMAC-MD5
|
||||
*/
|
||||
struct dynamic_sa_hash128 {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 inner_digest[4];
|
||||
u32 outer_digest[4];
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_HASH128_LEN (sizeof(struct dynamic_sa_hash128)/4)
|
||||
#define SA_HASH128_CONTENTS 0x20008402
|
||||
|
||||
/**
|
||||
* Security Association (SA) for HASH160: HMAC-SHA1
|
||||
*/
|
||||
struct dynamic_sa_hash160 {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 inner_digest[5];
|
||||
u32 outer_digest[5];
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_HASH160_LEN (sizeof(struct dynamic_sa_hash160)/4)
|
||||
#define SA_HASH160_CONTENTS 0x2000a502
|
||||
|
||||
/**
|
||||
* Security Association (SA) for HASH256: HMAC-SHA224, HMAC-SHA256
|
||||
*/
|
||||
struct dynamic_sa_hash256 {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 inner_digest[8];
|
||||
u32 outer_digest[8];
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_HASH256_LEN (sizeof(struct dynamic_sa_hash256)/4)
|
||||
#define SA_HASH256_CONTENTS 0x20010802
|
||||
|
||||
/*
|
||||
* Security Association (SA) for HASH512: HMAC-SHA512
|
||||
*/
|
||||
struct dynamic_sa_hash512 {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 inner_digest[16];
|
||||
u32 outer_digest[16];
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_HASH512_LEN (sizeof(struct dynamic_sa_hash512)/4)
|
||||
#define SA_HASH512_CONTENTS 0x20021002
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES128_XCBC_MAC
|
||||
*/
|
||||
struct dynamic_sa_aes128_xcbc_mac {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[4];
|
||||
u32 inner_digest[8];
|
||||
u32 outer_digest[8];
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_AES128_XCBC_MAC_LEN (sizeof(struct dynamic_sa_aes128_xcbc_mac)/4)
|
||||
#define SA_AES128_XCBC_MAC_CONTENTS 0x3e010842
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES128_GCM
|
||||
*/
|
||||
struct dynamic_sa_aes128_gcm {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[4];
|
||||
u32 inner_digest[4];
|
||||
u32 outer_digest[4];
|
||||
u32 spi;
|
||||
u32 seq;
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_AES128_GCM_LEN (sizeof(struct dynamic_sa_aes128_gcm)/4)
|
||||
#define SA_AES128_GCM_CONTENTS 0x3e0c8442
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES192_XCBC_MAC
|
||||
*/
|
||||
struct dynamic_sa_aes192_xcbc_mac {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[6];
|
||||
u32 inner_digest[8];
|
||||
u32 outer_digest[8];
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_AES192_XCBC_MAC_LEN (sizeof(struct dynamic_sa_aes192_xcbc_mac)/4)
|
||||
#define SA_AES192_XCBC_MAC_CONTENTS 0x3e010862
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES192_GCM
|
||||
*/
|
||||
struct dynamic_sa_aes192_gcm {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[6];
|
||||
u32 inner_digest[4];
|
||||
u32 outer_digest[4];
|
||||
u32 spi;
|
||||
u32 seq;
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_AES192_GCM_LEN (sizeof(struct dynamic_sa_aes192_gcm)/4)
|
||||
#define SA_AES192_GCM_CONTENTS 0x3e0c8462
|
||||
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES256_XCBC_MAC
|
||||
*/
|
||||
struct dynamic_sa_aes256_xcbc_mac {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[8];
|
||||
u32 inner_digest[8];
|
||||
u32 outer_digest[8];
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_AES256_XCBC_MAC_LEN (sizeof(struct dynamic_sa_aes256_xcbc_mac)/4)
|
||||
#define SA_AES256_XCBC_MAC_CONTENTS 0x3e010882
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES256_GCM
|
||||
*/
|
||||
struct dynamic_sa_aes256_gcm {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[8];
|
||||
u32 inner_digest[4];
|
||||
u32 outer_digest[4];
|
||||
u32 spi;
|
||||
u32 seq;
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_AES256_GCM_LEN (sizeof(struct dynamic_sa_aes256_gcm)/4)
|
||||
#define SA_AES256_GCM_CONTENTS 0x3e0c8482
|
||||
#define SA_AES_GCM_CONTENTS 0x3e0c8402
|
||||
|
||||
/**
|
||||
* Security Association (SA) for Kasumi
|
||||
*/
|
||||
struct dynamic_sa_kasumi {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[4];
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_KASUMI_LEN (sizeof(struct dynamic_sa_kasumi)/4)
|
||||
#define SA_KASUMI_CONTENTS 0x20000042
|
||||
|
||||
/**
|
||||
* Security Association (SA) for Kasumi f8
|
||||
*/
|
||||
struct dynamic_sa_kasumi_f8 {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[4];
|
||||
u32 iv[2];
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_KASUMI_F8_LEN (sizeof(struct dynamic_sa_kasumi_f8)/4)
|
||||
#define SA_KASUMI_F8_CONTENTS 0x26000042
|
||||
|
||||
#define KASUMI_BLOCK_SIZE 8
|
||||
#define KASUMI_KEY_SIZE 16
|
||||
|
||||
/**
|
||||
* Security Association (SA) for Kasumi f8
|
||||
*/
|
||||
struct dynamic_sa_kasumi_f9 {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 inner_digest[4];
|
||||
u32 outter_digest[3];
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_KASUMI_F9_LEN (sizeof(struct dynamic_sa_kasumi_f9)/4)
|
||||
#define SA_KASUMI_F9_CONTENTS 0x20006402
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES256 CCM
|
||||
*/
|
||||
struct dynamic_sa_aes256_ccm {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[8];
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_AES256_CCM_LEN (sizeof(struct dynamic_sa_aes256_ccm)/4)
|
||||
#define SA_AES256_CCM_CONTENTS 0x3e000082
|
||||
#define SA_AES_CCM_CONTENTS 0x3e000002
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES192 CCM
|
||||
*/
|
||||
struct dynamic_sa_aes192_ccm {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[6];
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_AES192_CCM_LEN (sizeof(struct dynamic_sa_aes192_ccm)/4)
|
||||
#define SA_AES192_CCM_CONTENTS 0x3e000062
|
||||
|
||||
/**
|
||||
* Security Association (SA) for AES128 CCM
|
||||
*/
|
||||
struct dynamic_sa_aes128_ccm {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[4];
|
||||
u32 iv[4]; /* for CBC, OFC, and CFB mode */
|
||||
u32 state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_AES128_CCM_LEN (sizeof(struct dynamic_sa_aes128_ccm)/4)
|
||||
#define SA_AES128_CCM_CONTENTS 0x3e000042
|
||||
|
||||
/**
|
||||
* Security Association (SA) for ARC4
|
||||
*/
|
||||
struct arc4_ij_ptr {
|
||||
u32 rsv:16;
|
||||
u32 j:8;
|
||||
u32 i:8;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dynamic_sa_arc4 {
|
||||
struct dynamic_sa_ctl ctrl;
|
||||
u32 key[4];
|
||||
struct arc4_ij_ptr ij;
|
||||
u32 arc4_state_ptr;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
#define SA_ARC4_LEN (sizeof(struct dynamic_sa_arc4)/4)
|
||||
#define SA_ARC4_CONTENTS 0xc0000042
|
||||
|
||||
#endif
|
||||
29
2025-03-19/dakota_mmc/Makefile
Normal file
29
2025-03-19/dakota_mmc/Makefile
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
MODULE = arm/dakota_mmc.ko
|
||||
|
||||
dakota_mmc_FILES = sdhci.c sdhci-pltfm.c sdhci-msm.c
|
||||
dakota_mmc_PREFIX = drivers/mmc/host
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
|
||||
EXTRA_CFLAGS := $(CFLAGS)
|
||||
|
||||
define moddef
|
||||
obj-m += $(1).o
|
||||
ifneq ($(1).o, $(2))
|
||||
$(1)-y := $(2)
|
||||
EXTRA_CFLAGS += $($(1)_CFLAGS)
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach m, $(MODULE), $(eval $(call moddef,$(m:.ko=),$($(m:.ko=)_FILES:.c=.o))))
|
||||
|
||||
EXTRA_CFLAGS := $(subst -I, -I$(src)/, $(EXTRA_CFLAGS))
|
||||
|
||||
else
|
||||
|
||||
KERNELDIR := /lib/modules/$$(uname -r)/build
|
||||
|
||||
all::
|
||||
$(MAKE) -C $(KERNELDIR) M=$$(pwd) $@
|
||||
|
||||
endif
|
||||
916
2025-03-19/dakota_mmc/sdhci-msm.c
Normal file
916
2025-03-19/dakota_mmc/sdhci-msm.c
Normal file
|
|
@ -0,0 +1,916 @@
|
|||
/*
|
||||
* drivers/mmc/host/sdhci-msm.c - Qualcomm SDHCI Platform driver
|
||||
*
|
||||
* Copyright (c) 2013-2014, The Linux Foundation. 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 version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <mach/clk-provider-dk.h>
|
||||
#include "sdhci-pltfm.h"
|
||||
|
||||
|
||||
#define CORE_HC_MODE 0x78
|
||||
#define HC_MODE_EN 0x1
|
||||
#define CORE_POWER 0x0
|
||||
#define CORE_SW_RST BIT(7)
|
||||
#define CORE_HC_SELECT_IN_EN (1 << 18)
|
||||
#define CORE_HC_SELECT_IN_MASK (7 << 19)
|
||||
|
||||
#define MAX_PHASES 16
|
||||
#define CORE_DLL_LOCK BIT(7)
|
||||
#define CORE_DLL_EN BIT(16)
|
||||
#define CORE_CDR_EN BIT(17)
|
||||
#define CORE_CK_OUT_EN BIT(18)
|
||||
#define CORE_CDR_EXT_EN BIT(19)
|
||||
#define CORE_DLL_PDN BIT(29)
|
||||
#define CORE_DLL_RST BIT(30)
|
||||
#define CORE_DLL_CONFIG 0x100
|
||||
#define CORE_DLL_STATUS 0x108
|
||||
#define CORE_DLL_CONFIG2 0x1b4
|
||||
#define CORE_DLL_CLK_DISABLE BIT(21)
|
||||
|
||||
#define CORE_VENDOR_SPEC 0x10c
|
||||
#define CORE_CLK_PWRSAVE BIT(1)
|
||||
|
||||
#define VENDOR_CAPS0 0x11c
|
||||
#define VOLTS_SUPP_1_8V BIT(26)
|
||||
#define VOLTS_SUPP_3_0V BIT(25)
|
||||
|
||||
#define VENDOR_CAPS1 0x120
|
||||
#define CAPS_SDR_104_SUPPORT BIT(1)
|
||||
|
||||
#define CDR_SELEXT_SHIFT 20
|
||||
#define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)
|
||||
#define CMUX_SHIFT_PHASE_SHIFT 24
|
||||
#define CMUX_SHIFT_PHASE_MASK (7 << CMUX_SHIFT_PHASE_SHIFT)
|
||||
#define SDHCI_RETUNING_MODE BIT(15)
|
||||
#define SDHCI_ASYNC_INT_SUPPORT BIT(29)
|
||||
#define SDHCI_SYS_BUS_SUPPORT_64_BIT BIT(28)
|
||||
#define SDHCI_HS_SUPPORT BIT(21)
|
||||
#define SDHCI_ADMA2_SUPPORT BIT(19)
|
||||
#define SDHCI_SUPPORT_8_BIT BIT(18)
|
||||
#define SDHCI_MAX_BLK_LENGTH BIT(16)
|
||||
#define SDHCI_BASE_SDCLK_FREQ 0xc800
|
||||
#define SDHCI_TIMEOUT_CLK_FREQ 0xb2
|
||||
|
||||
static const u32 tuning_block_64[] = {
|
||||
0x00ff0fff, 0xccc3ccff, 0xffcc3cc3, 0xeffefffe,
|
||||
0xddffdfff, 0xfbfffbff, 0xff7fffbf, 0xefbdf777,
|
||||
0xf0fff0ff, 0x3cccfc0f, 0xcfcc33cc, 0xeeffefff,
|
||||
0xfdfffdff, 0xffbfffdf, 0xfff7ffbb, 0xde7b7ff7
|
||||
};
|
||||
|
||||
static const u32 tuning_block_128[] = {
|
||||
0xff00ffff, 0x0000ffff, 0xccccffff, 0xcccc33cc,
|
||||
0xcc3333cc, 0xffffcccc, 0xffffeeff, 0xffeeeeff,
|
||||
0xffddffff, 0xddddffff, 0xbbffffff, 0xbbffffff,
|
||||
0xffffffbb, 0xffffff77, 0x77ff7777, 0xffeeddbb,
|
||||
0x00ffffff, 0x00ffffff, 0xccffff00, 0xcc33cccc,
|
||||
0x3333cccc, 0xffcccccc, 0xffeeffff, 0xeeeeffff,
|
||||
0xddffffff, 0xddffffff, 0xffffffdd, 0xffffffbb,
|
||||
0xffffbbbb, 0xffff77ff, 0xff7777ff, 0xeeddbb77
|
||||
};
|
||||
|
||||
struct sdhci_msm_host {
|
||||
struct platform_device *pdev;
|
||||
void __iomem *core_mem; /* MSM SDCC mapped address */
|
||||
struct clk *clk; /* main SD/MMC bus clock */
|
||||
struct clk *pclk; /* SDHC peripheral bus clock */
|
||||
struct clk *bus_clk; /* SDHC bus voter clock */
|
||||
struct mmc_host *mmc;
|
||||
struct sdhci_pltfm_data sdhci_msm_pdata;
|
||||
bool emulation;
|
||||
int irq;
|
||||
};
|
||||
|
||||
/* Platform specific tuning */
|
||||
static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll)
|
||||
{
|
||||
u32 wait_cnt = 50;
|
||||
u8 ck_out_en;
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
|
||||
/* Poll for CK_OUT_EN bit. max. poll time = 50us */
|
||||
ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
|
||||
CORE_CK_OUT_EN);
|
||||
|
||||
while (ck_out_en != poll) {
|
||||
if (--wait_cnt == 0) {
|
||||
dev_err(mmc_dev(mmc), "%s: CK_OUT_EN bit is not %d\n",
|
||||
mmc_hostname(mmc), poll);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
udelay(1);
|
||||
|
||||
ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
|
||||
CORE_CK_OUT_EN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
|
||||
{
|
||||
int rc;
|
||||
static const u8 grey_coded_phase_table[] = {
|
||||
0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
|
||||
0xc, 0xd, 0xf, 0xe, 0xa, 0xb, 0x9, 0x8
|
||||
};
|
||||
unsigned long flags;
|
||||
u32 config;
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
|
||||
config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN);
|
||||
config |= (CORE_CDR_EXT_EN | CORE_DLL_EN);
|
||||
writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
||||
|
||||
/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */
|
||||
rc = msm_dll_poll_ck_out_en(host, 0);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
|
||||
/*
|
||||
* Write the selected DLL clock output phase (0 ... 15)
|
||||
* to CDR_SELEXT bit field of DLL_CONFIG register.
|
||||
*/
|
||||
config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
|
||||
config &= ~CDR_SELEXT_MASK;
|
||||
config |= grey_coded_phase_table[phase] << CDR_SELEXT_SHIFT;
|
||||
writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
||||
|
||||
/* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
|
||||
| CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
|
||||
|
||||
/* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */
|
||||
rc = msm_dll_poll_ck_out_en(host, 1);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
|
||||
config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
|
||||
config |= CORE_CDR_EN;
|
||||
config &= ~CORE_CDR_EXT_EN;
|
||||
writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
||||
goto out;
|
||||
|
||||
err_out:
|
||||
dev_err(mmc_dev(mmc), "%s: Failed to set DLL phase: %d\n",
|
||||
mmc_hostname(mmc), phase);
|
||||
out:
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out the greatest range of consecuitive selected
|
||||
* DLL clock output phases that can be used as sampling
|
||||
* setting for SD3.0 UHS-I card read operation (in SDR104
|
||||
* timing mode) or for eMMC4.5 card read operation (in HS200
|
||||
* timing mode).
|
||||
* Select the 3/4 of the range and configure the DLL with the
|
||||
* selected DLL clock output phase.
|
||||
*/
|
||||
|
||||
static int msm_find_most_appropriate_phase(struct sdhci_host *host,
|
||||
u8 *phase_table, u8 total_phases)
|
||||
{
|
||||
int ret;
|
||||
u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
|
||||
u8 phases_per_row[MAX_PHASES] = { 0 };
|
||||
int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
|
||||
int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
|
||||
bool phase_0_found = false, phase_15_found = false;
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
|
||||
if (!total_phases || (total_phases > MAX_PHASES)) {
|
||||
dev_err(mmc_dev(mmc), "%s: Invalid argument: total_phases=%d\n",
|
||||
mmc_hostname(mmc), total_phases);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (cnt = 0; cnt < total_phases; cnt++) {
|
||||
ranges[row_index][col_index] = phase_table[cnt];
|
||||
phases_per_row[row_index] += 1;
|
||||
col_index++;
|
||||
|
||||
if ((cnt + 1) == total_phases) {
|
||||
continue;
|
||||
/* check if next phase in phase_table is consecutive or not */
|
||||
} else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
|
||||
row_index++;
|
||||
col_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (row_index >= MAX_PHASES)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check if phase-0 is present in first valid window? */
|
||||
if (!ranges[0][0]) {
|
||||
phase_0_found = true;
|
||||
phase_0_raw_index = 0;
|
||||
/* Check if cycle exist between 2 valid windows */
|
||||
for (cnt = 1; cnt <= row_index; cnt++) {
|
||||
if (phases_per_row[cnt]) {
|
||||
for (i = 0; i < phases_per_row[cnt]; i++) {
|
||||
if (ranges[cnt][i] == 15) {
|
||||
phase_15_found = true;
|
||||
phase_15_raw_index = cnt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If 2 valid windows form cycle then merge them as single window */
|
||||
if (phase_0_found && phase_15_found) {
|
||||
/* number of phases in raw where phase 0 is present */
|
||||
u8 phases_0 = phases_per_row[phase_0_raw_index];
|
||||
/* number of phases in raw where phase 15 is present */
|
||||
u8 phases_15 = phases_per_row[phase_15_raw_index];
|
||||
|
||||
if (phases_0 + phases_15 >= MAX_PHASES)
|
||||
/*
|
||||
* If there are more than 1 phase windows then total
|
||||
* number of phases in both the windows should not be
|
||||
* more than or equal to MAX_PHASES.
|
||||
*/
|
||||
return -EINVAL;
|
||||
|
||||
/* Merge 2 cyclic windows */
|
||||
i = phases_15;
|
||||
for (cnt = 0; cnt < phases_0; cnt++) {
|
||||
ranges[phase_15_raw_index][i] =
|
||||
ranges[phase_0_raw_index][cnt];
|
||||
if (++i >= MAX_PHASES)
|
||||
break;
|
||||
}
|
||||
|
||||
phases_per_row[phase_0_raw_index] = 0;
|
||||
phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
|
||||
}
|
||||
|
||||
for (cnt = 0; cnt <= row_index; cnt++) {
|
||||
if (phases_per_row[cnt] > curr_max) {
|
||||
curr_max = phases_per_row[cnt];
|
||||
selected_row_index = cnt;
|
||||
}
|
||||
}
|
||||
|
||||
i = (curr_max * 3) / 4;
|
||||
if (i)
|
||||
i--;
|
||||
|
||||
ret = ranges[selected_row_index][i];
|
||||
|
||||
if (ret >= MAX_PHASES) {
|
||||
ret = -EINVAL;
|
||||
dev_err(mmc_dev(mmc), "%s: Invalid phase selected=%d\n",
|
||||
mmc_hostname(mmc), ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
|
||||
{
|
||||
u32 mclk_freq = 0, config;
|
||||
|
||||
/* Program the MCLK value to MCLK_FREQ bit field */
|
||||
if (host->clock <= 112000000)
|
||||
mclk_freq = 0;
|
||||
else if (host->clock <= 125000000)
|
||||
mclk_freq = 1;
|
||||
else if (host->clock <= 137000000)
|
||||
mclk_freq = 2;
|
||||
else if (host->clock <= 150000000)
|
||||
mclk_freq = 3;
|
||||
else if (host->clock <= 162000000)
|
||||
mclk_freq = 4;
|
||||
else if (host->clock <= 175000000)
|
||||
mclk_freq = 5;
|
||||
else if (host->clock <= 187000000)
|
||||
mclk_freq = 6;
|
||||
else if (host->clock <= 200000000)
|
||||
mclk_freq = 7;
|
||||
|
||||
config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
|
||||
config &= ~CMUX_SHIFT_PHASE_MASK;
|
||||
config |= mclk_freq << CMUX_SHIFT_PHASE_SHIFT;
|
||||
writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
||||
}
|
||||
|
||||
/* Initialize the DLL (Programmable Delay Line) */
|
||||
static int msm_init_cm_dll(struct sdhci_host *host)
|
||||
{
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
int wait_cnt = 50;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
/*
|
||||
* Make sure that clock is always enabled when DLL
|
||||
* tuning is in progress. Keeping PWRSAVE ON may
|
||||
* turn off the clock.
|
||||
*/
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
|
||||
& ~CORE_CLK_PWRSAVE), host->ioaddr + CORE_VENDOR_SPEC);
|
||||
|
||||
/* Write 1 to DLL_RST bit of DLL_CONFIG register */
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
|
||||
| CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
|
||||
|
||||
/* Write 1 to DLL_PDN bit of DLL_CONFIG register */
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
|
||||
| CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
|
||||
msm_cm_dll_set_freq(host);
|
||||
|
||||
/* Write 0 to DLL_RST bit of DLL_CONFIG register */
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
|
||||
& ~CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
|
||||
|
||||
/* Write 0 to DLL_PDN bit of DLL_CONFIG register */
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
|
||||
& ~CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
|
||||
|
||||
/* Set DLL_EN bit to 1. */
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
|
||||
| CORE_DLL_EN), host->ioaddr + CORE_DLL_CONFIG);
|
||||
|
||||
/* Set CK_OUT_EN bit to 1. */
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
|
||||
| CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
|
||||
|
||||
/* Write 0 to DLL_CLOCK_DISABLE bit of DLL_CONFIG_2 register */
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG2)
|
||||
& ~CORE_DLL_CLK_DISABLE), host->ioaddr + CORE_DLL_CONFIG2);
|
||||
|
||||
/* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
|
||||
while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) &
|
||||
CORE_DLL_LOCK)) {
|
||||
/* max. wait for 50us sec for LOCK bit to be set */
|
||||
if (--wait_cnt == 0) {
|
||||
dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n",
|
||||
mmc_hostname(mmc));
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
|
||||
{
|
||||
int tuning_seq_cnt = 3;
|
||||
u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
|
||||
const u32 *tuning_block_pattern = tuning_block_64;
|
||||
int size = sizeof(tuning_block_64); /* Pattern size in bytes */
|
||||
int rc;
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
struct mmc_ios ios = host->mmc->ios;
|
||||
|
||||
/*
|
||||
* Tuning is required for SDR104, HS200 and HS400 cards and
|
||||
* if clock frequency is greater than 100MHz in these modes.
|
||||
*/
|
||||
if (host->clock <= 100 * 1000 * 1000 ||
|
||||
!((ios.timing == MMC_TIMING_MMC_HS200) ||
|
||||
(ios.timing == MMC_TIMING_UHS_SDR104)))
|
||||
return 0;
|
||||
|
||||
if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
|
||||
(mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
|
||||
tuning_block_pattern = tuning_block_128;
|
||||
size = sizeof(tuning_block_128);
|
||||
}
|
||||
|
||||
data_buf = kmalloc(size, GFP_KERNEL);
|
||||
if (!data_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
retry:
|
||||
/* First of all reset the tuning block */
|
||||
rc = msm_init_cm_dll(host);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
phase = 0;
|
||||
do {
|
||||
struct mmc_command cmd = { 0 };
|
||||
struct mmc_data data = { 0 };
|
||||
struct mmc_request mrq = {
|
||||
.cmd = &cmd,
|
||||
.data = &data
|
||||
};
|
||||
struct scatterlist sg;
|
||||
|
||||
/* Set the phase in delay line hw block */
|
||||
rc = msm_config_cm_dll_phase(host, phase);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
cmd.opcode = opcode;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
|
||||
data.blksz = size;
|
||||
data.blocks = 1;
|
||||
data.flags = MMC_DATA_READ;
|
||||
data.timeout_ns = NSEC_PER_SEC; /* 1 second */
|
||||
|
||||
data.sg = &sg;
|
||||
data.sg_len = 1;
|
||||
sg_init_one(&sg, data_buf, size);
|
||||
memset(data_buf, 0, size);
|
||||
mmc_wait_for_req(mmc, &mrq);
|
||||
|
||||
if (!cmd.error && !data.error &&
|
||||
!memcmp(data_buf, tuning_block_pattern, size)) {
|
||||
/* Tuning is successful at this tuning point */
|
||||
tuned_phases[tuned_phase_cnt++] = phase;
|
||||
dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
|
||||
mmc_hostname(mmc), phase);
|
||||
}
|
||||
} while (++phase < ARRAY_SIZE(tuned_phases));
|
||||
|
||||
if (tuned_phase_cnt) {
|
||||
rc = msm_find_most_appropriate_phase(host, tuned_phases,
|
||||
tuned_phase_cnt);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
else
|
||||
phase = rc;
|
||||
|
||||
/*
|
||||
* Finally set the selected phase in delay
|
||||
* line hw block.
|
||||
*/
|
||||
rc = msm_config_cm_dll_phase(host, phase);
|
||||
if (rc)
|
||||
goto out;
|
||||
dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
|
||||
mmc_hostname(mmc), phase);
|
||||
} else {
|
||||
if (--tuning_seq_cnt)
|
||||
goto retry;
|
||||
/* Tuning failed */
|
||||
dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
|
||||
mmc_hostname(mmc));
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(data_buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable)
|
||||
{
|
||||
u32 config;
|
||||
config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
|
||||
|
||||
if (enable) {
|
||||
config |= CORE_CDR_EN;
|
||||
config &= ~CORE_CDR_EXT_EN;
|
||||
writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
||||
} else {
|
||||
config &= ~CORE_CDR_EN;
|
||||
config |= CORE_CDR_EXT_EN;
|
||||
writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
static struct sdhci_ops sdhci_msm_ops = {
|
||||
.platform_execute_tuning = sdhci_msm_execute_tuning,
|
||||
.toggle_cdr = sdhci_msm_toggle_cdr,
|
||||
};
|
||||
|
||||
#define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10)
|
||||
#define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11)
|
||||
#define MMC_CAP2_FULL_PWR_CYCLE (1 << 2)
|
||||
|
||||
static irqreturn_t cd_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct mmc_host *mmc_host = (struct mmc_host *)data;
|
||||
|
||||
sdhci_card_event(mmc_host);
|
||||
mmc_detect_change(mmc_host, msecs_to_jiffies(200));
|
||||
|
||||
return (irqreturn_t) IRQ_HANDLED;
|
||||
}
|
||||
|
||||
extern int cd_gpio_pin;
|
||||
|
||||
int msm_mmc_of_parse(struct mmc_host *host, struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 bus_width;
|
||||
bool explicit_inv_wp, gpio_inv_wp = false;
|
||||
enum of_gpio_flags flags;
|
||||
int len, ret, gpio, irq_number, sd_ldo;
|
||||
struct sdhci_msm_host *msm_host =
|
||||
container_of(host, struct sdhci_msm_host, mmc);
|
||||
|
||||
if (!host->parent || !host->parent->of_node || !msm_host)
|
||||
return 0;
|
||||
|
||||
np = host->parent->of_node;
|
||||
|
||||
/* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
|
||||
if (of_property_read_u32(np, "bus-width", &bus_width) < 0) {
|
||||
pr_err("\"bus-width\" property is missing, assuming 1 bit.\n");
|
||||
bus_width = 1;
|
||||
}
|
||||
|
||||
switch (bus_width) {
|
||||
case 8:
|
||||
host->caps |= MMC_CAP_8_BIT_DATA;
|
||||
/* Hosts capable of 8-bit transfers can also do 4 bits */
|
||||
case 4:
|
||||
host->caps |= MMC_CAP_4_BIT_DATA;
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
pr_err("Invalid \"bus-width\" value %ud!\n", bus_width);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* f_max is obtained from the optional "max-frequency" property */
|
||||
of_property_read_u32(np, "max-frequency", &host->f_max);
|
||||
|
||||
sd_ldo = of_get_named_gpio(np, "sd-ldo-gpios", 0);
|
||||
if (gpio_is_valid(sd_ldo)) {
|
||||
ret = devm_gpio_request(&pdev->dev, sd_ldo, "sd-ldo-gpios");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to request sd-ldo-gpios %d\n",
|
||||
sd_ldo);
|
||||
return ret;
|
||||
}
|
||||
dev_info(&pdev->dev, "Got SD LDO GPIO #%d\n", sd_ldo);
|
||||
|
||||
/* Toggle SD LDO GPIO on Init */
|
||||
gpio_direction_output(sd_ldo, 1);
|
||||
gpio_set_value(sd_ldo, 0);
|
||||
mdelay(100);
|
||||
gpio_set_value(sd_ldo, 1);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure CD and WP pins. They are both by default active low to
|
||||
* match the SDHCI spec. If GPIOs are provided for CD and / or WP, the
|
||||
* mmc-gpio helpers are used to attach, configure and use them. If
|
||||
* polarity inversion is specified in DT, one of MMC_CAP2_CD_ACTIVE_HIGH
|
||||
* and MMC_CAP2_RO_ACTIVE_HIGH capability-2 flags is set. If the
|
||||
* "broken-cd" property is provided, the MMC_CAP_NEEDS_POLL capability
|
||||
* is set. If the "non-removable" property is found, the
|
||||
* MMC_CAP_NONREMOVABLE capability is set and no card-detection
|
||||
* configuration is performed.
|
||||
*/
|
||||
|
||||
/* Parse Card Detection */
|
||||
if (of_find_property(np, "non-removable", &len)) {
|
||||
host->caps |= MMC_CAP_NONREMOVABLE;
|
||||
} else {
|
||||
bool explicit_inv_cd, gpio_inv_cd = false;
|
||||
|
||||
// explicit_inv_cd = of_property_read_bool(np, "cd-inverted");
|
||||
explicit_inv_cd = of_find_property(np, "cd-inverted", NULL) ? true : false;
|
||||
|
||||
if (of_find_property(np, "broken-cd", &len))
|
||||
host->caps |= MMC_CAP_NEEDS_POLL;
|
||||
|
||||
gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
|
||||
if (gpio_is_valid(gpio)) {
|
||||
if (!(flags & OF_GPIO_ACTIVE_LOW))
|
||||
gpio_inv_cd = true;
|
||||
cd_gpio_pin = gpio;
|
||||
|
||||
// ret = mmc_gpio_request_cd(host, gpio, 0);
|
||||
irq_number = gpio_to_irq(gpio);
|
||||
ret = request_irq(irq_number,
|
||||
cd_irq_handler,
|
||||
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
mmc_hostname(host),
|
||||
host);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to request CD GPIO #%d: %d!\n",
|
||||
gpio, ret);
|
||||
return ret;
|
||||
} else {
|
||||
msm_host->irq = irq_number;
|
||||
pr_info("Got CD GPIO #%d. Requested interrupt #%d.\n"
|
||||
, gpio, irq_number);
|
||||
}
|
||||
}
|
||||
|
||||
if (explicit_inv_cd ^ gpio_inv_cd)
|
||||
host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
|
||||
}
|
||||
|
||||
// /* Parse Write Protection */
|
||||
// explicit_inv_wp = of_property_read_bool(np, "wp-inverted");
|
||||
// explicit_inv_wp = of_find_property(np, "wp-inverted", NULL) ? true : false;
|
||||
//
|
||||
// gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
|
||||
// if (gpio_is_valid(gpio)) {
|
||||
// if (!(flags & OF_GPIO_ACTIVE_LOW))
|
||||
// gpio_inv_wp = true;
|
||||
//
|
||||
// ret = mmc_gpio_request_ro(host, gpio);
|
||||
// if (ret < 0) {
|
||||
// dev_err(host->parent,
|
||||
// "Failed to request WP GPIO: %d!\n", ret);
|
||||
// goto out;
|
||||
// } else {
|
||||
// dev_info(host->parent, "Got WP GPIO #%d.\n",
|
||||
// gpio);
|
||||
// }
|
||||
// }
|
||||
// if (explicit_inv_wp ^ gpio_inv_wp)
|
||||
// host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
|
||||
|
||||
if (of_find_property(np, "cap-sd-highspeed", &len))
|
||||
host->caps |= MMC_CAP_SD_HIGHSPEED;
|
||||
if (of_find_property(np, "cap-mmc-highspeed", &len))
|
||||
host->caps |= MMC_CAP_MMC_HIGHSPEED;
|
||||
if (of_find_property(np, "sd-uhs-sdr12", &len))
|
||||
host->caps |= MMC_CAP_UHS_SDR12;
|
||||
if (of_find_property(np, "sd-uhs-sdr25", &len))
|
||||
host->caps |= MMC_CAP_UHS_SDR25;
|
||||
if (of_find_property(np, "sd-uhs-sdr50", &len))
|
||||
host->caps |= MMC_CAP_UHS_SDR50;
|
||||
if (of_find_property(np, "sd-uhs-sdr104", &len))
|
||||
host->caps |= MMC_CAP_UHS_SDR104;
|
||||
if (of_find_property(np, "sd-uhs-ddr50", &len))
|
||||
host->caps |= MMC_CAP_UHS_DDR50;
|
||||
if (of_find_property(np, "cap-power-off-card", &len))
|
||||
host->caps |= MMC_CAP_POWER_OFF_CARD;
|
||||
if (of_find_property(np, "cap-sdio-irq", &len))
|
||||
host->caps |= MMC_CAP_SDIO_IRQ;
|
||||
if (of_find_property(np, "keep-power-in-suspend", &len))
|
||||
host->pm_caps |= MMC_PM_KEEP_POWER;
|
||||
if (of_find_property(np, "enable-sdio-wakeup", &len))
|
||||
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
|
||||
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sdhci_msm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sdhci_host *host;
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
struct sdhci_msm_host *msm_host;
|
||||
struct resource *core_memres;
|
||||
int ret;
|
||||
u16 host_version;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
resource_size_t core_mem_size;
|
||||
const char *name;
|
||||
|
||||
msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
|
||||
if (!msm_host)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!np) {
|
||||
pr_err("failed to acquire device node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops;
|
||||
host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);
|
||||
if (IS_ERR(host))
|
||||
return PTR_ERR(host);
|
||||
|
||||
pltfm_host = sdhci_priv(host);
|
||||
pltfm_host->priv = msm_host;
|
||||
msm_host->mmc = host->mmc;
|
||||
msm_host->pdev = pdev;
|
||||
|
||||
// msm_host->emulation = of_property_read_bool(np, "qca,emulation");
|
||||
msm_host->emulation = of_find_property(np, "qca,emulation", NULL) ? true : false;
|
||||
|
||||
ret = msm_mmc_of_parse(host->mmc, pdev);
|
||||
if (ret)
|
||||
goto pltfm_free;
|
||||
|
||||
sdhci_get_of_property(pdev);
|
||||
|
||||
/* Setup SDCC bus voter clock. */
|
||||
msm_host->bus_clk = of_clk_get_by_name(pdev->dev.of_node, "bus");
|
||||
if (!IS_ERR(msm_host->bus_clk)) {
|
||||
/* Vote for max. clk rate for max. performance */
|
||||
ret = clk_set_rate_dk(msm_host->bus_clk, INT_MAX);
|
||||
if (ret)
|
||||
goto pltfm_free;
|
||||
ret = clk_prepare_enable_dk(msm_host->bus_clk);
|
||||
if (ret)
|
||||
goto pltfm_free;
|
||||
}
|
||||
|
||||
/* Setup main peripheral bus clock */
|
||||
msm_host->pclk = of_clk_get_by_name(pdev->dev.of_node, "iface");
|
||||
if (IS_ERR(msm_host->pclk)) {
|
||||
ret = PTR_ERR(msm_host->pclk);
|
||||
dev_err(&pdev->dev, "Perpheral clk setup failed (%d)\n", ret);
|
||||
goto bus_clk_disable;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable_dk(msm_host->pclk);
|
||||
if (ret)
|
||||
goto bus_clk_disable;
|
||||
|
||||
/* Setup SDCC clock */
|
||||
msm_host->clk = of_clk_get_by_name(pdev->dev.of_node, "core");
|
||||
if (IS_ERR(msm_host->clk)) {
|
||||
ret = PTR_ERR(msm_host->clk);
|
||||
dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret);
|
||||
goto pclk_disable;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable_dk(msm_host->clk);
|
||||
|
||||
if (ret)
|
||||
goto pclk_disable;
|
||||
|
||||
core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
// msm_host->core_mem = devm_ioremap_resource(&pdev->dev, core_memres);
|
||||
core_mem_size = resource_size(core_memres);
|
||||
name = core_memres->name ? core_memres->name : dev_name(&pdev->dev);
|
||||
devm_request_mem_region(&pdev->dev, core_memres->start, core_mem_size, name);
|
||||
msm_host->core_mem = devm_ioremap(&pdev->dev, core_memres->start, core_mem_size);
|
||||
|
||||
if (IS_ERR(msm_host->core_mem)) {
|
||||
pr_err("Failed to remap registers\n");
|
||||
ret = PTR_ERR(msm_host->core_mem);
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
|
||||
if (msm_host->emulation) {
|
||||
/*Set 1.8V,3V support*/
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + VENDOR_CAPS0)
|
||||
| VOLTS_SUPP_1_8V
|
||||
| VOLTS_SUPP_3_0V),
|
||||
host->ioaddr + VENDOR_CAPS0);
|
||||
|
||||
/*Set timeout caps*/
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + VENDOR_CAPS0)
|
||||
| 0x32),
|
||||
host->ioaddr + VENDOR_CAPS0);
|
||||
|
||||
/*Set base clock 10 MHz*/
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + VENDOR_CAPS0)
|
||||
| ((0xA) << 8)),
|
||||
host->ioaddr + VENDOR_CAPS0);
|
||||
|
||||
/* Remove SDR104 support*/
|
||||
writel_relaxed((readl_relaxed(host->ioaddr + VENDOR_CAPS1)
|
||||
& ~(CAPS_SDR_104_SUPPORT)),
|
||||
host->ioaddr + VENDOR_CAPS1);
|
||||
}
|
||||
|
||||
/* Set missing caps quirks */
|
||||
host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
|
||||
|
||||
/* Enable SDCC supported capabilities */
|
||||
host->caps = SDHCI_CAN_VDD_300 |
|
||||
SDHCI_CAN_VDD_180 |
|
||||
SDHCI_ASYNC_INT_SUPPORT |
|
||||
SDHCI_SYS_BUS_SUPPORT_64_BIT |
|
||||
SDHCI_HS_SUPPORT |
|
||||
SDHCI_ADMA2_SUPPORT |
|
||||
SDHCI_SUPPORT_8_BIT |
|
||||
SDHCI_MAX_BLK_LENGTH |
|
||||
SDHCI_TIMEOUT_CLK_UNIT |
|
||||
SDHCI_BASE_SDCLK_FREQ |
|
||||
SDHCI_TIMEOUT_CLK_FREQ;
|
||||
|
||||
/* Enable SD card supported modes */
|
||||
// host->caps1 = SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
|
||||
// SDHCI_SUPPORT_DDR50 | SDHCI_RETUNING_MODE;
|
||||
|
||||
/* Reset the core and Enable SDHC mode */
|
||||
writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
|
||||
CORE_SW_RST, msm_host->core_mem + CORE_POWER);
|
||||
|
||||
/* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
|
||||
usleep_range(1000, 5000);
|
||||
if (readl(msm_host->core_mem + CORE_POWER) & CORE_SW_RST) {
|
||||
pr_err("Stuck in reset\n");
|
||||
ret = -ETIMEDOUT;
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
/* Set HC_MODE_EN bit in HC_MODE register */
|
||||
writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
|
||||
|
||||
host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
|
||||
// host->quirks2 |= SDHCI_QUIRK2_USE_MAX_DISCARD_SIZE;
|
||||
|
||||
host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
|
||||
pr_info("Host Version: 0x%x Vendor Version 0x%x\n",
|
||||
host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
|
||||
SDHCI_VENDOR_VER_SHIFT));
|
||||
|
||||
ret = sdhci_add_host(host);
|
||||
|
||||
if (msm_host->emulation) {
|
||||
/* Enable controller */
|
||||
writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
|
||||
0x1, msm_host->core_mem + CORE_POWER);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
clk_disable:
|
||||
clk_disable_unprepare_dk(msm_host->clk);
|
||||
pclk_disable:
|
||||
clk_disable_unprepare_dk(msm_host->pclk);
|
||||
bus_clk_disable:
|
||||
if (!IS_ERR(msm_host->bus_clk))
|
||||
clk_disable_unprepare_dk(msm_host->bus_clk);
|
||||
pltfm_free:
|
||||
sdhci_pltfm_free(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sdhci_msm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_msm_host *msm_host = pltfm_host->priv;
|
||||
int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
|
||||
0xffffffff);
|
||||
if (msm_host->irq)
|
||||
free_irq(msm_host->irq, msm_host->mmc);
|
||||
|
||||
sdhci_remove_host(host, dead);
|
||||
sdhci_pltfm_free(pdev);
|
||||
clk_disable_unprepare_dk(msm_host->clk);
|
||||
clk_disable_unprepare_dk(msm_host->pclk);
|
||||
if (!IS_ERR(msm_host->bus_clk))
|
||||
clk_disable_unprepare_dk(msm_host->bus_clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sdhci_msm_dt_match[] = {
|
||||
{ .compatible = "qcom,sdhci-msm-v4" },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver sdhci_msm_driver = {
|
||||
.probe = sdhci_msm_probe,
|
||||
.remove = sdhci_msm_remove,
|
||||
.driver = {
|
||||
.name = "sdhci_msm",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = sdhci_msm_dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init dakota_mmc_module_init(void) {
|
||||
return platform_driver_register(&sdhci_msm_driver);
|
||||
}
|
||||
|
||||
static void __exit dakota_mmc_module_exit(void) {
|
||||
platform_driver_unregister(&sdhci_msm_driver);
|
||||
}
|
||||
|
||||
module_init(dakota_mmc_module_init);
|
||||
module_exit(dakota_mmc_module_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
278
2025-03-19/dakota_mmc/sdhci-pltfm.c
Normal file
278
2025-03-19/dakota_mmc/sdhci-pltfm.c
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* sdhci-pltfm.c Support for SDHCI platform devices
|
||||
* Copyright (c) 2009 Intel Corporation
|
||||
*
|
||||
* Copyright (c) 2007, 2011 Freescale Semiconductor, Inc.
|
||||
* Copyright (c) 2009 MontaVista Software, Inc.
|
||||
*
|
||||
* Authors: Xiaobo Xie <X.Xie@freescale.com>
|
||||
* Anton Vorontsov <avorontsov@ru.mvista.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* Supports:
|
||||
* SDHCI platform devices
|
||||
*
|
||||
* Inspired by sdhci-pci.c, by Pierre Ossman
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#ifdef CONFIG_PPC
|
||||
#include <asm/machdep.h>
|
||||
#endif
|
||||
#include "sdhci-pltfm.h"
|
||||
|
||||
unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
||||
return clk_get_rate(pltfm_host->clk);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock);
|
||||
|
||||
static const struct sdhci_ops sdhci_pltfm_ops = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static bool sdhci_of_wp_inverted(struct device_node *np)
|
||||
{
|
||||
if (of_get_property(np, "sdhci,wp-inverted", NULL) ||
|
||||
of_get_property(np, "wp-inverted", NULL))
|
||||
return true;
|
||||
|
||||
/* Old device trees don't have the wp-inverted property. */
|
||||
#ifdef CONFIG_PPC
|
||||
return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds);
|
||||
#else
|
||||
return false;
|
||||
#endif /* CONFIG_PPC */
|
||||
}
|
||||
|
||||
void sdhci_get_of_property(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
const __be32 *clk;
|
||||
u32 bus_width;
|
||||
int size;
|
||||
|
||||
if (of_device_is_available(np)) {
|
||||
if (of_get_property(np, "sdhci,auto-cmd12", NULL))
|
||||
host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
|
||||
|
||||
if (of_get_property(np, "sdhci,1-bit-only", NULL) ||
|
||||
(of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
|
||||
bus_width == 1))
|
||||
host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
|
||||
|
||||
if (sdhci_of_wp_inverted(np))
|
||||
host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
|
||||
|
||||
if (of_get_property(np, "broken-cd", NULL))
|
||||
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
|
||||
|
||||
if (of_get_property(np, "no-1-8-v", NULL))
|
||||
host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
|
||||
|
||||
if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
|
||||
host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
|
||||
|
||||
if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
|
||||
of_device_is_compatible(np, "fsl,p1010-esdhc") ||
|
||||
of_device_is_compatible(np, "fsl,t4240-esdhc") ||
|
||||
of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
|
||||
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
|
||||
|
||||
clk = of_get_property(np, "clock-frequency", &size);
|
||||
if (clk && size == sizeof(*clk) && *clk)
|
||||
pltfm_host->clock = be32_to_cpup(clk);
|
||||
|
||||
if (of_find_property(np, "keep-power-in-suspend", NULL))
|
||||
host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
|
||||
|
||||
if (of_find_property(np, "enable-sdio-wakeup", NULL))
|
||||
host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void sdhci_get_of_property(struct platform_device *pdev) {}
|
||||
#endif /* CONFIG_OF */
|
||||
EXPORT_SYMBOL_GPL(sdhci_get_of_property);
|
||||
|
||||
struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
|
||||
const struct sdhci_pltfm_data *pdata,
|
||||
size_t priv_size)
|
||||
{
|
||||
struct sdhci_host *host;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct resource *iomem;
|
||||
int ret;
|
||||
|
||||
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!iomem) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (resource_size(iomem) < 0x100)
|
||||
dev_err(&pdev->dev, "Invalid iomem size!\n");
|
||||
|
||||
/* Some PCI-based MFD need the parent here */
|
||||
if (pdev->dev.parent != &platform_bus && !np)
|
||||
host = sdhci_alloc_host(pdev->dev.parent,
|
||||
sizeof(struct sdhci_pltfm_host) + priv_size);
|
||||
else
|
||||
host = sdhci_alloc_host(&pdev->dev,
|
||||
sizeof(struct sdhci_pltfm_host) + priv_size);
|
||||
|
||||
if (IS_ERR(host)) {
|
||||
ret = PTR_ERR(host);
|
||||
goto err;
|
||||
}
|
||||
|
||||
host->hw_name = dev_name(&pdev->dev);
|
||||
if (pdata && pdata->ops)
|
||||
host->ops = pdata->ops;
|
||||
else
|
||||
host->ops = &sdhci_pltfm_ops;
|
||||
if (pdata) {
|
||||
host->quirks = pdata->quirks;
|
||||
host->quirks2 = pdata->quirks2;
|
||||
}
|
||||
|
||||
host->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (!request_mem_region(iomem->start, resource_size(iomem),
|
||||
mmc_hostname(host->mmc))) {
|
||||
dev_err(&pdev->dev, "cannot request region\n");
|
||||
ret = -EBUSY;
|
||||
goto err_request;
|
||||
}
|
||||
|
||||
host->ioaddr = ioremap(iomem->start, resource_size(iomem));
|
||||
if (!host->ioaddr) {
|
||||
dev_err(&pdev->dev, "failed to remap registers\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_remap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some platforms need to probe the controller to be able to
|
||||
* determine which caps should be used.
|
||||
*/
|
||||
if (host->ops && host->ops->platform_init)
|
||||
host->ops->platform_init(host);
|
||||
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
return host;
|
||||
|
||||
err_remap:
|
||||
release_mem_region(iomem->start, resource_size(iomem));
|
||||
err_request:
|
||||
sdhci_free_host(host);
|
||||
err:
|
||||
dev_err(&pdev->dev, "%s failed %d\n", __func__, ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_pltfm_init);
|
||||
|
||||
void sdhci_pltfm_free(struct platform_device *pdev)
|
||||
{
|
||||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
iounmap(host->ioaddr);
|
||||
release_mem_region(iomem->start, resource_size(iomem));
|
||||
sdhci_free_host(host);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_pltfm_free);
|
||||
|
||||
int sdhci_pltfm_register(struct platform_device *pdev,
|
||||
const struct sdhci_pltfm_data *pdata,
|
||||
size_t priv_size)
|
||||
{
|
||||
struct sdhci_host *host;
|
||||
int ret = 0;
|
||||
|
||||
host = sdhci_pltfm_init(pdev, pdata, priv_size);
|
||||
if (IS_ERR(host))
|
||||
return PTR_ERR(host);
|
||||
|
||||
sdhci_get_of_property(pdev);
|
||||
|
||||
ret = sdhci_add_host(host);
|
||||
if (ret)
|
||||
sdhci_pltfm_free(pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_pltfm_register);
|
||||
|
||||
int sdhci_pltfm_unregister(struct platform_device *pdev)
|
||||
{
|
||||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
|
||||
|
||||
sdhci_remove_host(host, dead);
|
||||
sdhci_pltfm_free(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int sdhci_pltfm_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
||||
return sdhci_suspend_host(host);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_pltfm_suspend);
|
||||
|
||||
int sdhci_pltfm_resume(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
||||
return sdhci_resume_host(host);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_pltfm_resume);
|
||||
|
||||
const struct dev_pm_ops sdhci_pltfm_pmops = {
|
||||
.suspend = sdhci_pltfm_suspend,
|
||||
.resume = sdhci_pltfm_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
//static int __init sdhci_pltfm_drv_init(void)
|
||||
//{
|
||||
// pr_info("sdhci-pltfm: SDHCI platform and OF driver helper\n");
|
||||
//
|
||||
// return 0;
|
||||
//}
|
||||
//module_init(sdhci_pltfm_drv_init);
|
||||
//
|
||||
//static void __exit sdhci_pltfm_drv_exit(void)
|
||||
//{
|
||||
//}
|
||||
//module_exit(sdhci_pltfm_drv_exit);
|
||||
//
|
||||
//MODULE_DESCRIPTION("SDHCI platform and OF driver helper");
|
||||
//MODULE_AUTHOR("Intel Corporation");
|
||||
//MODULE_LICENSE("GPL v2");
|
||||
122
2025-03-19/dakota_mmc/sdhci-pltfm.h
Normal file
122
2025-03-19/dakota_mmc/sdhci-pltfm.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright 2010 MontaVista Software, LLC.
|
||||
*
|
||||
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _DRIVERS_MMC_SDHCI_PLTFM_H
|
||||
#define _DRIVERS_MMC_SDHCI_PLTFM_H
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include "sdhci.h"
|
||||
|
||||
struct sdhci_pltfm_data {
|
||||
const struct sdhci_ops *ops;
|
||||
unsigned int quirks;
|
||||
unsigned int quirks2;
|
||||
};
|
||||
|
||||
struct sdhci_pltfm_host {
|
||||
struct clk *clk;
|
||||
void *priv; /* to handle quirks across io-accessor calls */
|
||||
|
||||
/* migrate from sdhci_of_host */
|
||||
unsigned int clock;
|
||||
u16 xfer_mode_shadow;
|
||||
|
||||
unsigned long private[0] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
|
||||
/*
|
||||
* These accessors are designed for big endian hosts doing I/O to
|
||||
* little endian controllers incorporating a 32-bit hardware byte swapper.
|
||||
*/
|
||||
static inline u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
|
||||
{
|
||||
return in_be32(host->ioaddr + reg);
|
||||
}
|
||||
|
||||
static inline u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
|
||||
{
|
||||
return in_be16(host->ioaddr + (reg ^ 0x2));
|
||||
}
|
||||
|
||||
static inline u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
|
||||
{
|
||||
return in_8(host->ioaddr + (reg ^ 0x3));
|
||||
}
|
||||
|
||||
static inline void sdhci_be32bs_writel(struct sdhci_host *host,
|
||||
u32 val, int reg)
|
||||
{
|
||||
out_be32(host->ioaddr + reg, val);
|
||||
}
|
||||
|
||||
static inline void sdhci_be32bs_writew(struct sdhci_host *host,
|
||||
u16 val, int reg)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
int base = reg & ~0x3;
|
||||
int shift = (reg & 0x2) * 8;
|
||||
|
||||
switch (reg) {
|
||||
case SDHCI_TRANSFER_MODE:
|
||||
/*
|
||||
* Postpone this write, we must do it together with a
|
||||
* command write that is down below.
|
||||
*/
|
||||
pltfm_host->xfer_mode_shadow = val;
|
||||
return;
|
||||
case SDHCI_COMMAND:
|
||||
sdhci_be32bs_writel(host,
|
||||
val << 16 | pltfm_host->xfer_mode_shadow,
|
||||
SDHCI_TRANSFER_MODE);
|
||||
return;
|
||||
}
|
||||
clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
|
||||
}
|
||||
|
||||
static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
|
||||
{
|
||||
int base = reg & ~0x3;
|
||||
int shift = (reg & 0x3) * 8;
|
||||
|
||||
clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
|
||||
}
|
||||
#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
|
||||
|
||||
extern void sdhci_get_of_property(struct platform_device *pdev);
|
||||
|
||||
extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
|
||||
const struct sdhci_pltfm_data *pdata,
|
||||
size_t priv_size);
|
||||
extern void sdhci_pltfm_free(struct platform_device *pdev);
|
||||
|
||||
extern int sdhci_pltfm_register(struct platform_device *pdev,
|
||||
const struct sdhci_pltfm_data *pdata,
|
||||
size_t priv_size);
|
||||
extern int sdhci_pltfm_unregister(struct platform_device *pdev);
|
||||
|
||||
extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host);
|
||||
|
||||
static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
|
||||
{
|
||||
return (void *)host->private;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern int sdhci_pltfm_suspend(struct device *dev);
|
||||
extern int sdhci_pltfm_resume(struct device *dev);
|
||||
extern const struct dev_pm_ops sdhci_pltfm_pmops;
|
||||
#define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
|
||||
#else
|
||||
#define SDHCI_PLTFM_PMOPS NULL
|
||||
#endif
|
||||
|
||||
#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
|
||||
3386
2025-03-19/dakota_mmc/sdhci.c
Normal file
3386
2025-03-19/dakota_mmc/sdhci.c
Normal file
File diff suppressed because it is too large
Load diff
425
2025-03-19/dakota_mmc/sdhci.h
Normal file
425
2025-03-19/dakota_mmc/sdhci.h
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver
|
||||
*
|
||||
* Header file for Host Controller registers and I/O accessors.
|
||||
*
|
||||
* Copyright (C) 2005-2008 Pierre Ossman, 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.
|
||||
*/
|
||||
#ifndef __SDHCI_HW_H
|
||||
#define __SDHCI_HW_H
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <linux/mmc/sdhci.h>
|
||||
|
||||
/*
|
||||
* Controller registers
|
||||
*/
|
||||
|
||||
#define SDHCI_DMA_ADDRESS 0x00
|
||||
#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS
|
||||
|
||||
#define SDHCI_BLOCK_SIZE 0x04
|
||||
#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
|
||||
|
||||
#define SDHCI_BLOCK_COUNT 0x06
|
||||
|
||||
#define SDHCI_ARGUMENT 0x08
|
||||
|
||||
#define SDHCI_TRANSFER_MODE 0x0C
|
||||
#define SDHCI_TRNS_DMA 0x01
|
||||
#define SDHCI_TRNS_BLK_CNT_EN 0x02
|
||||
#define SDHCI_TRNS_AUTO_CMD12 0x04
|
||||
#define SDHCI_TRNS_AUTO_CMD23 0x08
|
||||
#define SDHCI_TRNS_READ 0x10
|
||||
#define SDHCI_TRNS_MULTI 0x20
|
||||
|
||||
#define SDHCI_COMMAND 0x0E
|
||||
#define SDHCI_CMD_RESP_MASK 0x03
|
||||
#define SDHCI_CMD_CRC 0x08
|
||||
#define SDHCI_CMD_INDEX 0x10
|
||||
#define SDHCI_CMD_DATA 0x20
|
||||
#define SDHCI_CMD_ABORTCMD 0xC0
|
||||
|
||||
#define SDHCI_CMD_RESP_NONE 0x00
|
||||
#define SDHCI_CMD_RESP_LONG 0x01
|
||||
#define SDHCI_CMD_RESP_SHORT 0x02
|
||||
#define SDHCI_CMD_RESP_SHORT_BUSY 0x03
|
||||
|
||||
#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
|
||||
#define SDHCI_GET_CMD(c) ((c>>8) & 0x3f)
|
||||
|
||||
#define SDHCI_RESPONSE 0x10
|
||||
|
||||
#define SDHCI_BUFFER 0x20
|
||||
|
||||
#define SDHCI_PRESENT_STATE 0x24
|
||||
#define SDHCI_CMD_INHIBIT 0x00000001
|
||||
#define SDHCI_DATA_INHIBIT 0x00000002
|
||||
#define SDHCI_DOING_WRITE 0x00000100
|
||||
#define SDHCI_DOING_READ 0x00000200
|
||||
#define SDHCI_SPACE_AVAILABLE 0x00000400
|
||||
#define SDHCI_DATA_AVAILABLE 0x00000800
|
||||
#define SDHCI_CARD_PRESENT 0x00010000
|
||||
#define SDHCI_WRITE_PROTECT 0x00080000
|
||||
#define SDHCI_DATA_LVL_MASK 0x00F00000
|
||||
#define SDHCI_DATA_LVL_SHIFT 20
|
||||
|
||||
#define SDHCI_HOST_CONTROL 0x28
|
||||
#define SDHCI_CTRL_LED 0x01
|
||||
#define SDHCI_CTRL_4BITBUS 0x02
|
||||
#define SDHCI_CTRL_HISPD 0x04
|
||||
#define SDHCI_CTRL_DMA_MASK 0x18
|
||||
#define SDHCI_CTRL_SDMA 0x00
|
||||
#define SDHCI_CTRL_ADMA1 0x08
|
||||
#define SDHCI_CTRL_ADMA32 0x10
|
||||
#define SDHCI_CTRL_ADMA64 0x18
|
||||
#define SDHCI_CTRL_8BITBUS 0x20
|
||||
|
||||
#define SDHCI_POWER_CONTROL 0x29
|
||||
#define SDHCI_POWER_ON 0x01
|
||||
#define SDHCI_POWER_180 0x0A
|
||||
#define SDHCI_POWER_300 0x0C
|
||||
#define SDHCI_POWER_330 0x0E
|
||||
|
||||
#define SDHCI_BLOCK_GAP_CONTROL 0x2A
|
||||
|
||||
#define SDHCI_WAKE_UP_CONTROL 0x2B
|
||||
#define SDHCI_WAKE_ON_INT 0x01
|
||||
#define SDHCI_WAKE_ON_INSERT 0x02
|
||||
#define SDHCI_WAKE_ON_REMOVE 0x04
|
||||
|
||||
#define SDHCI_CLOCK_CONTROL 0x2C
|
||||
#define SDHCI_DIVIDER_SHIFT 8
|
||||
#define SDHCI_DIVIDER_HI_SHIFT 6
|
||||
#define SDHCI_DIV_MASK 0xFF
|
||||
#define SDHCI_DIV_MASK_LEN 8
|
||||
#define SDHCI_DIV_HI_MASK 0x300
|
||||
#define SDHCI_PROG_CLOCK_MODE 0x0020
|
||||
#define SDHCI_CLOCK_CARD_EN 0x0004
|
||||
#define SDHCI_CLOCK_INT_STABLE 0x0002
|
||||
#define SDHCI_CLOCK_INT_EN 0x0001
|
||||
|
||||
#define SDHCI_TIMEOUT_CONTROL 0x2E
|
||||
|
||||
#define SDHCI_SOFTWARE_RESET 0x2F
|
||||
#define SDHCI_RESET_ALL 0x01
|
||||
#define SDHCI_RESET_CMD 0x02
|
||||
#define SDHCI_RESET_DATA 0x04
|
||||
|
||||
#define SDHCI_INT_STATUS 0x30
|
||||
#define SDHCI_INT_ENABLE 0x34
|
||||
#define SDHCI_SIGNAL_ENABLE 0x38
|
||||
#define SDHCI_INT_RESPONSE 0x00000001
|
||||
#define SDHCI_INT_DATA_END 0x00000002
|
||||
#define SDHCI_INT_BLK_GAP 0x00000004
|
||||
#define SDHCI_INT_DMA_END 0x00000008
|
||||
#define SDHCI_INT_SPACE_AVAIL 0x00000010
|
||||
#define SDHCI_INT_DATA_AVAIL 0x00000020
|
||||
#define SDHCI_INT_CARD_INSERT 0x00000040
|
||||
#define SDHCI_INT_CARD_REMOVE 0x00000080
|
||||
#define SDHCI_INT_CARD_INT 0x00000100
|
||||
#define SDHCI_INT_ERROR 0x00008000
|
||||
#define SDHCI_INT_TIMEOUT 0x00010000
|
||||
#define SDHCI_INT_CRC 0x00020000
|
||||
#define SDHCI_INT_END_BIT 0x00040000
|
||||
#define SDHCI_INT_INDEX 0x00080000
|
||||
#define SDHCI_INT_DATA_TIMEOUT 0x00100000
|
||||
#define SDHCI_INT_DATA_CRC 0x00200000
|
||||
#define SDHCI_INT_DATA_END_BIT 0x00400000
|
||||
#define SDHCI_INT_BUS_POWER 0x00800000
|
||||
#define SDHCI_INT_ACMD12ERR 0x01000000
|
||||
#define SDHCI_INT_ADMA_ERROR 0x02000000
|
||||
|
||||
#define SDHCI_INT_NORMAL_MASK 0x00007FFF
|
||||
#define SDHCI_INT_ERROR_MASK 0xFFFF8000
|
||||
|
||||
#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
|
||||
SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
|
||||
#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
|
||||
SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
|
||||
SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
|
||||
SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
|
||||
SDHCI_INT_BLK_GAP)
|
||||
#define SDHCI_INT_ALL_MASK ((unsigned int)-1)
|
||||
|
||||
#define SDHCI_ACMD12_ERR 0x3C
|
||||
|
||||
#define SDHCI_HOST_CONTROL2 0x3E
|
||||
#define SDHCI_CTRL_UHS_MASK 0x0007
|
||||
#define SDHCI_CTRL_UHS_SDR12 0x0000
|
||||
#define SDHCI_CTRL_UHS_SDR25 0x0001
|
||||
#define SDHCI_CTRL_UHS_SDR50 0x0002
|
||||
#define SDHCI_CTRL_UHS_SDR104 0x0003
|
||||
#define SDHCI_CTRL_UHS_DDR50 0x0004
|
||||
#define SDHCI_CTRL_HS_SDR200 0x0005 /* reserved value in SDIO spec */
|
||||
#define SDHCI_CTRL_VDD_180 0x0008
|
||||
#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
|
||||
#define SDHCI_CTRL_DRV_TYPE_B 0x0000
|
||||
#define SDHCI_CTRL_DRV_TYPE_A 0x0010
|
||||
#define SDHCI_CTRL_DRV_TYPE_C 0x0020
|
||||
#define SDHCI_CTRL_DRV_TYPE_D 0x0030
|
||||
#define SDHCI_CTRL_EXEC_TUNING 0x0040
|
||||
#define SDHCI_CTRL_TUNED_CLK 0x0080
|
||||
#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
|
||||
|
||||
#define SDHCI_CAPABILITIES 0x40
|
||||
#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
|
||||
#define SDHCI_TIMEOUT_CLK_SHIFT 0
|
||||
#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
|
||||
#define SDHCI_CLOCK_BASE_MASK 0x00003F00
|
||||
#define SDHCI_CLOCK_V3_BASE_MASK 0x0000FF00
|
||||
#define SDHCI_CLOCK_BASE_SHIFT 8
|
||||
#define SDHCI_MAX_BLOCK_MASK 0x00030000
|
||||
#define SDHCI_MAX_BLOCK_SHIFT 16
|
||||
#define SDHCI_CAN_DO_8BIT 0x00040000
|
||||
#define SDHCI_CAN_DO_ADMA2 0x00080000
|
||||
#define SDHCI_CAN_DO_ADMA1 0x00100000
|
||||
#define SDHCI_CAN_DO_HISPD 0x00200000
|
||||
#define SDHCI_CAN_DO_SDMA 0x00400000
|
||||
#define SDHCI_CAN_VDD_330 0x01000000
|
||||
#define SDHCI_CAN_VDD_300 0x02000000
|
||||
#define SDHCI_CAN_VDD_180 0x04000000
|
||||
#define SDHCI_CAN_64BIT 0x10000000
|
||||
|
||||
#define SDHCI_SUPPORT_SDR50 0x00000001
|
||||
#define SDHCI_SUPPORT_SDR104 0x00000002
|
||||
#define SDHCI_SUPPORT_DDR50 0x00000004
|
||||
#define SDHCI_DRIVER_TYPE_A 0x00000010
|
||||
#define SDHCI_DRIVER_TYPE_C 0x00000020
|
||||
#define SDHCI_DRIVER_TYPE_D 0x00000040
|
||||
#define SDHCI_RETUNING_TIMER_COUNT_MASK 0x00000F00
|
||||
#define SDHCI_RETUNING_TIMER_COUNT_SHIFT 8
|
||||
#define SDHCI_USE_SDR50_TUNING 0x00002000
|
||||
#define SDHCI_RETUNING_MODE_MASK 0x0000C000
|
||||
#define SDHCI_RETUNING_MODE_SHIFT 14
|
||||
#define SDHCI_CLOCK_MUL_MASK 0x00FF0000
|
||||
#define SDHCI_CLOCK_MUL_SHIFT 16
|
||||
|
||||
#define SDHCI_CAPABILITIES_1 0x44
|
||||
|
||||
#define SDHCI_MAX_CURRENT 0x48
|
||||
#define SDHCI_MAX_CURRENT_LIMIT 0xFF
|
||||
#define SDHCI_MAX_CURRENT_330_MASK 0x0000FF
|
||||
#define SDHCI_MAX_CURRENT_330_SHIFT 0
|
||||
#define SDHCI_MAX_CURRENT_300_MASK 0x00FF00
|
||||
#define SDHCI_MAX_CURRENT_300_SHIFT 8
|
||||
#define SDHCI_MAX_CURRENT_180_MASK 0xFF0000
|
||||
#define SDHCI_MAX_CURRENT_180_SHIFT 16
|
||||
#define SDHCI_MAX_CURRENT_MULTIPLIER 4
|
||||
|
||||
/* 4C-4F reserved for more max current */
|
||||
|
||||
#define SDHCI_SET_ACMD12_ERROR 0x50
|
||||
#define SDHCI_SET_INT_ERROR 0x52
|
||||
|
||||
#define SDHCI_ADMA_ERROR 0x54
|
||||
|
||||
/* 55-57 reserved */
|
||||
|
||||
#define SDHCI_ADMA_ADDRESS 0x58
|
||||
|
||||
/* 60-FB reserved */
|
||||
|
||||
#define SDHCI_PRESET_FOR_SDR12 0x66
|
||||
#define SDHCI_PRESET_FOR_SDR25 0x68
|
||||
#define SDHCI_PRESET_FOR_SDR50 0x6A
|
||||
#define SDHCI_PRESET_FOR_SDR104 0x6C
|
||||
#define SDHCI_PRESET_FOR_DDR50 0x6E
|
||||
#define SDHCI_PRESET_DRV_MASK 0xC000
|
||||
#define SDHCI_PRESET_DRV_SHIFT 14
|
||||
#define SDHCI_PRESET_CLKGEN_SEL_MASK 0x400
|
||||
#define SDHCI_PRESET_CLKGEN_SEL_SHIFT 10
|
||||
#define SDHCI_PRESET_SDCLK_FREQ_MASK 0x3FF
|
||||
#define SDHCI_PRESET_SDCLK_FREQ_SHIFT 0
|
||||
|
||||
#define SDHCI_SLOT_INT_STATUS 0xFC
|
||||
|
||||
#define SDHCI_HOST_VERSION 0xFE
|
||||
#define SDHCI_VENDOR_VER_MASK 0xFF00
|
||||
#define SDHCI_VENDOR_VER_SHIFT 8
|
||||
#define SDHCI_SPEC_VER_MASK 0x00FF
|
||||
#define SDHCI_SPEC_VER_SHIFT 0
|
||||
#define SDHCI_SPEC_100 0
|
||||
#define SDHCI_SPEC_200 1
|
||||
#define SDHCI_SPEC_300 2
|
||||
|
||||
#define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */
|
||||
#define SDHCI_QUIRK2_BROKEN_HS200 (1<<6)
|
||||
#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3)
|
||||
#define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */
|
||||
#define SDHCI_QUIRK2_HOST_NO_CMD23 (1<<1)
|
||||
/* The system physically doesn't support 1.8v, even if the host does */
|
||||
#define SDHCI_QUIRK2_USE_MAX_DISCARD_SIZE (1<<7)
|
||||
#define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0)
|
||||
#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1<<4)
|
||||
/* Controller has a non-standard host control register */
|
||||
#define SDHCI_QUIRK2_NO_1_8_V (1<<2)
|
||||
|
||||
/*
|
||||
* End of controller registers.
|
||||
*/
|
||||
|
||||
#define SDHCI_MAX_DIV_SPEC_200 256
|
||||
#define SDHCI_MAX_DIV_SPEC_300 2046
|
||||
|
||||
/*
|
||||
* Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2.
|
||||
*/
|
||||
#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024)
|
||||
#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12)
|
||||
|
||||
|
||||
struct sdhci_ops {
|
||||
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
|
||||
u32 (*read_l)(struct sdhci_host *host, int reg);
|
||||
u16 (*read_w)(struct sdhci_host *host, int reg);
|
||||
u8 (*read_b)(struct sdhci_host *host, int reg);
|
||||
void (*write_l)(struct sdhci_host *host, u32 val, int reg);
|
||||
void (*write_w)(struct sdhci_host *host, u16 val, int reg);
|
||||
void (*write_b)(struct sdhci_host *host, u8 val, int reg);
|
||||
#endif
|
||||
|
||||
void (*set_clock)(struct sdhci_host *host, unsigned int clock);
|
||||
|
||||
int (*enable_dma)(struct sdhci_host *host);
|
||||
unsigned int (*get_max_clock)(struct sdhci_host *host);
|
||||
unsigned int (*get_min_clock)(struct sdhci_host *host);
|
||||
unsigned int (*get_timeout_clock)(struct sdhci_host *host);
|
||||
int (*platform_bus_width)(struct sdhci_host *host,
|
||||
int width);
|
||||
void (*platform_send_init_74_clocks)(struct sdhci_host *host,
|
||||
u8 power_mode);
|
||||
unsigned int (*get_ro)(struct sdhci_host *host);
|
||||
void (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
|
||||
void (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
|
||||
int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
|
||||
int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
|
||||
void (*hw_reset)(struct sdhci_host *host);
|
||||
void (*platform_suspend)(struct sdhci_host *host);
|
||||
void (*platform_resume)(struct sdhci_host *host);
|
||||
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
|
||||
void (*platform_init)(struct sdhci_host *host);
|
||||
void (*card_event)(struct sdhci_host *host);
|
||||
void (*toggle_cdr)(struct sdhci_host *host, bool enable);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
|
||||
|
||||
static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg)
|
||||
{
|
||||
if (unlikely(host->ops->write_l))
|
||||
host->ops->write_l(host, val, reg);
|
||||
else
|
||||
writel(val, host->ioaddr + reg);
|
||||
}
|
||||
|
||||
static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg)
|
||||
{
|
||||
if (unlikely(host->ops->write_w))
|
||||
host->ops->write_w(host, val, reg);
|
||||
else
|
||||
writew(val, host->ioaddr + reg);
|
||||
}
|
||||
|
||||
static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
|
||||
{
|
||||
if (unlikely(host->ops->write_b))
|
||||
host->ops->write_b(host, val, reg);
|
||||
else
|
||||
writeb(val, host->ioaddr + reg);
|
||||
}
|
||||
|
||||
static inline u32 sdhci_readl(struct sdhci_host *host, int reg)
|
||||
{
|
||||
if (unlikely(host->ops->read_l))
|
||||
return host->ops->read_l(host, reg);
|
||||
else
|
||||
return readl(host->ioaddr + reg);
|
||||
}
|
||||
|
||||
static inline u16 sdhci_readw(struct sdhci_host *host, int reg)
|
||||
{
|
||||
if (unlikely(host->ops->read_w))
|
||||
return host->ops->read_w(host, reg);
|
||||
else
|
||||
return readw(host->ioaddr + reg);
|
||||
}
|
||||
|
||||
static inline u8 sdhci_readb(struct sdhci_host *host, int reg)
|
||||
{
|
||||
if (unlikely(host->ops->read_b))
|
||||
return host->ops->read_b(host, reg);
|
||||
else
|
||||
return readb(host->ioaddr + reg);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg)
|
||||
{
|
||||
writel(val, host->ioaddr + reg);
|
||||
}
|
||||
|
||||
static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg)
|
||||
{
|
||||
writew(val, host->ioaddr + reg);
|
||||
}
|
||||
|
||||
static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
|
||||
{
|
||||
writeb(val, host->ioaddr + reg);
|
||||
}
|
||||
|
||||
static inline u32 sdhci_readl(struct sdhci_host *host, int reg)
|
||||
{
|
||||
return readl(host->ioaddr + reg);
|
||||
}
|
||||
|
||||
static inline u16 sdhci_readw(struct sdhci_host *host, int reg)
|
||||
{
|
||||
return readw(host->ioaddr + reg);
|
||||
}
|
||||
|
||||
static inline u8 sdhci_readb(struct sdhci_host *host, int reg)
|
||||
{
|
||||
return readb(host->ioaddr + reg);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */
|
||||
|
||||
extern struct sdhci_host *sdhci_alloc_host(struct device *dev,
|
||||
size_t priv_size);
|
||||
extern void sdhci_free_host(struct sdhci_host *host);
|
||||
|
||||
static inline void *sdhci_priv(struct sdhci_host *host)
|
||||
{
|
||||
return (void *)host->private;
|
||||
}
|
||||
|
||||
extern void sdhci_card_detect(struct sdhci_host *host);
|
||||
extern int sdhci_add_host(struct sdhci_host *host);
|
||||
extern void sdhci_remove_host(struct sdhci_host *host, int dead);
|
||||
extern void sdhci_send_command(struct sdhci_host *host,
|
||||
struct mmc_command *cmd);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern int sdhci_suspend_host(struct sdhci_host *host);
|
||||
extern int sdhci_resume_host(struct sdhci_host *host);
|
||||
extern void sdhci_enable_irq_wakeups(struct sdhci_host *host);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
extern int sdhci_runtime_suspend_host(struct sdhci_host *host);
|
||||
extern int sdhci_runtime_resume_host(struct sdhci_host *host);
|
||||
#endif
|
||||
|
||||
#endif /* __SDHCI_HW_H */
|
||||
72
2025-03-19/e2fsprogs-1.46.2.patch
Normal file
72
2025-03-19/e2fsprogs-1.46.2.patch
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
diff -puNrb e2fsprogs-1.46.2/config/config.sub e2fsprogs/config/config.sub
|
||||
--- e2fsprogs-1.46.2/config/config.sub 2021-03-15 14:20:09.000000000 +0200
|
||||
+++ e2fsprogs/config/config.sub 2021-12-03 14:02:42.948535474 +0200
|
||||
@@ -1338,7 +1338,7 @@ case $os in
|
||||
# The portable systems comes first.
|
||||
# Each alternative MUST end in a * to match a version number.
|
||||
# sysv* is not here because it comes later, after sysvr4.
|
||||
- gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
|
||||
+ gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* | musl* \
|
||||
| *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\
|
||||
| hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
|
||||
| sym* | kopensolaris* | plan9* \
|
||||
diff -puNrb e2fsprogs-1.46.2/e2fsck/logfile.c e2fsprogs/e2fsck/logfile.c
|
||||
--- e2fsprogs-1.46.2/e2fsck/logfile.c 2021-03-15 14:20:09.000000000 +0200
|
||||
+++ e2fsprogs/e2fsck/logfile.c 2021-12-03 14:02:42.964535515 +0200
|
||||
@@ -77,7 +77,7 @@ static void expand_percent_expression(e2
|
||||
if ((ch == 'D') || (ch == 'd') || (ch == 'm') || (ch == 'y') ||
|
||||
(ch == 'Y') ||
|
||||
(ch == 'T') || (ch == 'H') || (ch == 'M') || (ch == 'S')) {
|
||||
- tzset();
|
||||
+// tzset();
|
||||
tm = (*flags & FLAG_UTC) ? gmtime_r(&ctx->now, &tm_struct) :
|
||||
localtime_r(&ctx->now, &tm_struct);
|
||||
}
|
||||
diff -puNrb e2fsprogs-1.46.2/e2fsck/unix.c e2fsprogs/e2fsck/unix.c
|
||||
--- e2fsprogs-1.46.2/e2fsck/unix.c 2021-03-15 14:20:09.000000000 +0200
|
||||
+++ e2fsprogs/e2fsck/unix.c 2021-12-03 14:02:42.968535525 +0200
|
||||
@@ -241,6 +241,8 @@ static void check_mount(e2fsck_t ctx)
|
||||
ctx->filesystem_name);
|
||||
return;
|
||||
}
|
||||
+ if (ctx->mount_flags & EXT2_MF_READONLY)
|
||||
+ return; /* disable root fs filesystem check */
|
||||
|
||||
/*
|
||||
* If the filesystem isn't mounted, or it's the root
|
||||
@@ -1499,8 +1501,9 @@ restart:
|
||||
if ((ctx->options & E2F_OPT_READONLY) == 0) {
|
||||
flags |= EXT2_FLAG_RW;
|
||||
if (!(ctx->mount_flags & EXT2_MF_ISROOT &&
|
||||
- ctx->mount_flags & EXT2_MF_READONLY))
|
||||
- flags |= EXT2_FLAG_EXCLUSIVE;
|
||||
+ ctx->mount_flags & EXT2_MF_READONLY)) {
|
||||
+ //flags |= EXT2_FLAG_EXCLUSIVE;
|
||||
+ }
|
||||
if ((ctx->mount_flags & EXT2_MF_READONLY) &&
|
||||
(ctx->options & E2F_OPT_FORCE))
|
||||
flags &= ~EXT2_FLAG_EXCLUSIVE;
|
||||
diff -puNrb e2fsprogs-1.46.2/lib/blkid/llseek.c e2fsprogs/lib/blkid/llseek.c
|
||||
--- e2fsprogs-1.46.2/lib/blkid/llseek.c 2021-03-15 14:20:09.000000000 +0200
|
||||
+++ e2fsprogs/lib/blkid/llseek.c 2021-12-03 14:02:42.972535536 +0200
|
||||
@@ -56,7 +56,7 @@ extern long long llseek(int fd, long lon
|
||||
|
||||
#else /* SIZEOF_LONG != SIZEOF_LONG_LONG */
|
||||
|
||||
-#include <linux/unistd.h>
|
||||
+//#include <linux/unistd.h>
|
||||
|
||||
#ifndef __NR__llseek
|
||||
#define __NR__llseek 140
|
||||
diff -puNrb e2fsprogs-1.46.2/lib/ext2fs/llseek.c e2fsprogs/lib/ext2fs/llseek.c
|
||||
--- e2fsprogs-1.46.2/lib/ext2fs/llseek.c 2021-03-15 14:20:09.000000000 +0200
|
||||
+++ e2fsprogs/lib/ext2fs/llseek.c 2021-12-03 14:02:42.988535578 +0200
|
||||
@@ -57,7 +57,7 @@ extern long long llseek (int fd, long lo
|
||||
|
||||
#else /* SIZEOF_LONG != SIZEOF_LONG_LONG */
|
||||
|
||||
-#include <linux/unistd.h>
|
||||
+//#include <linux/unistd.h>
|
||||
|
||||
#ifndef __NR__llseek
|
||||
#define __NR__llseek 140
|
||||
237
2025-03-19/e2fsprogs-1.46.2/.gitignore
vendored
Normal file
237
2025-03-19/e2fsprogs-1.46.2/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
autom4te.cache
|
||||
build
|
||||
build.profiled
|
||||
build.static
|
||||
FILES
|
||||
^core
|
||||
*~
|
||||
patches
|
||||
Makefile
|
||||
*.bak
|
||||
*.diff
|
||||
*.dSYM
|
||||
*.o
|
||||
*.a
|
||||
*.orig
|
||||
*.patch
|
||||
*.pc
|
||||
*.rej
|
||||
*.swp
|
||||
00[0-9][1-9]*.patch
|
||||
MCONFIG
|
||||
asm_types.h
|
||||
config.log
|
||||
config.status
|
||||
cscope.*
|
||||
debugfs/extent_cmds.c
|
||||
debugfs/debug_cmds.c
|
||||
debugfs/debugfs
|
||||
debugfs/debugfs.8
|
||||
debugfs/extent_cmds.c
|
||||
debugfs/tst_set_fields
|
||||
doc/libext2fs.aux
|
||||
doc/libext2fs.cp
|
||||
doc/libext2fs.dvi
|
||||
doc/libext2fs.fn
|
||||
doc/libext2fs.fns
|
||||
doc/libext2fs.info
|
||||
doc/libext2fs.ky
|
||||
doc/libext2fs.log
|
||||
doc/libext2fs.pg
|
||||
doc/libext2fs.toc
|
||||
doc/libext2fs.tp
|
||||
doc/libext2fs.vr
|
||||
e2fsck/crc32table.h
|
||||
e2fsck/e2fsck
|
||||
e2fsck/e2fsck.8
|
||||
e2fsck/e2fsck.conf.5
|
||||
e2fsck/e2fsck.shared
|
||||
e2fsck/e2fsck.static
|
||||
e2fsck/gen_crc32table
|
||||
e2fsck/prof_err.c
|
||||
e2fsck/prof_err.h
|
||||
e2fsck/tst_crc32
|
||||
e2fsck/tst_problem
|
||||
e2fsck/tst_refcount
|
||||
e2fsck/tst_region
|
||||
e2fsprogs.spec
|
||||
ext2ed/ext2ed.conf
|
||||
ext2ed/ext2ed.8
|
||||
intl/charset.alias
|
||||
intl/libgnuintl.h
|
||||
intl/libintl.a
|
||||
intl/libintl.h
|
||||
intl/ref-add.sed
|
||||
intl/ref-del.sed
|
||||
lib/blkid/blkid.h
|
||||
lib/blkid/blkid.pc
|
||||
lib/blkid/blkid_types.h
|
||||
lib/blkid/libblkid.3
|
||||
lib/blkid/subdirs
|
||||
lib/blkid/test_probe
|
||||
lib/blkid/tests/*.ok
|
||||
lib/blkid/tests/*.out
|
||||
lib/blkid/tests/tmp
|
||||
lib/blkid/tst_cache
|
||||
lib/blkid/tst_dev
|
||||
lib/blkid/tst_devname
|
||||
lib/blkid/tst_devno
|
||||
lib/blkid/tst_getsize
|
||||
lib/blkid/tst_probe
|
||||
lib/blkid/tst_read
|
||||
lib/blkid/tst_resolve
|
||||
lib/blkid/tst_save
|
||||
lib/blkid/tst_tag
|
||||
lib/blkid/tst_types
|
||||
lib/config.h
|
||||
lib/dirpaths.h
|
||||
lib/e2p/e2p.pc
|
||||
lib/e2p/subdirs
|
||||
lib/e2p/tst_feature
|
||||
lib/e2p/tst_ostype
|
||||
lib/et/com_err.pc
|
||||
lib/et/compile_et
|
||||
lib/et/subdirs
|
||||
lib/ext2fs/crc32c_table.h
|
||||
lib/ext2fs/debug_cmds.c
|
||||
lib/ext2fs/ext2_err.c
|
||||
lib/ext2fs/ext2_err.et
|
||||
lib/ext2fs/ext2_err.h
|
||||
lib/ext2fs/ext2_types.h
|
||||
lib/ext2fs/ext2fs.pc
|
||||
lib/ext2fs/extent_cmds.c
|
||||
lib/ext2fs/gen_crc32ctable
|
||||
lib/ext2fs/subdirs
|
||||
lib/ext2fs/tst_badblocks
|
||||
lib/ext2fs/tst_bitmaps
|
||||
lib/ext2fs/tst_bitmaps_cmd.c
|
||||
lib/ext2fs/tst_bitmaps_out
|
||||
lib/ext2fs/tst_bitops
|
||||
lib/ext2fs/tst_cmds.c
|
||||
lib/ext2fs/tst_csum
|
||||
lib/ext2fs/tst_crc32c
|
||||
lib/ext2fs/tst_digest_encode
|
||||
lib/ext2fs/tst_getsectsize
|
||||
lib/ext2fs/tst_getsize
|
||||
lib/ext2fs/tst_icount
|
||||
lib/ext2fs/tst_inline
|
||||
lib/ext2fs/tst_inline_data
|
||||
lib/ext2fs/tst_inode_size
|
||||
lib/ext2fs/tst_iscan
|
||||
lib/ext2fs/tst_libext2fs
|
||||
lib/ext2fs/tst_sha256
|
||||
lib/ext2fs/tst_sha512
|
||||
lib/ext2fs/tst_super_size
|
||||
lib/ext2fs/tst_types
|
||||
lib/quota/subdirs
|
||||
lib/ss/mk_cmds
|
||||
lib/ss/ss.pc
|
||||
lib/ss/ss_err.c
|
||||
lib/ss/ss_err.h
|
||||
lib/ss/std_rqs.c
|
||||
lib/ss/subdirs
|
||||
lib/ss/test.diff
|
||||
lib/ss/test_cmd.c
|
||||
lib/ss/test_out
|
||||
lib/ss/test_ss
|
||||
lib/support/prof_err.c
|
||||
lib/support/prof_err.h
|
||||
lib/support/subdirs
|
||||
lib/uuid/subdirs
|
||||
lib/uuid/tst_uuid
|
||||
lib/uuid/uuid.3
|
||||
lib/uuid/uuid.h
|
||||
lib/uuid/uuid.pc
|
||||
lib/uuid/uuid_clear.3
|
||||
lib/uuid/uuid_compare.3
|
||||
lib/uuid/uuid_copy.3
|
||||
lib/uuid/uuid_generate.3
|
||||
lib/uuid/uuid_is_null.3
|
||||
lib/uuid/uuid_parse.3
|
||||
lib/uuid/uuid_time
|
||||
lib/uuid/uuid_time.3
|
||||
lib/uuid/uuid_types.h
|
||||
lib/uuid/uuid_unparse.3
|
||||
misc/badblocks
|
||||
misc/badblocks.8
|
||||
misc/base_device
|
||||
misc/base_device.out
|
||||
misc/blkid
|
||||
misc/blkid.8
|
||||
misc/chattr
|
||||
misc/chattr.1
|
||||
misc/default_profile.c
|
||||
misc/dumpe2fs
|
||||
misc/dumpe2fs.8
|
||||
misc/e2freefrag
|
||||
misc/e2freefrag.8
|
||||
misc/e2fuzz
|
||||
misc/e2image
|
||||
misc/e2image.8
|
||||
misc/e2initrd_helper
|
||||
misc/e2label.8
|
||||
misc/e2mmpstatus
|
||||
misc/e2mmpstatus.8
|
||||
misc/e2undo
|
||||
misc/e2undo.8
|
||||
misc/e4crypt
|
||||
misc/e4crypt.8
|
||||
misc/e4defrag
|
||||
misc/e4defrag.8
|
||||
misc/ext4.5
|
||||
misc/filefrag
|
||||
misc/filefrag.8
|
||||
misc/findfs.8
|
||||
misc/findsuper
|
||||
misc/fsck
|
||||
misc/fsck.8
|
||||
misc/fuse2fs
|
||||
misc/fuse2fs.1
|
||||
misc/logsave
|
||||
misc/logsave.8
|
||||
misc/lsattr
|
||||
misc/lsattr.1
|
||||
misc/mke2fs
|
||||
misc/mke2fs.8
|
||||
misc/mke2fs.conf.5
|
||||
misc/mke2fs.conf
|
||||
misc/mklost+found
|
||||
misc/mklost+found.8
|
||||
misc/prof_err.c
|
||||
misc/prof_err.h
|
||||
misc/profile.h
|
||||
misc/tune2fs
|
||||
misc/tune2fs.8
|
||||
misc/uuidd
|
||||
misc/uuidd.8
|
||||
misc/uuidgen
|
||||
misc/uuidgen.1
|
||||
ncscope.*
|
||||
parse-types.log
|
||||
po/Makefile.in
|
||||
po/POTFILES
|
||||
public_config.h
|
||||
resize/resize2fs
|
||||
resize/resize2fs.8
|
||||
resize/test_extent
|
||||
resize/test_extent.out
|
||||
tags
|
||||
TAGS
|
||||
tests/progs/test_icount
|
||||
tests/progs/test_icount_cmds.c
|
||||
tests/progs/crcsum
|
||||
tests/*.ok
|
||||
tests/*.failed
|
||||
tests/*.log
|
||||
tests/*.tmp
|
||||
tests/*.slow
|
||||
tests/test_data.tmp
|
||||
tests/mke2fs.conf
|
||||
tests/test_script
|
||||
tests/test_one
|
||||
util/dirpaths.h
|
||||
util/gen-tarball
|
||||
util/install-symlink
|
||||
util/subst
|
||||
util/subst.conf
|
||||
Meta
|
||||
4
2025-03-19/e2fsprogs-1.46.2/.missing-copyright
Normal file
4
2025-03-19/e2fsprogs-1.46.2/.missing-copyright
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
find . -type f \! -name \*~ \! -exec grep -q Begin-Header \{\} \; -print \
|
||||
| grep -v ^./build
|
||||
19
2025-03-19/e2fsprogs-1.46.2/.release-checklist
Normal file
19
2025-03-19/e2fsprogs-1.46.2/.release-checklist
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
1) Do "make depend" if necessary
|
||||
|
||||
2) "make check"!!!
|
||||
|
||||
3) Use "git log" to assemble release notes and update RELEASE-NOTES symlink.
|
||||
|
||||
4) Update files which contain version information
|
||||
version.h
|
||||
README
|
||||
e2fsprogs.lsm
|
||||
e2fsprogs.spec
|
||||
doc/libext2fs.texinfo (three places)
|
||||
|
||||
5) Run "(cd po; make e2fsprogs.pot-update)" to update the translation template.
|
||||
|
||||
6) Make source tarfile
|
||||
|
||||
7) Adjust sizes in e2fsprogs-VER.lsm; rebuild source files; regenerate source tarfile
|
||||
|
||||
1379
2025-03-19/e2fsprogs-1.46.2/ABOUT-NLS
Normal file
1379
2025-03-19/e2fsprogs-1.46.2/ABOUT-NLS
Normal file
File diff suppressed because it is too large
Load diff
28
2025-03-19/e2fsprogs-1.46.2/Android.bp
Normal file
28
2025-03-19/e2fsprogs-1.46.2/Android.bp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2017 The Android Open Source Project
|
||||
|
||||
cc_defaults {
|
||||
name: "e2fsprogs-defaults",
|
||||
cflags: ["-Wall", "-Werror"],
|
||||
target: {
|
||||
darwin: {
|
||||
// Still has unfixed/unsuppressed warnings.
|
||||
cflags: ["-Wno-error"],
|
||||
},
|
||||
windows: {
|
||||
cflags: [
|
||||
"-Wno-typedef-redefinition",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-unused-variable",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
subdirs = [
|
||||
"contrib",
|
||||
"debugfs",
|
||||
"e2fsck",
|
||||
"lib",
|
||||
"misc",
|
||||
"resize",
|
||||
]
|
||||
52
2025-03-19/e2fsprogs-1.46.2/CleanSpec.mk
Normal file
52
2025-03-19/e2fsprogs-1.46.2/CleanSpec.mk
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Copyright (C) 2007 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# If you don't need to do a full clean build but would like to touch
|
||||
# a file or delete some intermediate files, add a clean step to the end
|
||||
# of the list. These steps will only be run once, if they haven't been
|
||||
# run before.
|
||||
#
|
||||
# E.g.:
|
||||
# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
|
||||
# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
|
||||
#
|
||||
# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
|
||||
# files that are missing or have been moved.
|
||||
#
|
||||
# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
|
||||
# Use $(OUT_DIR) to refer to the "out" directory.
|
||||
#
|
||||
# If you need to re-do something that's already mentioned, just copy
|
||||
# the command and add it to the bottom of the list. E.g., if a change
|
||||
# that you made last week required touching a file and a change you
|
||||
# made today requires touching the same file, just copy the old
|
||||
# touch step and add it to the end of the list.
|
||||
#
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
|
||||
# For example:
|
||||
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
|
||||
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
|
||||
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
|
||||
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
|
||||
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libext2_uuid_intermediates)
|
||||
$(call add-clean-step, rm -rf $(TARGET_RECOVERY_OUT)/root/sbin)
|
||||
69
2025-03-19/e2fsprogs-1.46.2/INSTALL
Normal file
69
2025-03-19/e2fsprogs-1.46.2/INSTALL
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
To install the second extended file system management programs,
|
||||
just follow the steps:
|
||||
|
||||
1) Change directory into the top of the e2fsprogs source tree
|
||||
|
||||
2) Create a build directory and cd into it:
|
||||
|
||||
mkdir build; cd build
|
||||
|
||||
3) Run the configure script
|
||||
|
||||
../configure
|
||||
|
||||
If you wish to turn on ELF shared libraries, add the option
|
||||
--enable-elf-shlibs. If you wish to build profiling libraries, add
|
||||
the option --enable-profile.
|
||||
|
||||
Note that if you are building on an older system (i.e., a 2.4
|
||||
kernel and/or glibc 2.2), the use of thread local storage will probably
|
||||
cause programs that use the uuid library to core dump. To disable
|
||||
thread local storage, use the configure option --disable-tls.
|
||||
|
||||
4) Compile the programs
|
||||
|
||||
make
|
||||
|
||||
5) Check to make sure the installation built correctly:
|
||||
|
||||
make check
|
||||
|
||||
6) Install the programs
|
||||
|
||||
Run `make install'
|
||||
|
||||
7) Install the include files and libraries
|
||||
|
||||
You can run `make install-libs' to install the include files and
|
||||
libraries. Please note that this installation is not needed for the
|
||||
programs to work. It is only needed if you expect to develop other
|
||||
programs using the libraries or if you want to compile other program
|
||||
using these libraries (like the 4.4BSD dump and restore port).
|
||||
|
||||
8) Remove any pre-formatted man pages.
|
||||
|
||||
Some distributions will have pre-formatted manual pages which
|
||||
will always be displayed in preference to newer man pages in /usr/man.
|
||||
If this is the case, you may need to manually remove them in order to
|
||||
see the correct manual pages. The shell script in
|
||||
install-utils/remove_preformat_manpages may be helpful in doing so.
|
||||
|
||||
9) Make sure your /etc/fstab file is correct.
|
||||
|
||||
Some distributions install an /etc/fstab which is missing the
|
||||
fifth and sixth field of filesystem entry, which are the dump
|
||||
frequency, and the fsck pass number, respectively. The problem with
|
||||
this is that the getmntent() library routine interprets those missing
|
||||
fields as "0", and a pass number of 0 is documented as meaning that
|
||||
fsck should not check that particular filesystem. If your entries in
|
||||
your /etc/fstab file look like this:
|
||||
|
||||
/dev/hda4 / ext2 defaults
|
||||
|
||||
you should add "1 1" at the end of each line, so that they look like this:
|
||||
|
||||
/dev/hda4 / ext2 defaults 1 1
|
||||
|
||||
There is a script in install-utils/convfstab (donated by
|
||||
Michael Weller) that may help you correct your /etc/fstab file.
|
||||
|
||||
53
2025-03-19/e2fsprogs-1.46.2/INSTALL.elfbin
Normal file
53
2025-03-19/e2fsprogs-1.46.2/INSTALL.elfbin
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
NOTE: This is the ELF version of the binary distribution. If you have
|
||||
a DLL system, please compile e2fsprogs from sources yourself. (In
|
||||
fact, in general you're better off compiling e2fsprogs from sources
|
||||
instead of using precompiled binaries.)
|
||||
|
||||
Also please note that these binaries assume the use of the GNU Libc.
|
||||
If you're still using libc5, you'll need build e2fsprogs from source.
|
||||
|
||||
To install the binary distribution of the second extended file
|
||||
system management programs, just follow the steps:
|
||||
|
||||
1) Install this tar file using the following command:
|
||||
|
||||
gunzip < e2fsprogs-1.13-elfbin.tar.gz | (cd /; tar Sxvpf - )
|
||||
|
||||
2) Run ldconfig to update the shared library pointers.
|
||||
|
||||
As root, type /sbin/ldconfig. This will update the links to
|
||||
the shared libraries included in the distribution. You can then remove
|
||||
the old versions of the libraries from /lib.
|
||||
|
||||
3) Remove any pre-formatted man pages.
|
||||
|
||||
Some distributions will have pre-formatted manual pages which
|
||||
will always be displayed in preference to newer man pages in /usr/man.
|
||||
If this is the case, you may need to manually remove them in order to
|
||||
see the correct manual pages. The shell script in
|
||||
install-utils/remove_preformat_manpages may be helpful in doing so.
|
||||
|
||||
4) Make sure your /etc/fstab file is correct.
|
||||
|
||||
Some distributions install an /etc/fstab which is missing the
|
||||
fifth and sixth field of filesystem entry, which are the dump
|
||||
frequency, and the fsck pass number, respectively. The problem with
|
||||
this is that the getmntent() library routine interprets those missing
|
||||
fields as "0", and a pass number of 0 is documented as meaning that
|
||||
fsck should not check that particular filesystem. If your entries in
|
||||
your /etc/fstab file look like this:
|
||||
|
||||
/dev/hda4 / ext2 defaults
|
||||
|
||||
you should add "1 1" at the end of each line, so that they look like this:
|
||||
|
||||
/dev/hda4 / ext2 defaults 1 1
|
||||
|
||||
There is a script in install-utils/convfstab (donated by
|
||||
Michael Weller) that may help you correct your /etc/fstab file.
|
||||
|
||||
5) Cleanup files from the installation.
|
||||
|
||||
When you're done with the installation, you will probably want
|
||||
to remove /INSTALL (this file), /README, and /install-utils from your
|
||||
root directory
|
||||
335
2025-03-19/e2fsprogs-1.46.2/MCONFIG.in
Normal file
335
2025-03-19/e2fsprogs-1.46.2/MCONFIG.in
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
# Beginning of file MCONFIG
|
||||
|
||||
all::
|
||||
|
||||
all-static::
|
||||
|
||||
check::
|
||||
|
||||
fullcheck::
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
COMPRESS_EXT = gz bz2 bz Z
|
||||
|
||||
prefix = @prefix@
|
||||
root_prefix = @root_prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
root_bindir = @root_bindir@
|
||||
root_sbindir = @root_sbindir@
|
||||
root_libdir = @root_libdir@
|
||||
datarootdir = @datarootdir@
|
||||
bindir = @bindir@
|
||||
sbindir = @sbindir@
|
||||
libdir = @libdir@
|
||||
datadir= @datadir@
|
||||
localedir = $(datadir)/locale
|
||||
root_sysconfdir= @root_sysconfdir@
|
||||
includedir = @includedir@
|
||||
mandir = @mandir@
|
||||
man1dir = $(mandir)/man1
|
||||
man3dir = $(mandir)/man3
|
||||
man5dir = $(mandir)/man5
|
||||
man8dir = $(mandir)/man8
|
||||
infodir = @infodir@
|
||||
datadir = @datadir@
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkglibdir = $(libdir)/e2fsprogs
|
||||
|
||||
HAVE_UDEV = @have_udev@
|
||||
UDEV_RULES_DIR = @pkg_udev_rules_dir@
|
||||
HAVE_CROND = @have_crond@
|
||||
CROND_DIR = @crond_dir@
|
||||
HAVE_SYSTEMD = @have_systemd@
|
||||
SYSTEMD_SYSTEM_UNIT_DIR = @systemd_system_unit_dir@
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
@ifGNUmake@ V =
|
||||
@ifGNUmake@ ifeq ($(strip $(V)),)
|
||||
@ifGNUmake@ # E = @echo
|
||||
@ifGNUmake@ # ES = echo
|
||||
@ifGNUmake@ # Q = @
|
||||
@ifGNUmake@ E = @E@
|
||||
@ifGNUmake@ ES = @ES@
|
||||
@ifGNUmake@ Q = @Q@
|
||||
@ifGNUmake@ else
|
||||
@ifGNUmake@ E = @\#
|
||||
@ifGNUmake@ ES = \#
|
||||
@ifGNUmake@ Q =
|
||||
@ifGNUmake@ endif
|
||||
|
||||
@ifNotGNUmake@ E = @E@
|
||||
@ifNotGNUmake@ ES = @ES@
|
||||
@ifNotGNUmake@ Q = @Q@
|
||||
|
||||
@ifGNUmake@ CHECK=sparse
|
||||
@ifGNUmake@ CHECK_OPTS=-Wsparse-all -Wno-transparent-union -Wno-return-void -Wno-undef -Wno-non-pointer-null
|
||||
@ifGNUmake@ CPPCHECK=cppcheck
|
||||
@ifGNUmake@ CPPCHECK_OPTS=--force --enable=all --quiet
|
||||
@ifGNUmake@ ifeq ("$(C)", "2")
|
||||
@ifGNUmake@ CHECK_CMD=$(CHECK) $(CHECK_OPTS) -Wbitwise -D__CHECK_ENDIAN__
|
||||
@ifGNUmake@ CPPCHECK_CMD=$(CPPCHECK) $(CPPCHECK_OPTS)
|
||||
@ifGNUmake@ else
|
||||
@ifGNUmake@ ifeq ("$(C)", "1")
|
||||
@ifGNUmake@ CHECK_CMD=$(CHECK) $(CHECK_OPTS)
|
||||
@ifGNUmake@ CPPCHECK_CMD=$(CPPCHECK) $(CPPCHECK_OPTS)
|
||||
@ifGNUmake@ else
|
||||
@ifGNUmake@ CHECK_CMD=@true
|
||||
@ifGNUmake@ CPPCHECK_CMD=@true
|
||||
@ifGNUmake@ endif
|
||||
@ifGNUmake@ endif
|
||||
|
||||
@ifNotGNUmake@ CHECK_CMD=true
|
||||
@ifNotGNUmake@ CPPCHECK_CMD=true
|
||||
|
||||
SANITIZER_CFLAGS = @lto_cflags@ @ubsan_cflags@ @addrsan_cflags@ @threadsan_cflags@
|
||||
SANITIZER_LDFLAGS = @lto_ldflags@ @ubsan_ldflags@ @addrsan_ldflags@ @threadsan_ldflags@
|
||||
|
||||
CC = @PTHREAD_CC@
|
||||
BUILD_CC = @BUILD_CC@
|
||||
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
|
||||
PTHREAD_LIBS = @PTHREAD_LIBS@
|
||||
CFLAGS = @CFLAGS@
|
||||
CFLAGS_SHLIB = @CFLAGS_SHLIB@
|
||||
CFLAGS_STLIB = @CFLAGS_STLIB@
|
||||
CPPFLAGS = @INCLUDES@
|
||||
ALL_CFLAGS = $(CPPFLAGS) $(SANITIZER_CFLAGS) $(CFLAGS) $(PTHREAD_CFLAGS) $(CFLAGS_WARN) @DEFS@ $(LOCAL_CFLAGS)
|
||||
ALL_CFLAGS_SHLIB = $(CPPFLAGS) $(SANITIZER_CFLAGS) $(CFLAGS_SHLIB) $(PTHREAD_CFLAGS) $(CFLAGS_WARN) @DEFS@ $(LOCAL_CFLAGS)
|
||||
ALL_CFLAGS_STLIB = $(CPPFLAGS) $(SANITIZER_CFLAGS) $(CFLAGS_STLIB) $(PTHREAD_CFLAGS) $(CFLAGS_WARN) @DEFS@ $(LOCAL_CFLAGS)
|
||||
LDFLAGS = $(SANITIZER_LDFLAGS) $(PTHREAD_CFLAGS) @LDFLAGS@
|
||||
LDFLAGS_SHLIB = $(SANITIZER_LDFLAGS) $(PTHREAD_CFLAGS) @LDFLAGS_SHLIB@
|
||||
ALL_LDFLAGS = $(LDFLAGS) @LDFLAG_DYNAMIC@
|
||||
LDFLAGS_STATIC = $(SANITIZER_LDFLAGS) $(PTHREAD_CFLAGS) @LDFLAGS_STATIC@
|
||||
BUILD_CFLAGS = $(SANITIZER_CFLAGS) @BUILD_CFLAGS@
|
||||
BUILD_LDFLAGS = $(SANITIZER_LDFLAGS) @BUILD_LDFLAGS@
|
||||
RDYNAMIC = @RDYNAMIC@
|
||||
LINK_BUILD_FLAGS = @LINK_BUILD_FLAGS@
|
||||
LINK_INSTALL_FLAGS = @LINK_INSTALL_FLAGS@
|
||||
RM = @RM@
|
||||
LN = @LN@
|
||||
LN_S = @LN_S@
|
||||
MV = @MV@
|
||||
CP = @CP@
|
||||
CHMOD = @CHMOD@
|
||||
AR = @AR@
|
||||
AWK = @AWK@
|
||||
SED = @SED@
|
||||
PERL = @PERL@
|
||||
RANLIB = @RANLIB@
|
||||
STRIP = @STRIP@
|
||||
LD = $(PURE) @CC@
|
||||
ARUPD = $(AR) r
|
||||
ARGEN = $(AR) rc
|
||||
LDCONFIG = @LDCONFIG@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
|
||||
#
|
||||
# Library definitions
|
||||
#
|
||||
LIB = $(top_builddir)/lib
|
||||
LIBSS = $(LIB)/libss@LIB_EXT@ @PRIVATE_LIBS_CMT@ @DLOPEN_LIB@
|
||||
LIBCOM_ERR = $(LIB)/libcom_err@LIB_EXT@ @PRIVATE_LIBS_CMT@ @SEM_INIT_LIB@
|
||||
LIBE2P = $(LIB)/libe2p@LIB_EXT@
|
||||
LIBEXT2FS = $(LIB)/libext2fs@LIB_EXT@
|
||||
LIBUUID = @LIBUUID@ @SOCKET_LIB@
|
||||
LIBMAGIC = @MAGIC_LIB@
|
||||
LIBFUSE = @FUSE_LIB@
|
||||
LIBSUPPORT = $(LIBINTL) $(LIB)/libsupport@STATIC_LIB_EXT@
|
||||
LIBBLKID = @LIBBLKID@ @PRIVATE_LIBS_CMT@ $(LIBUUID)
|
||||
LIBINTL = @LIBINTL@
|
||||
SYSLIBS = @LIBS@ @PTHREAD_LIBS@
|
||||
DEPLIBSS = $(LIB)/libss@LIB_EXT@
|
||||
DEPLIBCOM_ERR = $(LIB)/libcom_err@LIB_EXT@
|
||||
DEPLIBUUID = @DEPLIBUUID@
|
||||
DEPLIBSUPPORT = $(LIB)/libsupport@STATIC_LIB_EXT@
|
||||
DEPLIBBLKID = @DEPLIBBLKID@ @PRIVATE_LIBS_CMT@ $(DEPLIBUUID)
|
||||
TESTENV = LD_LIBRARY_PATH="$(LIB):$${LD_LIBRARY_PATH}" DYLD_LIBRARY_PATH="$(LIB):$${DYLD_LIBRARY_PATH}"
|
||||
|
||||
STATIC_LIBSS = $(LIB)/libss@STATIC_LIB_EXT@ @DLOPEN_LIB@
|
||||
STATIC_LIBCOM_ERR = $(LIB)/libcom_err@STATIC_LIB_EXT@ @SEM_INIT_LIB@
|
||||
STATIC_LIBE2P = $(LIB)/libe2p@STATIC_LIB_EXT@
|
||||
STATIC_LIBEXT2FS = $(LIB)/libext2fs@STATIC_LIB_EXT@
|
||||
STATIC_LIBUUID = @STATIC_LIBUUID@ @SOCKET_LIB@
|
||||
STATIC_LIBSUPPORT = $(LIBINTL) $(LIBSUPPORT)
|
||||
STATIC_LIBBLKID = @STATIC_LIBBLKID@ $(STATIC_LIBUUID)
|
||||
DEPSTATIC_LIBSS = $(LIB)/libss@STATIC_LIB_EXT@
|
||||
DEPSTATIC_LIBCOM_ERR = $(LIB)/libcom_err@STATIC_LIB_EXT@
|
||||
DEPSTATIC_LIBUUID = @DEPSTATIC_LIBUUID@
|
||||
DEPSTATIC_LIBSUPPORT = $(DEPLIBSUPPORT)
|
||||
DEPSTATIC_LIBBLKID = @DEPSTATIC_LIBBLKID@ $(DEPSTATIC_LIBUUID)
|
||||
|
||||
PROFILED_LIBSS = $(LIB)/libss@PROFILED_LIB_EXT@ @DLOPEN_LIB@
|
||||
PROFILED_LIBCOM_ERR = $(LIB)/libcom_err@PROFILED_LIB_EXT@ @SEM_INIT_LIB@
|
||||
PROFILED_LIBE2P = $(LIB)/libe2p@PROFILED_LIB_EXT@
|
||||
PROFILED_LIBEXT2FS = $(LIB)/libext2fs@PROFILED_LIB_EXT@
|
||||
PROFILED_LIBUUID = @PROFILED_LIBUUID@ @SOCKET_LIB@
|
||||
PROFILED_LIBSUPPORT = $(LIBINTL) $(LIB)/libsupport@PROFILED_LIB_EXT@
|
||||
PROFILED_LIBBLKID = @PROFILED_LIBBLKID@ $(PROFILED_LIBUUID)
|
||||
DEPPROFILED_LIBSS = $(LIB)/libss@PROFILED_LIB_EXT@
|
||||
DEPPROFILED_LIBCOM_ERR = $(LIB)/libcom_err@PROFILED_LIB_EXT@
|
||||
DEPPROFILED_LIBUUID = @PROFILED_LIBUUID@
|
||||
DEPPROFILED_LIBSUPPORT = $(PROFILED_LIBSUPPORT)
|
||||
DEPPROFILED_LIBBLKID = @PROFILED_LIBBLKID@ $(DEPPROFILED_LIBUUID)
|
||||
|
||||
#
|
||||
# A fast substitution command for fixing up man pages, shell scripts, etc.
|
||||
#
|
||||
SUBST_CONF=$(top_builddir)/util/subst.conf
|
||||
SUBSTITUTE= $(top_builddir)/util/subst -f $(SUBST_CONF)
|
||||
SUBSTITUTE_UPTIME= $(top_builddir)/util/subst -t -f $(SUBST_CONF)
|
||||
DEP_SUBSTITUTE= $(top_builddir)/util/subst $(SUBST_CONF)
|
||||
|
||||
$(top_builddir)/util/subst:
|
||||
cd $(top_builddir)/util ; $(MAKE) subst
|
||||
|
||||
#
|
||||
# Script for generating utf8data.h
|
||||
#
|
||||
MKUTF8DATA=$(top_builddir)/util/mkutf8data
|
||||
|
||||
$(top_builddir)/util/mkutf8data:
|
||||
$(MAKE) -C $(top_builddir)/util mkutf8data
|
||||
|
||||
#
|
||||
# Script for installing symlinks (for shared libraries)
|
||||
#
|
||||
$(top_builddir)/util/install-symlink: $(top_srcdir)/util/install-symlink.in \
|
||||
$(top_builddir)/config.status
|
||||
cd $(top_builddir); CONFIG_FILES=util/install-symlink ./config.status
|
||||
chmod +x $(top_builddir)/util/install-symlink
|
||||
|
||||
$(top_builddir)/util/symlinks:
|
||||
cd $(top_builddir)/util ; $(MAKE) symlinks
|
||||
|
||||
INSTALL_SYMLINK = /bin/sh $(top_builddir)/util/install-symlink \
|
||||
@SYMLINK_RELATIVE@ \
|
||||
--symlinks=$(top_builddir)/util/symlinks
|
||||
DEP_INSTALL_SYMLINK = $(top_builddir)/util/install-symlink \
|
||||
$(top_builddir)/util/symlinks
|
||||
|
||||
#
|
||||
# Warning flags
|
||||
#
|
||||
# Run make gcc-wall to do a build with warning messages.
|
||||
#
|
||||
#
|
||||
WFLAGS= -std=gnu99 -D_XOPEN_SOURCE=600 -D_GNU_SOURCE $(WFLAGS_EXTRA) \
|
||||
-Wall -W -Wwrite-strings -Wpointer-arith \
|
||||
-Wcast-qual -Wcast-align -Wno-variadic-macros \
|
||||
-Wstrict-prototypes -Wmissing-prototypes \
|
||||
-Wformat-security -Wformat-nonliteral \
|
||||
-Wmissing-format-attribute -O2 -Wstrict-aliasing \
|
||||
-Wnested-externs -Winline -DNO_INLINE_FUNCS -Wshadow \
|
||||
-UENABLE_NLS
|
||||
|
||||
gcc-wall-new:
|
||||
($(MAKE) CFLAGS_WARN="$(WFLAGS)" > /dev/null) 2>&1
|
||||
|
||||
gcc-wall:
|
||||
$(MAKE) clean > /dev/null
|
||||
$(MAKE) gcc-wall-new
|
||||
|
||||
static-check:
|
||||
($(MAKE) C=1 V=1 CFLAGS="$(ALL_CFLAGS) $(WFLAGS)") 2>&1
|
||||
|
||||
static-check-all:
|
||||
$(MAKE) clean > /dev/null
|
||||
$(MAKE) static-check
|
||||
|
||||
#
|
||||
# Installation user and groups
|
||||
#
|
||||
BINGRP= bin
|
||||
BINOWN= bin
|
||||
BINMODE= 555
|
||||
INCGRP= bin
|
||||
INCOWN= bin
|
||||
INCMODE= 444
|
||||
LIBOWN= bin
|
||||
LIBGRP= bin
|
||||
LIBMODE= 444
|
||||
MANGRP= bin
|
||||
MANOWN= bin
|
||||
MANMODE= 444
|
||||
|
||||
#
|
||||
# Autoconf magic...
|
||||
#
|
||||
|
||||
DEP_LIB_MAKEFILES = $(top_srcdir)/lib/Makefile.library \
|
||||
$(top_srcdir)/lib/Makefile.elf-lib \
|
||||
$(top_srcdir)/lib/Makefile.bsd-lib \
|
||||
$(top_srcdir)/lib/Makefile.darwin-lib \
|
||||
$(top_srcdir)/lib/Makefile.solaris-lib \
|
||||
$(top_srcdir)/lib/Makefile.profile
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure
|
||||
cd $(top_builddir); ./config.status --recheck
|
||||
|
||||
$(top_builddir)/MCONFIG: $(top_srcdir)/MCONFIG.in $(top_builddir)/config.status
|
||||
cd $(top_builddir); CONFIG_FILES=MCONFIG ./config.status
|
||||
|
||||
$(top_builddir)/lib/config.h: $(top_srcdir)/lib/config.h.in \
|
||||
$(top_builddir)/config.status
|
||||
cd $(top_builddir); CONFIG_FILES=lib/config.h ./config.status
|
||||
|
||||
$(top_builddir)/lib/dirpaths.h: $(DEP_SUBSTITUTE) $(top_srcdir)/lib/dirpaths.h.in
|
||||
$(E) " SUBST $@"
|
||||
$(Q) $(SUBSTITUTE) $(top_srcdir)/lib/dirpaths.h.in $@
|
||||
|
||||
$(top_builddir)/lib/substitute_sh: $(top_srcdir)/lib/substitute_sh.in \
|
||||
$(top_builddir)/config.status
|
||||
cd $(top_builddir); CONFIG_FILES=lib/substitute_sh ./config.status
|
||||
|
||||
$(top_builddir)/util/subst.conf: $(top_srcdir)/util/subst.conf.in \
|
||||
$(top_builddir)/config.status
|
||||
cd $(top_builddir); CONFIG_FILES=util/subst.conf ./config.status
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/MCONFIG \
|
||||
$(DEP_MAKEFILE) $(top_builddir)/config.status
|
||||
cd $(top_builddir); CONFIG_FILES=$(my_dir)/Makefile ./config.status
|
||||
|
||||
@MAINTAINER_CMT@$(top_srcdir)/configure: $(top_srcdir)/configure.ac
|
||||
@MAINTAINER_CMT@ cd $(top_srcdir) && autoheader && autoconf
|
||||
|
||||
coverage.txt: Makefile $(SRCS)
|
||||
if test -n "$(SRCS)"; then \
|
||||
gcov -s $(top_srcdir) -o . $(SRCS) > coverage.txt 2>&1 ; \
|
||||
fi
|
||||
|
||||
clean::
|
||||
$(RM) -f *.gcda *.gcov *.gcno coverage.txt
|
||||
|
||||
#
|
||||
# Make depend magic...
|
||||
#
|
||||
|
||||
.depend: Makefile $(SRCS) $(top_srcdir)/depfix.sed $(top_srcdir)/wordwrap.pl
|
||||
if test -n "$(SRCS)" ; then \
|
||||
$(CC) -M $(ALL_CFLAGS) $(DEPEND_CFLAGS) $(SRCS) | \
|
||||
$(SED) -f $(top_srcdir)/depfix.sed \
|
||||
-e 's; $(srcdir)/; $$(srcdir)/;g' \
|
||||
-e 's; $(top_srcdir)/; $$(top_srcdir)/;g' \
|
||||
-e 's; $(top_builddir)/; $$(top_builddir)/;g' \
|
||||
-e 's; \./; ;g' \
|
||||
-e '/^#/d' \
|
||||
-e '/^ *\\$$/d' | \
|
||||
$(PERL) $(top_srcdir)/wordwrap.pl > .depend; \
|
||||
else :; fi
|
||||
|
||||
depend:: .depend
|
||||
if test -n "$(SRCS)" ; then \
|
||||
sed -e '/^# +++ Dependency line eater +++/,$$d' \
|
||||
< $(srcdir)/Makefile.in | cat - .depend \
|
||||
> $(srcdir)/Makefile.in.new; \
|
||||
if cmp -s $(srcdir)/Makefile.in $(srcdir)/Makefile.in.new ; then \
|
||||
$(RM) $(srcdir)/Makefile.in.new ; \
|
||||
else \
|
||||
$(MV) $(srcdir)/Makefile.in $(srcdir)/Makefile.in.old; \
|
||||
$(MV) $(srcdir)/Makefile.in.new $(srcdir)/Makefile.in; \
|
||||
fi ; else :; fi
|
||||
|
||||
# End of file MCONFIG
|
||||
170
2025-03-19/e2fsprogs-1.46.2/Makefile.in
Normal file
170
2025-03-19/e2fsprogs-1.46.2/Makefile.in
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
top_builddir = .
|
||||
my_dir = .
|
||||
INSTALL = @INSTALL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
|
||||
@MCONFIG@
|
||||
|
||||
% : %.sh
|
||||
|
||||
@RESIZER_CMT@RESIZE_DIR= resize
|
||||
@DEBUGFS_CMT@DEBUGFS_DIR= debugfs
|
||||
@UUID_CMT@UUID_LIB_SUBDIR= lib/uuid
|
||||
@BLKID_CMT@BLKID_LIB_SUBDIR= lib/blkid
|
||||
@E2SCRUB_CMT@E2SCRUB_DIR= scrub
|
||||
@ALL_CMT@SUPPORT_LIB_SUBDIR= lib/support
|
||||
@ALL_CMT@E2P_LIB_SUBDIR= lib/e2p
|
||||
@ALL_CMT@EXT2FS_LIB_SUBDIR= lib/ext2fs
|
||||
|
||||
LIB_SUBDIRS=lib/et lib/ss $(E2P_LIB_SUBDIR) $(UUID_LIB_SUBDIR) \
|
||||
$(BLKID_LIB_SUBDIR) $(SUPPORT_LIB_SUBDIR) $(EXT2FS_LIB_SUBDIR)
|
||||
|
||||
PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po \
|
||||
$(E2SCRUB_DIR)
|
||||
|
||||
SUBDIRS=util $(LIB_SUBDIRS) $(PROG_SUBDIRS) tests
|
||||
|
||||
SUBS= util/subst.conf lib/config.h $(top_builddir)/lib/dirpaths.h \
|
||||
lib/ext2fs/ext2_types.h lib/blkid/blkid_types.h lib/uuid/uuid_types.h
|
||||
|
||||
TAR=tar
|
||||
|
||||
all:: subs
|
||||
$(MAKE) libs
|
||||
@ALL_CMT@ $(MAKE) progs
|
||||
@ALL_CMT@ $(MAKE) docs
|
||||
|
||||
all-static::
|
||||
$(MAKE) libs
|
||||
@ALL_CMT@ $(MAKE) static-progs
|
||||
|
||||
subs: $(DEP_SUBSTITUTE)
|
||||
@for i in $(SUBS) ; do if test -d `dirname $$i` ; \
|
||||
then $(MAKE) $$i || exit $$? ; fi ; done
|
||||
@(if test -d lib/et ; then cd lib/et && $(MAKE) compile_et; fi)
|
||||
@(if test -d lib/ext2fs ; then cd lib/ext2fs && $(MAKE) ext2_err.h; fi)
|
||||
@(if test -d lib/support ; then cd lib/support && $(MAKE) prof_err.h; fi)
|
||||
|
||||
progs: all-progs-recursive
|
||||
static-progs: all-static-progs-recursive
|
||||
libs: all-libs-recursive
|
||||
all-progs-recursive all-libs-recursive:: subs
|
||||
|
||||
rpm:
|
||||
sh contrib/build-rpm
|
||||
|
||||
docs:
|
||||
-@test -d doc && cd doc && $(MAKE) libext2fs.info
|
||||
|
||||
install-doc-libs:
|
||||
-@test -d doc && cd doc && $(MAKE) install-doc-libs
|
||||
|
||||
uninstall-doc-libs:
|
||||
-@test -d doc && cd doc && $(MAKE) uninstall-doc-libs
|
||||
|
||||
clean-doc:
|
||||
-@test -d doc && cd doc && $(MAKE) clean
|
||||
|
||||
distclean-doc:
|
||||
-test -d doc && cd doc && $(MAKE) distclean
|
||||
|
||||
install: subs all-libs-recursive install-progs-recursive \
|
||||
install-shlibs-libs-recursive install-doc-libs
|
||||
@SUBSET_CMT@ $(MAKE) install-libs
|
||||
|
||||
install-strip: subs all-libs-recursive install-strip-progs-recursive \
|
||||
install-shlibs-strip-libs-recursive install-doc-libs
|
||||
|
||||
uninstall: uninstall-progs-recursive uninstall-shlibs-libs-recursive uninstall-doc-libs
|
||||
|
||||
install-libs: install-libs-recursive
|
||||
|
||||
uninstall-libs: uninstall-libs-recursive
|
||||
|
||||
coverage.txt: coverage.txt-recursive
|
||||
|
||||
check-recursive: all
|
||||
|
||||
TAGS clean-recursive distclean-recursive depend-recursive fullcheck-recursive \
|
||||
check-recursive mostlyclean-recursive realclean-recursive \
|
||||
coverage.txt-recursive:
|
||||
@for subdir in $(SUBDIRS); do \
|
||||
if test -d $$subdir ; then \
|
||||
target=`echo $@|$(SED) 's/-recursive//'`; \
|
||||
echo making $$target in $$subdir; \
|
||||
(cd $$subdir && $(MAKE) $$target) || exit 1; \
|
||||
fi ; \
|
||||
done
|
||||
|
||||
all-progs-recursive install-progs-recursive install-strip-progs-recursive \
|
||||
uninstall-progs-recursive coverage.txt-progs-recursive:: all-libs-recursive
|
||||
|
||||
|
||||
@ALL_CMT@all-progs-recursive all-static-progs-recursive install-progs-recursive \
|
||||
@ALL_CMT@ install-strip-progs-recursive uninstall-progs-recursive \
|
||||
@ALL_CMT@ coverage.txt-progs-recursive:: all-libs-recursive
|
||||
@ALL_CMT@ @for subdir in $(PROG_SUBDIRS); do \
|
||||
@ALL_CMT@ if test -d $$subdir ; then \
|
||||
@ALL_CMT@ target=`echo $@|$(SED) 's/-progs-recursive//'`; \
|
||||
@ALL_CMT@ echo making $$target in $$subdir; \
|
||||
@ALL_CMT@ (cd $$subdir && $(MAKE) $$target) || exit 1; \
|
||||
@ALL_CMT@ fi ; \
|
||||
@ALL_CMT@ done
|
||||
|
||||
all-libs-recursive install-libs-recursive install-strip-libs-recursive \
|
||||
uninstall-libs-recursive install-shlibs-libs-recursive \
|
||||
install-shlibs-strip-libs-recursive uninstall-shlibs-libs-recursive \
|
||||
coverage.txt-libs-recursive::
|
||||
@for subdir in $(LIB_SUBDIRS); do \
|
||||
if test -d $$subdir ; then \
|
||||
target=`echo $@|$(SED) 's/-libs-recursive//'`; \
|
||||
echo making $$target in $$subdir; \
|
||||
(cd $$subdir && $(MAKE) $$target) || exit 1; \
|
||||
fi ; \
|
||||
done
|
||||
|
||||
mostlyclean: mostlyclean-recursive mostlyclean-local
|
||||
|
||||
clean:: clean-recursive clean-local clean-doc
|
||||
$(RM) -f $(SUBS)
|
||||
|
||||
distclean: distclean-doc distclean-recursive
|
||||
$(RM) -rf autom4te.cache ext2ed/Makefile po/stamp-po \
|
||||
asm_types.h config.log public_config.h parse-types.log
|
||||
$(MAKE) distclean-local
|
||||
|
||||
realclean: realclean-recursive realclean-local
|
||||
|
||||
depend:: depend-recursive
|
||||
|
||||
lib/ext2fs/ext2_types.h: $(DEP_SUBSTITUTE) asm_types.h \
|
||||
$(srcdir)/lib/ext2fs/ext2_types.h.in
|
||||
cd $(top_builddir); CONFIG_FILES=./lib/ext2fs/ext2_types.h ./config.status
|
||||
|
||||
lib/blkid/blkid_types.h: $(DEP_SUBSTITUTE) asm_types.h \
|
||||
$(srcdir)/lib/blkid/blkid_types.h.in
|
||||
cd $(top_builddir); CONFIG_FILES=./lib/blkid/blkid_types.h ./config.status
|
||||
|
||||
lib/uuid/uuid_types.h: $(DEP_SUBSTITUTE) asm_types.h \
|
||||
$(srcdir)/lib/uuid/uuid_types.h.in
|
||||
cd $(top_builddir); CONFIG_FILES=./lib/uuid/uuid_types.h ./config.status
|
||||
|
||||
mostlyclean-local:
|
||||
$(RM) -f \#* *~ *.orig core MAKELOG
|
||||
|
||||
clean-local: mostlyclean-local
|
||||
|
||||
distclean-local: clean-local
|
||||
$(RM) -f $(SUBS) $(SUBST_CONF) \
|
||||
config.status config.log config.cache MCONFIG Makefile \
|
||||
$(srcdir)/TAGS $(srcdir)/Makefile.in.old
|
||||
|
||||
realclean-local: distclean-local
|
||||
$(RM) -f configure
|
||||
|
||||
check:: all check-recursive
|
||||
|
||||
fullcheck:: all fullcheck-recursive
|
||||
849
2025-03-19/e2fsprogs-1.46.2/NOTICE
Normal file
849
2025-03-19/e2fsprogs-1.46.2/NOTICE
Normal file
|
|
@ -0,0 +1,849 @@
|
|||
This package, the EXT2 filesystem utilities, are made available under
|
||||
the GNU Public License version 2, with the exception of the lib/ext2fs
|
||||
and lib/e2p libraries, which are made available under the GNU Library
|
||||
General Public License Version 2, the lib/uuid library which is made
|
||||
available under a BSD-style license and the lib/et and lib/ss
|
||||
libraries which are made available under an MIT-style license. Please
|
||||
see lib/uuid/COPYING for more details for the license for the files
|
||||
comprising the libuuid library, and the source file headers of the
|
||||
libet and libss libraries for more information.
|
||||
|
||||
The most recent officially distributed version can be found at
|
||||
http://e2fsprogs.sourceforge.net. If you need to make a distribution,
|
||||
that's the one you should use. If there is some reason why you'd like
|
||||
a more recent version that is still in ALPHA testing (i.e., either
|
||||
using the "WIP" test distributions or one from the hg or git
|
||||
repository from the development branch, please contact me
|
||||
(tytso@mit.edu) before you ship. The release schedules for this
|
||||
package are flexible, if you give me enough lead time.
|
||||
|
||||
|
||||
Theodore Ts'o
|
||||
23-June-2007
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
19
2025-03-19/e2fsprogs-1.46.2/README
Normal file
19
2025-03-19/e2fsprogs-1.46.2/README
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
This is the new version (1.46.2) of the second extended file
|
||||
system management programs.
|
||||
|
||||
From time to time, I release new versions of e2fsprogs, to fix
|
||||
bugs and to make the utilities more robust. You can always find
|
||||
information about the latest version at the the e2fsprogs web page,
|
||||
which is:
|
||||
|
||||
http://e2fsprogs.sourceforge.net
|
||||
|
||||
The INSTALL file has instructions on building and installing
|
||||
e2fsprogs. Provisions for building Red Hat RPMs and Debian dpkg files
|
||||
are supplied as well.
|
||||
|
||||
In case of bugs in these programs, please contact Ted Ts'o at
|
||||
tytso@mit.edu or tytso@alum.mit.edu. See the e2fsck man page for
|
||||
suggestions of what sort of information to include when submitting bug
|
||||
reports for these programs.
|
||||
|
||||
64
2025-03-19/e2fsprogs-1.46.2/RELEASE-NOTES
Normal file
64
2025-03-19/e2fsprogs-1.46.2/RELEASE-NOTES
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
E2fsprogs 1.46.2 (February 28, 2021)
|
||||
===================================
|
||||
|
||||
Updates/Fixes since v1.46.1:
|
||||
|
||||
UI and Features
|
||||
---------------
|
||||
|
||||
Teach the tune2fs program to support "random" as an argument to the -c
|
||||
option, which sets the maximum mount count. (Addresses Debian Bug:
|
||||
#926293)
|
||||
|
||||
Add support for the FS_NOCOMP_FL flag to chattr and lsattr.
|
||||
|
||||
|
||||
Fixes
|
||||
-----
|
||||
|
||||
When resizing a small file systems to a super-large file system size,
|
||||
avoid issuing some scary bitmap operation warnings. (Addresses Github
|
||||
issue https://github.com/tytso/e2fsprogs/issues/60)
|
||||
|
||||
Fix the debugfs rdump and ls commands so they will work correctly for
|
||||
uid's and gid's => 65536. (Addresses Github issue issue
|
||||
https://github.com/tytso/e2fsprogs/issues/63)
|
||||
|
||||
Fix the debugfs write and symlink commands so they support targets which
|
||||
contain a pathname (instead of only working when writing a file or
|
||||
creating a symlink in the current directory). (Addresses Github issue
|
||||
https://github.com/tytso/e2fsprogs/issues/61)
|
||||
|
||||
Fix Direct I/O support on block devices where the logical block size is
|
||||
greater 1k. (This includes Advanced Format HDD's, where the sector size
|
||||
is 4k, and IBM Mainframe DASD's, where the sector size is 2k.)
|
||||
|
||||
Fix debugfs's logdump so it works on file systems whose block size is
|
||||
greater than 8k.
|
||||
|
||||
Fix a where e2fsck could a crash when there is error while e2fsck is
|
||||
trying to open the file system, and e2fsck calls ext2fs_mmp_stop()
|
||||
before MMP has been initialized. (Addresses Debian Bug: #696609)
|
||||
|
||||
Improved error checking in the fast commit replay code in e2fsck.
|
||||
|
||||
Updated and clarified the chattr man page.
|
||||
|
||||
|
||||
Performance, Internal Implementation, Development Support etc.
|
||||
--------------------------------------------------------------
|
||||
|
||||
Fix various compiler and Coverity warnings.
|
||||
|
||||
Update the Spanish translation from the translation project.
|
||||
|
||||
Update the e2fsck/iscan.c test program so that it builds again.
|
||||
|
||||
Fix an environmental dependency bug for the m_rootdir_acl regression
|
||||
test.
|
||||
|
||||
Avoid the use of loff_t, which is not available for all compilers /
|
||||
system include files.
|
||||
|
||||
Fix failure of the t_mmp_fail test when running on a device with a 4k
|
||||
logical sector size.
|
||||
35
2025-03-19/e2fsprogs-1.46.2/SHLIBS
Normal file
35
2025-03-19/e2fsprogs-1.46.2/SHLIBS
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
Library:libcom_err.o
|
||||
Description: Common error code library
|
||||
Maintainer: Theodore Ts'o
|
||||
Email: tytso@mit.edu
|
||||
Start: 0x66800000
|
||||
End: 0x6687ffff
|
||||
|
||||
Library:libss.o
|
||||
Description: Generic Subsystem library (Simple tty UI)
|
||||
Maintainer: Theodore Ts'o
|
||||
Email: tytso@mit.edu
|
||||
Start: 0x66880000
|
||||
End: 0x668fffff
|
||||
|
||||
Library:libext2fs.so
|
||||
Description: The ext2fs (raw interface) library
|
||||
Maintainer: Theodore Ts'o
|
||||
Email: tytso@mit.edu
|
||||
Start: 0x66900000
|
||||
End: 0x6697ffff
|
||||
|
||||
Library:libe2p.so
|
||||
Description: The e2p (ext2fs's programmers) library
|
||||
Maintainer: Theodore Ts'o
|
||||
Email: tytso@mit.edu
|
||||
Start: 0x66980000
|
||||
End: 0x669fffff
|
||||
|
||||
Library:libuuid.so
|
||||
Description: DCE Universally Unique ID (UUID) library
|
||||
Maintainer: Theodore Ts'o
|
||||
Email: tytso@mit.edu
|
||||
Start: 0x67900000
|
||||
End: 0x679fffff
|
||||
|
||||
39
2025-03-19/e2fsprogs-1.46.2/SUBMITTING-PATCHES
Normal file
39
2025-03-19/e2fsprogs-1.46.2/SUBMITTING-PATCHES
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
Like the Linux kernel, submitted e2fsprogs patches now require the
|
||||
following "sign-off" procedure:
|
||||
|
||||
The sign-off is a simple line at the end of the explanation for the
|
||||
patch, which certifies that you wrote it or otherwise have the right to
|
||||
pass it on as a open-source patch. The rules are pretty simple: if you
|
||||
can certify the below:
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
|
||||
then you just add a line saying
|
||||
|
||||
Signed-off-by: Random J Developer <random@developer.example.org>
|
||||
|
||||
178
2025-03-19/e2fsprogs-1.46.2/acinclude.m4
Normal file
178
2025-03-19/e2fsprogs-1.46.2/acinclude.m4
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
# from http://autoconf-archive.cryp.to/ax_tls.html
|
||||
#
|
||||
# This was licensed under the GPL with the following exception:
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright
|
||||
# owner gives unlimited permission to copy, distribute and modify the
|
||||
# configure scripts that are the output of Autoconf when processing
|
||||
# the Macro. You need not follow the terms of the GNU General Public
|
||||
# License when using or distributing such scripts, even though
|
||||
# portions of the text of the Macro appear in them. The GNU General
|
||||
# Public License (GPL) does govern all other use of the material that
|
||||
# constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the
|
||||
# Autoconf Macro released by the Autoconf Macro Archive. When you make
|
||||
# and distribute a modified version of the Autoconf Macro, you may
|
||||
# extend this special exception to the GPL to apply to your modified
|
||||
# version as well.
|
||||
#
|
||||
AC_DEFUN([AX_TLS], [
|
||||
AC_MSG_CHECKING(for thread local storage (TLS) class)
|
||||
AC_CACHE_VAL(ac_cv_tls, [
|
||||
ax_tls_keywords="__thread __declspec(thread) none"
|
||||
for ax_tls_keyword in $ax_tls_keywords; do
|
||||
case $ax_tls_keyword in
|
||||
none) ac_cv_tls=none ; break ;;
|
||||
*)
|
||||
AC_TRY_COMPILE(
|
||||
[#include <stdlib.h>
|
||||
static void
|
||||
foo(void) {
|
||||
static ] $ax_tls_keyword [ int bar;
|
||||
exit(1);
|
||||
}],
|
||||
[],
|
||||
[ac_cv_tls=$ax_tls_keyword ; break],
|
||||
ac_cv_tls=none
|
||||
)
|
||||
esac
|
||||
done
|
||||
])
|
||||
|
||||
if test "$ac_cv_tls" != "none"; then
|
||||
dnl AC_DEFINE([TLS], [], [If the compiler supports a TLS storage class define it to that here])
|
||||
AC_DEFINE_UNQUOTED([TLS], $ac_cv_tls, [If the compiler supports a TLS storage class define it to that here])
|
||||
fi
|
||||
AC_MSG_RESULT($ac_cv_tls)
|
||||
])
|
||||
|
||||
# ===========================================================================
|
||||
# http://www.nongnu.org/autoconf-archive/check_gnu_make.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# CHECK_GNU_MAKE()
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro searches for a GNU version of make. If a match is found, the
|
||||
# makefile variable `ifGNUmake' is set to the empty string, otherwise it
|
||||
# is set to "#". This is useful for including a special features in a
|
||||
# Makefile, which cannot be handled by other versions of make. The
|
||||
# variable _cv_gnu_make_command is set to the command to invoke GNU make
|
||||
# if it exists, the empty string otherwise.
|
||||
#
|
||||
# Here is an example of its use:
|
||||
#
|
||||
# Makefile.in might contain:
|
||||
#
|
||||
# # A failsafe way of putting a dependency rule into a makefile
|
||||
# $(DEPEND):
|
||||
# $(CC) -MM $(srcdir)/*.c > $(DEPEND)
|
||||
#
|
||||
# @ifGNUmake@ ifeq ($(DEPEND),$(wildcard $(DEPEND)))
|
||||
# @ifGNUmake@ include $(DEPEND)
|
||||
# @ifGNUmake@ endif
|
||||
#
|
||||
# Then configure.in would normally contain:
|
||||
#
|
||||
# CHECK_GNU_MAKE()
|
||||
# AC_OUTPUT(Makefile)
|
||||
#
|
||||
# Then perhaps to cause gnu make to override any other make, we could do
|
||||
# something like this (note that GNU make always looks for GNUmakefile
|
||||
# first):
|
||||
#
|
||||
# if ! test x$_cv_gnu_make_command = x ; then
|
||||
# mv Makefile GNUmakefile
|
||||
# echo .DEFAULT: > Makefile ;
|
||||
# echo \ $_cv_gnu_make_command \$@ >> Makefile;
|
||||
# fi
|
||||
#
|
||||
# Then, if any (well almost any) other make is called, and GNU make also
|
||||
# exists, then the other make wraps the GNU make.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 John Darrington <j.darrington@elvis.murdoch.edu.au>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved.
|
||||
#
|
||||
# Note: Modified by Ted Ts'o to add @ifNotGNUMake@
|
||||
|
||||
AC_DEFUN(
|
||||
[CHECK_GNU_MAKE], [ AC_CACHE_CHECK( for GNU make,_cv_gnu_make_command,
|
||||
_cv_gnu_make_command='' ;
|
||||
dnl Search all the common names for GNU make
|
||||
if test -n "$FORCE_NATIVE_MAKE" ; then
|
||||
MAKES="make"
|
||||
else
|
||||
MAKES="make gmake gnumake"
|
||||
fi
|
||||
for a in "$MAKE" $MAKES ; do
|
||||
if test -z "$a" ; then continue ; fi ;
|
||||
if ( sh -c "$a --version" 2> /dev/null | grep GNU 2>&1 > /dev/null ) ; then
|
||||
_cv_gnu_make_command=$a ;
|
||||
break;
|
||||
fi
|
||||
done ;
|
||||
) ;
|
||||
dnl If there was a GNU version, then set @ifGNUmake@ to the empty string, '#' otherwise
|
||||
if test "x$_cv_gnu_make_command" != "x" ; then
|
||||
ifGNUmake='' ;
|
||||
ifNotGNUmake='#' ;
|
||||
else
|
||||
ifGNUmake='#' ;
|
||||
ifNotGNUmake='' ;
|
||||
AC_MSG_RESULT("Not found");
|
||||
fi
|
||||
AC_SUBST(ifGNUmake)
|
||||
AC_SUBST(ifNotGNUmake)
|
||||
] )
|
||||
|
||||
# AX_CHECK_MOUNT_OPT: an autoconf macro to check for generic filesystem-
|
||||
# agnostic 'mount' options. Written by Nicholas Clark. Looks for constants in
|
||||
# sys/mount.h to predict whether the 'mount' utility will support a specific
|
||||
# mounting option.
|
||||
#
|
||||
# This macro can be used to check for the presence of 'nodev' (or other mount
|
||||
# options), which isn't uniformly implemented in the BSD family at the time of
|
||||
# this writing. Tested on FreeBSD, NetBSD, OpenBSD, and Linux.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# AX_CHECK_MOUNT_OPT(option)
|
||||
#
|
||||
# Defines HAVE_MOUNT_$OPTION (in uppercase) if the option exists, and sets
|
||||
# ac_cv_mount_$option (in original case) otherwise.
|
||||
#
|
||||
# Copyright (c) 2018 Nicholas Clark <nicholas.clark@gmail.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty or attribution requirement.
|
||||
|
||||
AC_DEFUN([AX_CHECK_MOUNT_OPT], [__AX_CHECK_MOUNT_OPT(m4_tolower([$1]),m4_toupper([$1]))])
|
||||
AC_DEFUN([__AX_CHECK_MOUNT_OPT],
|
||||
[
|
||||
AS_ECHO_N("checking for mount '$1' option... ")
|
||||
AC_TRY_COMPILE(
|
||||
[#include <sys/mount.h>],
|
||||
[void *temp = (void *)(MS_$2); (void) temp;],
|
||||
[AC_DEFINE(HAVE_MOUNT_$2, 1, [Define to 1 if mount supports $1.])
|
||||
AS_VAR_SET(ac_cv_mount_$1, yes)
|
||||
AS_ECHO("yes")],
|
||||
[AC_TRY_COMPILE(
|
||||
[#include <sys/mount.h>],
|
||||
[void *temp = (void *)(MNT_$2); (void) temp;],
|
||||
[AC_DEFINE(HAVE_MOUNT_$2, 1, [Define to 1 if mount supports $1.])
|
||||
AS_VAR_SET(ac_cv_mount_$1, yes)
|
||||
AS_ECHO("yes")],
|
||||
[AS_VAR_SET(ac_cv_mount_$1, no)
|
||||
AS_ECHO("no")]
|
||||
)]
|
||||
)
|
||||
])
|
||||
4062
2025-03-19/e2fsprogs-1.46.2/aclocal.m4
vendored
Normal file
4062
2025-03-19/e2fsprogs-1.46.2/aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load diff
1667
2025-03-19/e2fsprogs-1.46.2/config/config.guess
vendored
Executable file
1667
2025-03-19/e2fsprogs-1.46.2/config/config.guess
vendored
Executable file
File diff suppressed because it is too large
Load diff
684
2025-03-19/e2fsprogs-1.46.2/config/config.rpath
Executable file
684
2025-03-19/e2fsprogs-1.46.2/config/config.rpath
Executable file
|
|
@ -0,0 +1,684 @@
|
|||
#! /bin/sh
|
||||
# Output a system dependent set of variables, describing how to set the
|
||||
# run time search path of shared libraries in an executable.
|
||||
#
|
||||
# Copyright 1996-2016 Free Software Foundation, Inc.
|
||||
# Taken from GNU libtool, 2001
|
||||
# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
|
||||
#
|
||||
# This file is free software; the Free Software Foundation gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# The first argument passed to this file is the canonical host specification,
|
||||
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
|
||||
# or
|
||||
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
|
||||
# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
|
||||
# should be set by the caller.
|
||||
#
|
||||
# The set of defined variables is at the end of this script.
|
||||
|
||||
# Known limitations:
|
||||
# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
|
||||
# than 256 bytes, otherwise the compiler driver will dump core. The only
|
||||
# known workaround is to choose shorter directory names for the build
|
||||
# directory and/or the installation directory.
|
||||
|
||||
# All known linkers require a '.a' archive for static linking (except MSVC,
|
||||
# which needs '.lib').
|
||||
libext=a
|
||||
shrext=.so
|
||||
|
||||
host="$1"
|
||||
host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
|
||||
host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
|
||||
host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
|
||||
|
||||
# Code taken from libtool.m4's _LT_CC_BASENAME.
|
||||
|
||||
for cc_temp in $CC""; do
|
||||
case $cc_temp in
|
||||
compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
|
||||
distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
|
||||
\-*) ;;
|
||||
*) break;;
|
||||
esac
|
||||
done
|
||||
cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
|
||||
|
||||
# Code taken from libtool.m4's _LT_COMPILER_PIC.
|
||||
|
||||
wl=
|
||||
if test "$GCC" = yes; then
|
||||
wl='-Wl,'
|
||||
else
|
||||
case "$host_os" in
|
||||
aix*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
mingw* | cygwin* | pw32* | os2* | cegcc*)
|
||||
;;
|
||||
hpux9* | hpux10* | hpux11*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
irix5* | irix6* | nonstopux*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
case $cc_basename in
|
||||
ecc*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
icc* | ifort*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
lf95*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
nagfor*)
|
||||
wl='-Wl,-Wl,,'
|
||||
;;
|
||||
pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
ccc*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
xl* | bgxl* | bgf* | mpixl*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
como)
|
||||
wl='-lopt='
|
||||
;;
|
||||
*)
|
||||
case `$CC -V 2>&1 | sed 5q` in
|
||||
*Sun\ F* | *Sun*Fortran*)
|
||||
wl=
|
||||
;;
|
||||
*Sun\ C*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
newsos6)
|
||||
;;
|
||||
*nto* | *qnx*)
|
||||
;;
|
||||
osf3* | osf4* | osf5*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
rdos*)
|
||||
;;
|
||||
solaris*)
|
||||
case $cc_basename in
|
||||
f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
|
||||
wl='-Qoption ld '
|
||||
;;
|
||||
*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
sunos4*)
|
||||
wl='-Qoption ld '
|
||||
;;
|
||||
sysv4 | sysv4.2uw2* | sysv4.3*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
sysv4*MP*)
|
||||
;;
|
||||
sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
unicos*)
|
||||
wl='-Wl,'
|
||||
;;
|
||||
uts4*)
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Code taken from libtool.m4's _LT_LINKER_SHLIBS.
|
||||
|
||||
hardcode_libdir_flag_spec=
|
||||
hardcode_libdir_separator=
|
||||
hardcode_direct=no
|
||||
hardcode_minus_L=no
|
||||
|
||||
case "$host_os" in
|
||||
cygwin* | mingw* | pw32* | cegcc*)
|
||||
# FIXME: the MSVC++ port hasn't been tested in a loooong time
|
||||
# When not using gcc, we currently assume that we are using
|
||||
# Microsoft Visual C++.
|
||||
if test "$GCC" != yes; then
|
||||
with_gnu_ld=no
|
||||
fi
|
||||
;;
|
||||
interix*)
|
||||
# we just hope/assume this is gcc and not c89 (= MSVC++)
|
||||
with_gnu_ld=yes
|
||||
;;
|
||||
openbsd*)
|
||||
with_gnu_ld=no
|
||||
;;
|
||||
esac
|
||||
|
||||
ld_shlibs=yes
|
||||
if test "$with_gnu_ld" = yes; then
|
||||
# Set some defaults for GNU ld with shared library support. These
|
||||
# are reset later if shared libraries are not supported. Putting them
|
||||
# here allows them to be overridden if necessary.
|
||||
# Unlike libtool, we use -rpath here, not --rpath, since the documented
|
||||
# option of GNU ld is called -rpath, not --rpath.
|
||||
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
|
||||
case "$host_os" in
|
||||
aix[3-9]*)
|
||||
# On AIX/PPC, the GNU linker is very broken
|
||||
if test "$host_cpu" != ia64; then
|
||||
ld_shlibs=no
|
||||
fi
|
||||
;;
|
||||
amigaos*)
|
||||
case "$host_cpu" in
|
||||
powerpc)
|
||||
;;
|
||||
m68k)
|
||||
hardcode_libdir_flag_spec='-L$libdir'
|
||||
hardcode_minus_L=yes
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
beos*)
|
||||
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
|
||||
:
|
||||
else
|
||||
ld_shlibs=no
|
||||
fi
|
||||
;;
|
||||
cygwin* | mingw* | pw32* | cegcc*)
|
||||
# hardcode_libdir_flag_spec is actually meaningless, as there is
|
||||
# no search path for DLLs.
|
||||
hardcode_libdir_flag_spec='-L$libdir'
|
||||
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
|
||||
:
|
||||
else
|
||||
ld_shlibs=no
|
||||
fi
|
||||
;;
|
||||
haiku*)
|
||||
;;
|
||||
interix[3-9]*)
|
||||
hardcode_direct=no
|
||||
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
|
||||
;;
|
||||
gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
|
||||
:
|
||||
else
|
||||
ld_shlibs=no
|
||||
fi
|
||||
;;
|
||||
netbsd*)
|
||||
;;
|
||||
solaris*)
|
||||
if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
|
||||
ld_shlibs=no
|
||||
elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
|
||||
:
|
||||
else
|
||||
ld_shlibs=no
|
||||
fi
|
||||
;;
|
||||
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
|
||||
case `$LD -v 2>&1` in
|
||||
*\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
|
||||
ld_shlibs=no
|
||||
;;
|
||||
*)
|
||||
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
|
||||
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
|
||||
else
|
||||
ld_shlibs=no
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
sunos4*)
|
||||
hardcode_direct=yes
|
||||
;;
|
||||
*)
|
||||
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
|
||||
:
|
||||
else
|
||||
ld_shlibs=no
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
if test "$ld_shlibs" = no; then
|
||||
hardcode_libdir_flag_spec=
|
||||
fi
|
||||
else
|
||||
case "$host_os" in
|
||||
aix3*)
|
||||
# Note: this linker hardcodes the directories in LIBPATH if there
|
||||
# are no directories specified by -L.
|
||||
hardcode_minus_L=yes
|
||||
if test "$GCC" = yes; then
|
||||
# Neither direct hardcoding nor static linking is supported with a
|
||||
# broken collect2.
|
||||
hardcode_direct=unsupported
|
||||
fi
|
||||
;;
|
||||
aix[4-9]*)
|
||||
if test "$host_cpu" = ia64; then
|
||||
# On IA64, the linker does run time linking by default, so we don't
|
||||
# have to do anything special.
|
||||
aix_use_runtimelinking=no
|
||||
else
|
||||
aix_use_runtimelinking=no
|
||||
# Test if we are trying to use run time linking or normal
|
||||
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
|
||||
# need to do runtime linking.
|
||||
case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
|
||||
for ld_flag in $LDFLAGS; do
|
||||
if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
|
||||
aix_use_runtimelinking=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
hardcode_direct=yes
|
||||
hardcode_libdir_separator=':'
|
||||
if test "$GCC" = yes; then
|
||||
case $host_os in aix4.[012]|aix4.[012].*)
|
||||
collect2name=`${CC} -print-prog-name=collect2`
|
||||
if test -f "$collect2name" && \
|
||||
strings "$collect2name" | grep resolve_lib_name >/dev/null
|
||||
then
|
||||
# We have reworked collect2
|
||||
:
|
||||
else
|
||||
# We have old collect2
|
||||
hardcode_direct=unsupported
|
||||
hardcode_minus_L=yes
|
||||
hardcode_libdir_flag_spec='-L$libdir'
|
||||
hardcode_libdir_separator=
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
# Begin _LT_AC_SYS_LIBPATH_AIX.
|
||||
echo 'int main () { return 0; }' > conftest.c
|
||||
${CC} ${LDFLAGS} conftest.c -o conftest
|
||||
aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
|
||||
}'`
|
||||
if test -z "$aix_libpath"; then
|
||||
aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
|
||||
}'`
|
||||
fi
|
||||
if test -z "$aix_libpath"; then
|
||||
aix_libpath="/usr/lib:/lib"
|
||||
fi
|
||||
rm -f conftest.c conftest
|
||||
# End _LT_AC_SYS_LIBPATH_AIX.
|
||||
if test "$aix_use_runtimelinking" = yes; then
|
||||
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
|
||||
else
|
||||
if test "$host_cpu" = ia64; then
|
||||
hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
|
||||
else
|
||||
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
amigaos*)
|
||||
case "$host_cpu" in
|
||||
powerpc)
|
||||
;;
|
||||
m68k)
|
||||
hardcode_libdir_flag_spec='-L$libdir'
|
||||
hardcode_minus_L=yes
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
bsdi[45]*)
|
||||
;;
|
||||
cygwin* | mingw* | pw32* | cegcc*)
|
||||
# When not using gcc, we currently assume that we are using
|
||||
# Microsoft Visual C++.
|
||||
# hardcode_libdir_flag_spec is actually meaningless, as there is
|
||||
# no search path for DLLs.
|
||||
hardcode_libdir_flag_spec=' '
|
||||
libext=lib
|
||||
;;
|
||||
darwin* | rhapsody*)
|
||||
hardcode_direct=no
|
||||
if { case $cc_basename in ifort*) true;; *) test "$GCC" = yes;; esac; }; then
|
||||
:
|
||||
else
|
||||
ld_shlibs=no
|
||||
fi
|
||||
;;
|
||||
dgux*)
|
||||
hardcode_libdir_flag_spec='-L$libdir'
|
||||
;;
|
||||
freebsd2.[01]*)
|
||||
hardcode_direct=yes
|
||||
hardcode_minus_L=yes
|
||||
;;
|
||||
freebsd* | dragonfly*)
|
||||
hardcode_libdir_flag_spec='-R$libdir'
|
||||
hardcode_direct=yes
|
||||
;;
|
||||
hpux9*)
|
||||
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
|
||||
hardcode_libdir_separator=:
|
||||
hardcode_direct=yes
|
||||
# hardcode_minus_L: Not really in the search PATH,
|
||||
# but as the default location of the library.
|
||||
hardcode_minus_L=yes
|
||||
;;
|
||||
hpux10*)
|
||||
if test "$with_gnu_ld" = no; then
|
||||
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
|
||||
hardcode_libdir_separator=:
|
||||
hardcode_direct=yes
|
||||
# hardcode_minus_L: Not really in the search PATH,
|
||||
# but as the default location of the library.
|
||||
hardcode_minus_L=yes
|
||||
fi
|
||||
;;
|
||||
hpux11*)
|
||||
if test "$with_gnu_ld" = no; then
|
||||
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
|
||||
hardcode_libdir_separator=:
|
||||
case $host_cpu in
|
||||
hppa*64*|ia64*)
|
||||
hardcode_direct=no
|
||||
;;
|
||||
*)
|
||||
hardcode_direct=yes
|
||||
# hardcode_minus_L: Not really in the search PATH,
|
||||
# but as the default location of the library.
|
||||
hardcode_minus_L=yes
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
irix5* | irix6* | nonstopux*)
|
||||
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
|
||||
hardcode_libdir_separator=:
|
||||
;;
|
||||
netbsd*)
|
||||
hardcode_libdir_flag_spec='-R$libdir'
|
||||
hardcode_direct=yes
|
||||
;;
|
||||
newsos6)
|
||||
hardcode_direct=yes
|
||||
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
|
||||
hardcode_libdir_separator=:
|
||||
;;
|
||||
*nto* | *qnx*)
|
||||
;;
|
||||
openbsd*)
|
||||
if test -f /usr/libexec/ld.so; then
|
||||
hardcode_direct=yes
|
||||
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
|
||||
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
|
||||
else
|
||||
case "$host_os" in
|
||||
openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
|
||||
hardcode_libdir_flag_spec='-R$libdir'
|
||||
;;
|
||||
*)
|
||||
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else
|
||||
ld_shlibs=no
|
||||
fi
|
||||
;;
|
||||
os2*)
|
||||
hardcode_libdir_flag_spec='-L$libdir'
|
||||
hardcode_minus_L=yes
|
||||
;;
|
||||
osf3*)
|
||||
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
|
||||
hardcode_libdir_separator=:
|
||||
;;
|
||||
osf4* | osf5*)
|
||||
if test "$GCC" = yes; then
|
||||
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
|
||||
else
|
||||
# Both cc and cxx compiler support -rpath directly
|
||||
hardcode_libdir_flag_spec='-rpath $libdir'
|
||||
fi
|
||||
hardcode_libdir_separator=:
|
||||
;;
|
||||
solaris*)
|
||||
hardcode_libdir_flag_spec='-R$libdir'
|
||||
;;
|
||||
sunos4*)
|
||||
hardcode_libdir_flag_spec='-L$libdir'
|
||||
hardcode_direct=yes
|
||||
hardcode_minus_L=yes
|
||||
;;
|
||||
sysv4)
|
||||
case $host_vendor in
|
||||
sni)
|
||||
hardcode_direct=yes # is this really true???
|
||||
;;
|
||||
siemens)
|
||||
hardcode_direct=no
|
||||
;;
|
||||
motorola)
|
||||
hardcode_direct=no #Motorola manual says yes, but my tests say they lie
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
sysv4.3*)
|
||||
;;
|
||||
sysv4*MP*)
|
||||
if test -d /usr/nec; then
|
||||
ld_shlibs=yes
|
||||
fi
|
||||
;;
|
||||
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
|
||||
;;
|
||||
sysv5* | sco3.2v5* | sco5v6*)
|
||||
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
|
||||
hardcode_libdir_separator=':'
|
||||
;;
|
||||
uts4*)
|
||||
hardcode_libdir_flag_spec='-L$libdir'
|
||||
;;
|
||||
*)
|
||||
ld_shlibs=no
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Check dynamic linker characteristics
|
||||
# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER.
|
||||
# Unlike libtool.m4, here we don't care about _all_ names of the library, but
|
||||
# only about the one the linker finds when passed -lNAME. This is the last
|
||||
# element of library_names_spec in libtool.m4, or possibly two of them if the
|
||||
# linker has special search rules.
|
||||
library_names_spec= # the last element of library_names_spec in libtool.m4
|
||||
libname_spec='lib$name'
|
||||
case "$host_os" in
|
||||
aix3*)
|
||||
library_names_spec='$libname.a'
|
||||
;;
|
||||
aix[4-9]*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
amigaos*)
|
||||
case "$host_cpu" in
|
||||
powerpc*)
|
||||
library_names_spec='$libname$shrext' ;;
|
||||
m68k)
|
||||
library_names_spec='$libname.a' ;;
|
||||
esac
|
||||
;;
|
||||
beos*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
bsdi[45]*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
cygwin* | mingw* | pw32* | cegcc*)
|
||||
shrext=.dll
|
||||
library_names_spec='$libname.dll.a $libname.lib'
|
||||
;;
|
||||
darwin* | rhapsody*)
|
||||
shrext=.dylib
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
dgux*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
freebsd[23].*)
|
||||
library_names_spec='$libname$shrext$versuffix'
|
||||
;;
|
||||
freebsd* | dragonfly*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
gnu*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
haiku*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
hpux9* | hpux10* | hpux11*)
|
||||
case $host_cpu in
|
||||
ia64*)
|
||||
shrext=.so
|
||||
;;
|
||||
hppa*64*)
|
||||
shrext=.sl
|
||||
;;
|
||||
*)
|
||||
shrext=.sl
|
||||
;;
|
||||
esac
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
interix[3-9]*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
irix5* | irix6* | nonstopux*)
|
||||
library_names_spec='$libname$shrext'
|
||||
case "$host_os" in
|
||||
irix5* | nonstopux*)
|
||||
libsuff= shlibsuff=
|
||||
;;
|
||||
*)
|
||||
case $LD in
|
||||
*-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
|
||||
*-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
|
||||
*-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
|
||||
*) libsuff= shlibsuff= ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
linux*oldld* | linux*aout* | linux*coff*)
|
||||
;;
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
knetbsd*-gnu)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
netbsd*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
newsos6)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
*nto* | *qnx*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
openbsd*)
|
||||
library_names_spec='$libname$shrext$versuffix'
|
||||
;;
|
||||
os2*)
|
||||
libname_spec='$name'
|
||||
shrext=.dll
|
||||
library_names_spec='$libname.a'
|
||||
;;
|
||||
osf3* | osf4* | osf5*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
rdos*)
|
||||
;;
|
||||
solaris*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
sunos4*)
|
||||
library_names_spec='$libname$shrext$versuffix'
|
||||
;;
|
||||
sysv4 | sysv4.3*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
sysv4*MP*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
tpf*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
uts4*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
esac
|
||||
|
||||
sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
|
||||
escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
|
||||
shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
|
||||
escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
|
||||
escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
|
||||
escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
|
||||
|
||||
LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
|
||||
|
||||
# How to pass a linker flag through the compiler.
|
||||
wl="$escaped_wl"
|
||||
|
||||
# Static library suffix (normally "a").
|
||||
libext="$libext"
|
||||
|
||||
# Shared library suffix (normally "so").
|
||||
shlibext="$shlibext"
|
||||
|
||||
# Format of library name prefix.
|
||||
libname_spec="$escaped_libname_spec"
|
||||
|
||||
# Library names that the linker finds when passed -lNAME.
|
||||
library_names_spec="$escaped_library_names_spec"
|
||||
|
||||
# Flag to hardcode \$libdir into a binary during linking.
|
||||
# This must work even if \$libdir does not exist.
|
||||
hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
|
||||
|
||||
# Whether we need a single -rpath flag with a separated argument.
|
||||
hardcode_libdir_separator="$hardcode_libdir_separator"
|
||||
|
||||
# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
|
||||
# resulting binary.
|
||||
hardcode_direct="$hardcode_direct"
|
||||
|
||||
# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
|
||||
# resulting binary.
|
||||
hardcode_minus_L="$hardcode_minus_L"
|
||||
|
||||
EOF
|
||||
1793
2025-03-19/e2fsprogs-1.46.2/config/config.sub
vendored
Executable file
1793
2025-03-19/e2fsprogs-1.46.2/config/config.sub
vendored
Executable file
File diff suppressed because it is too large
Load diff
238
2025-03-19/e2fsprogs-1.46.2/config/install-sh
Executable file
238
2025-03-19/e2fsprogs-1.46.2/config/install-sh
Executable file
|
|
@ -0,0 +1,238 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
#
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
tranformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
||||
11249
2025-03-19/e2fsprogs-1.46.2/config/ltmain.sh
Normal file
11249
2025-03-19/e2fsprogs-1.46.2/config/ltmain.sh
Normal file
File diff suppressed because it is too large
Load diff
40
2025-03-19/e2fsprogs-1.46.2/config/mkinstalldirs
Executable file
40
2025-03-19/e2fsprogs-1.46.2/config/mkinstalldirs
Executable file
|
|
@ -0,0 +1,40 @@
|
|||
#! /bin/sh
|
||||
# mkinstalldirs --- make directory hierarchy
|
||||
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
|
||||
# Created: 1993-05-16
|
||||
# Public domain
|
||||
|
||||
# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $
|
||||
|
||||
errstatus=0
|
||||
|
||||
for file
|
||||
do
|
||||
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
|
||||
shift
|
||||
|
||||
pathcomp=
|
||||
for d
|
||||
do
|
||||
pathcomp="$pathcomp$d"
|
||||
case "$pathcomp" in
|
||||
-* ) pathcomp=./$pathcomp ;;
|
||||
esac
|
||||
|
||||
if test ! -d "$pathcomp"; then
|
||||
echo "mkdir $pathcomp"
|
||||
|
||||
mkdir "$pathcomp" || lasterr=$?
|
||||
|
||||
if test ! -d "$pathcomp"; then
|
||||
errstatus=$lasterr
|
||||
fi
|
||||
fi
|
||||
|
||||
pathcomp="$pathcomp/"
|
||||
done
|
||||
done
|
||||
|
||||
exit $errstatus
|
||||
|
||||
# mkinstalldirs ends here
|
||||
127
2025-03-19/e2fsprogs-1.46.2/config/parse-types.sh
Executable file
127
2025-03-19/e2fsprogs-1.46.2/config/parse-types.sh
Executable file
|
|
@ -0,0 +1,127 @@
|
|||
#!/bin/sh
|
||||
|
||||
cat > sed.script << "EOF"
|
||||
/^#/d
|
||||
/^$/d
|
||||
s/__extension__ //
|
||||
s/typedef \(.*\) __u\([1-9]*\);/#define __U\2_TYPEDEF \1/
|
||||
s/typedef \(.*\) __s\([1-9]*\);/#define __S\2_TYPEDEF \1/
|
||||
EOF
|
||||
|
||||
if test -z "$CC"; then
|
||||
CC=gcc
|
||||
fi
|
||||
|
||||
if test -z "$CPP"; then
|
||||
CPP="$CC -E"
|
||||
fi
|
||||
|
||||
/bin/echo -n "checking for __uNN types... "
|
||||
# can't check [ -f /usr/include/asm/types.h ] directly, since
|
||||
# the include path might be different if cross-compiling
|
||||
if echo '#include <asm/types.h>' | $CPP - 2> parse-types.log | \
|
||||
sed -f sed.script | grep '^#' > asm_types.h; then
|
||||
echo "using <asm/types.h>"
|
||||
else
|
||||
echo "using generic types"
|
||||
fi
|
||||
|
||||
rm sed.script
|
||||
|
||||
cp asm_types.h asm_types.c
|
||||
|
||||
cat >> asm_types.c <<EOF
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef __U8_TYPEDEF
|
||||
if (sizeof(__U8_TYPEDEF) != 1) {
|
||||
printf("Sizeof(__U8__TYPEDEF) is %d should be 1\n",
|
||||
(int) sizeof(__U8_TYPEDEF));
|
||||
exit(1);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#warning __U8_TYPEDEF not defined
|
||||
#endif
|
||||
#ifdef __S8_TYPEDEF
|
||||
if (sizeof(__S8_TYPEDEF) != 1) {
|
||||
printf("Sizeof(_S8__TYPEDEF) is %d should be 1\n",
|
||||
(int) sizeof(__S8_TYPEDEF));
|
||||
exit(1);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#warning __S8_TYPEDEF not defined
|
||||
#endif
|
||||
#ifdef __U16_TYPEDEF
|
||||
if (sizeof(__U16_TYPEDEF) != 2) {
|
||||
printf("Sizeof(__U16__TYPEDEF) is %d should be 2\n",
|
||||
(int) sizeof(__U16_TYPEDEF));
|
||||
exit(1);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#warning __U16_TYPEDEF not defined
|
||||
#endif
|
||||
#ifdef __S16_TYPEDEF
|
||||
if (sizeof(__S16_TYPEDEF) != 2) {
|
||||
printf("Sizeof(__S16__TYPEDEF) is %d should be 2\n",
|
||||
(int) sizeof(__S16_TYPEDEF));
|
||||
exit(1);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#warning __S16_TYPEDEF not defined
|
||||
#endif
|
||||
|
||||
#ifdef __U32_TYPEDEF
|
||||
if (sizeof(__U32_TYPEDEF) != 4) {
|
||||
printf("Sizeof(__U32__TYPEDEF) is %d should be 4\n",
|
||||
(int) sizeof(__U32_TYPEDEF));
|
||||
exit(1);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#warning __U32_TYPEDEF not defined
|
||||
#endif
|
||||
#ifdef __S32_TYPEDEF
|
||||
if (sizeof(__S32_TYPEDEF) != 4) {
|
||||
printf("Sizeof(__S32__TYPEDEF) is %d should be 4\n",
|
||||
(int) sizeof(__S32_TYPEDEF));
|
||||
exit(1);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#warning __S32_TYPEDEF not defined
|
||||
#endif
|
||||
|
||||
#ifdef __U64_TYPEDEF
|
||||
if (sizeof(__U64_TYPEDEF) != 8) {
|
||||
printf("Sizeof(__U64__TYPEDEF) is %d should be 8\n",
|
||||
(int) sizeof(__U64_TYPEDEF));
|
||||
exit(1);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#warning __U64_TYPEDEF not defined
|
||||
#endif
|
||||
#ifdef __S64_TYPEDEF
|
||||
if (sizeof(__S64_TYPEDEF) != 8) {
|
||||
printf("Sizeof(__S64__TYPEDEF) is %d should be 8\n",
|
||||
(int) sizeof(__S64_TYPEDEF));
|
||||
exit(1);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#warning __S64_TYPEDEF not defined
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
${BUILD_CC-${CC-gcc}} -o asm_types asm_types.c
|
||||
if ./asm_types
|
||||
then
|
||||
true
|
||||
else
|
||||
if [ "${CROSS_COMPILE}" != "1" ]; then
|
||||
echo "Problem detected with asm_types.h"
|
||||
echo "" > asm_types.h
|
||||
fi
|
||||
fi
|
||||
rm asm_types.c asm_types
|
||||
|
||||
14161
2025-03-19/e2fsprogs-1.46.2/configure
vendored
Executable file
14161
2025-03-19/e2fsprogs-1.46.2/configure
vendored
Executable file
File diff suppressed because it is too large
Load diff
1819
2025-03-19/e2fsprogs-1.46.2/configure.ac
Normal file
1819
2025-03-19/e2fsprogs-1.46.2/configure.ac
Normal file
File diff suppressed because it is too large
Load diff
19
2025-03-19/e2fsprogs-1.46.2/contrib/Android.bp
Normal file
19
2025-03-19/e2fsprogs-1.46.2/contrib/Android.bp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2017 The Android Open Source Project
|
||||
|
||||
subdirs = ["android"]
|
||||
|
||||
//########################################################################
|
||||
// Build add_ext4_encrypt
|
||||
|
||||
cc_binary {
|
||||
name: "add_ext4_encrypt",
|
||||
host_supported: true,
|
||||
defaults: ["e2fsprogs-defaults"],
|
||||
|
||||
srcs: ["add_ext4_encrypt.c"],
|
||||
shared_libs: [
|
||||
"libext2fs",
|
||||
"libext2_com_err",
|
||||
],
|
||||
system_shared_libs: ["libc", "libdl"],
|
||||
}
|
||||
64
2025-03-19/e2fsprogs-1.46.2/contrib/add_ext4_encrypt.c
Normal file
64
2025-03-19/e2fsprogs-1.46.2/contrib/add_ext4_encrypt.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Basic program to add ext4 encryption to a file system
|
||||
*
|
||||
* Copyright 2015, Google, Inc.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ext2fs/ext2_fs.h>
|
||||
#include <ext2fs/ext2fs.h>
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
ext2_filsys fs;
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
setbuf(stderr, NULL);
|
||||
initialize_ext2_error_table();
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "%s: Usage <device|filesystem>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
retval = ext2fs_open(argv[1], EXT2_FLAG_RW, 0, 0,
|
||||
unix_io_manager, &fs);
|
||||
|
||||
if (retval) {
|
||||
com_err(argv[0], retval, "while trying to open '%s'",
|
||||
argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
if (!ext2fs_has_feature_encrypt(fs->super)) {
|
||||
ext2fs_set_feature_encrypt(fs->super);
|
||||
fs->super->s_encrypt_algos[0] =
|
||||
EXT4_ENCRYPTION_MODE_AES_256_XTS;
|
||||
fs->super->s_encrypt_algos[1] =
|
||||
EXT4_ENCRYPTION_MODE_AES_256_CTS;
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
printf("Ext4 encryption enabled on %s\n", argv[1]);
|
||||
} else
|
||||
printf("Ext4 encryption already enabled on %s\n", argv[1]);
|
||||
|
||||
retval = ext2fs_close(fs);
|
||||
if (retval) {
|
||||
com_err(argv[0], retval, "while trying to close '%s'",
|
||||
argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
69
2025-03-19/e2fsprogs-1.46.2/contrib/android/Android.bp
Normal file
69
2025-03-19/e2fsprogs-1.46.2/contrib/android/Android.bp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2017 The Android Open Source Project
|
||||
|
||||
//##########################################################################
|
||||
// Build e2fsdroid
|
||||
|
||||
cc_binary {
|
||||
name: "e2fsdroid",
|
||||
host_supported: true,
|
||||
recovery_available: true,
|
||||
defaults: ["e2fsprogs-defaults"],
|
||||
|
||||
srcs: [
|
||||
"e2fsdroid.c",
|
||||
"block_range.c",
|
||||
"fsmap.c",
|
||||
"block_list.c",
|
||||
"base_fs.c",
|
||||
"perms.c",
|
||||
"basefs_allocator.c",
|
||||
],
|
||||
target: {
|
||||
host: {
|
||||
static_libs: [
|
||||
"libext2_com_err",
|
||||
"libext2_misc",
|
||||
"libext2fs",
|
||||
"libsparse",
|
||||
"libz",
|
||||
"libcutils",
|
||||
"libbase",
|
||||
"libselinux",
|
||||
"libcrypto",
|
||||
"liblog",
|
||||
],
|
||||
sanitize: {
|
||||
address: false, // http://b/68387795 - heap overflow in e2fsdroid
|
||||
},
|
||||
},
|
||||
android: {
|
||||
shared_libs: [
|
||||
"libext2fs",
|
||||
"libext2_com_err",
|
||||
"libext2_misc",
|
||||
"libcutils",
|
||||
"libbase",
|
||||
"libselinux",
|
||||
"libcrypto",
|
||||
],
|
||||
},
|
||||
},
|
||||
stl: "libc++_static",
|
||||
}
|
||||
|
||||
//##########################################################################
|
||||
// Build ext2simg
|
||||
|
||||
cc_binary {
|
||||
name: "ext2simg",
|
||||
host_supported: true,
|
||||
defaults: ["e2fsprogs-defaults"],
|
||||
|
||||
srcs: ["ext2simg.c"],
|
||||
shared_libs: [
|
||||
"libext2fs",
|
||||
"libext2_com_err",
|
||||
"libsparse",
|
||||
"libz",
|
||||
],
|
||||
}
|
||||
205
2025-03-19/e2fsprogs-1.46.2/contrib/android/base_fs.c
Normal file
205
2025-03-19/e2fsprogs-1.46.2/contrib/android/base_fs.c
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
#include "base_fs.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define BASE_FS_VERSION "Base EXT4 version 1.0"
|
||||
|
||||
struct base_fs {
|
||||
FILE *file;
|
||||
const char *mountpoint;
|
||||
struct basefs_entry entry;
|
||||
};
|
||||
|
||||
static FILE *basefs_open(const char *file)
|
||||
{
|
||||
char *line = NULL;
|
||||
size_t len;
|
||||
FILE *f = fopen(file, "r");
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
if (getline(&line, &len, f) == -1 || !line)
|
||||
goto err_getline;
|
||||
|
||||
if (strncmp(line, BASE_FS_VERSION, strlen(BASE_FS_VERSION)))
|
||||
goto err_header;
|
||||
|
||||
free(line);
|
||||
return f;
|
||||
|
||||
err_header:
|
||||
free(line);
|
||||
err_getline:
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct basefs_entry *basefs_readline(FILE *f, const char *mountpoint,
|
||||
int *err)
|
||||
{
|
||||
char *line = NULL, *saveptr1, *saveptr2, *block_range, *block;
|
||||
int offset;
|
||||
size_t len;
|
||||
struct basefs_entry *entry = NULL;
|
||||
blk64_t range_start, range_end;
|
||||
|
||||
if (getline(&line, &len, f) == -1) {
|
||||
if (feof(f))
|
||||
goto end;
|
||||
goto err_getline;
|
||||
}
|
||||
|
||||
entry = calloc(1, sizeof(*entry));
|
||||
if (!entry)
|
||||
goto err_alloc;
|
||||
|
||||
/*
|
||||
* With BASEFS version 1.0, a typical line looks like this:
|
||||
* /bin/mke2fs 5000-5004,8000,9000-9990
|
||||
*/
|
||||
if (sscanf(line, "%ms%n", &entry->path, &offset) != 1)
|
||||
goto err_sscanf;
|
||||
len = strlen(mountpoint);
|
||||
memmove(entry->path, entry->path + len, strlen(entry->path) - len + 1);
|
||||
|
||||
while (line[offset] == ' ')
|
||||
++offset;
|
||||
|
||||
block_range = strtok_r(line + offset, ",\n", &saveptr1);
|
||||
while (block_range) {
|
||||
block = strtok_r(block_range, "-", &saveptr2);
|
||||
if (!block)
|
||||
break;
|
||||
range_start = atoll(block);
|
||||
block = strtok_r(NULL, "-", &saveptr2);
|
||||
range_end = block ? atoll(block) : range_start;
|
||||
add_blocks_to_range(&entry->blocks, range_start, range_end);
|
||||
block_range = strtok_r(NULL, ",\n", &saveptr1);
|
||||
}
|
||||
end:
|
||||
*err = 0;
|
||||
free(line);
|
||||
return entry;
|
||||
|
||||
err_sscanf:
|
||||
free(entry);
|
||||
err_alloc:
|
||||
free(line);
|
||||
err_getline:
|
||||
*err = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void free_base_fs_entry(void *e)
|
||||
{
|
||||
struct basefs_entry *entry = e;
|
||||
if (entry) {
|
||||
free(entry->path);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
struct ext2fs_hashmap *basefs_parse(const char *file, const char *mountpoint)
|
||||
{
|
||||
int err;
|
||||
struct ext2fs_hashmap *entries = NULL;
|
||||
struct basefs_entry *entry;
|
||||
FILE *f = basefs_open(file);
|
||||
if (!f)
|
||||
return NULL;
|
||||
entries = ext2fs_hashmap_create(ext2fs_djb2_hash, free_base_fs_entry, 1024);
|
||||
if (!entries)
|
||||
goto end;
|
||||
|
||||
while ((entry = basefs_readline(f, mountpoint, &err)))
|
||||
ext2fs_hashmap_add(entries, entry, entry->path,
|
||||
strlen(entry->path));
|
||||
|
||||
if (err) {
|
||||
fclose(f);
|
||||
ext2fs_hashmap_free(entries);
|
||||
return NULL;
|
||||
}
|
||||
end:
|
||||
fclose(f);
|
||||
return entries;
|
||||
}
|
||||
|
||||
static void *init(const char *file, const char *mountpoint)
|
||||
{
|
||||
struct base_fs *params = malloc(sizeof(*params));
|
||||
|
||||
if (!params)
|
||||
return NULL;
|
||||
params->mountpoint = mountpoint;
|
||||
params->file = fopen(file, "w+");
|
||||
if (!params->file) {
|
||||
free(params);
|
||||
return NULL;
|
||||
}
|
||||
if (fwrite(BASE_FS_VERSION"\n", 1, strlen(BASE_FS_VERSION"\n"),
|
||||
params->file) != strlen(BASE_FS_VERSION"\n")) {
|
||||
fclose(params->file);
|
||||
free(params);
|
||||
return NULL;
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
static int start_new_file(char *path, ext2_ino_t ino EXT2FS_ATTR((unused)),
|
||||
struct ext2_inode *inode, void *data)
|
||||
{
|
||||
struct base_fs *params = data;
|
||||
|
||||
params->entry.path = LINUX_S_ISREG(inode->i_mode) ? path : NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk64_t blocknr,
|
||||
int metadata, void *data)
|
||||
{
|
||||
struct base_fs *params = data;
|
||||
|
||||
if (params->entry.path && !metadata)
|
||||
add_blocks_to_range(¶ms->entry.blocks, blocknr, blocknr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int inline_data(void *inline_data EXT2FS_ATTR((unused)),
|
||||
void *data EXT2FS_ATTR((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int end_new_file(void *data)
|
||||
{
|
||||
struct base_fs *params = data;
|
||||
|
||||
if (!params->entry.path)
|
||||
return 0;
|
||||
if (fprintf(params->file, "%s%s ", params->mountpoint,
|
||||
params->entry.path) < 0
|
||||
|| write_block_ranges(params->file, params->entry.blocks.head, ",")
|
||||
|| fwrite("\n", 1, 1, params->file) != 1)
|
||||
return -1;
|
||||
|
||||
delete_block_ranges(¶ms->entry.blocks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cleanup(void *data)
|
||||
{
|
||||
struct base_fs *params = data;
|
||||
|
||||
fclose(params->file);
|
||||
free(params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fsmap_format base_fs_format = {
|
||||
.init = init,
|
||||
.start_new_file = start_new_file,
|
||||
.add_block = add_block,
|
||||
.inline_data = inline_data,
|
||||
.end_new_file = end_new_file,
|
||||
.cleanup = cleanup,
|
||||
};
|
||||
17
2025-03-19/e2fsprogs-1.46.2/contrib/android/base_fs.h
Normal file
17
2025-03-19/e2fsprogs-1.46.2/contrib/android/base_fs.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef BASE_FS_H
|
||||
# define BASE_FS_H
|
||||
|
||||
# include "fsmap.h"
|
||||
# include "hashmap.h"
|
||||
# include "block_range.h"
|
||||
|
||||
struct basefs_entry {
|
||||
char *path;
|
||||
struct block_range_list blocks;
|
||||
};
|
||||
|
||||
extern struct fsmap_format base_fs_format;
|
||||
|
||||
struct ext2fs_hashmap *basefs_parse(const char *file, const char *mountpoint);
|
||||
|
||||
#endif /* !BASE_FS_H */
|
||||
367
2025-03-19/e2fsprogs-1.46.2/contrib/android/basefs_allocator.c
Normal file
367
2025-03-19/e2fsprogs-1.46.2/contrib/android/basefs_allocator.c
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "basefs_allocator.h"
|
||||
#include "block_range.h"
|
||||
#include "hashmap.h"
|
||||
#include "base_fs.h"
|
||||
|
||||
struct base_fs_allocator {
|
||||
struct ext2fs_hashmap *entries;
|
||||
struct basefs_entry *cur_entry;
|
||||
/* The next expected logical block to allocate for cur_entry. */
|
||||
blk64_t next_lblk;
|
||||
/* Blocks which are definitely owned by a single inode in BaseFS. */
|
||||
ext2fs_block_bitmap exclusive_block_map;
|
||||
/* Blocks which are available to the first inode that requests it. */
|
||||
ext2fs_block_bitmap dedup_block_map;
|
||||
};
|
||||
|
||||
static errcode_t basefs_block_allocator(ext2_filsys, blk64_t, blk64_t *,
|
||||
struct blk_alloc_ctx *ctx);
|
||||
|
||||
/*
|
||||
* Free any reserved, but unconsumed block ranges in the allocator. This both
|
||||
* frees the block_range_list data structure and unreserves exclusive blocks
|
||||
* from the block map.
|
||||
*/
|
||||
static void fs_free_blocks_range(ext2_filsys fs,
|
||||
struct base_fs_allocator *allocator,
|
||||
struct block_range_list *list)
|
||||
{
|
||||
ext2fs_block_bitmap exclusive_map = allocator->exclusive_block_map;
|
||||
|
||||
blk64_t block;
|
||||
while (list->head) {
|
||||
block = consume_next_block(list);
|
||||
if (ext2fs_test_block_bitmap2(exclusive_map, block)) {
|
||||
ext2fs_unmark_block_bitmap2(fs->block_map, block);
|
||||
ext2fs_unmark_block_bitmap2(exclusive_map, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free any blocks in the bitmap that were reserved but never used. This is
|
||||
* needed to free dedup_block_map and ensure the free block bitmap is
|
||||
* internally consistent.
|
||||
*/
|
||||
static void fs_free_blocks_bitmap(ext2_filsys fs, ext2fs_block_bitmap bitmap)
|
||||
{
|
||||
blk64_t block = 0;
|
||||
blk64_t start = fs->super->s_first_data_block;
|
||||
blk64_t end = ext2fs_blocks_count(fs->super) - 1;
|
||||
errcode_t retval;
|
||||
|
||||
for (;;) {
|
||||
retval = ext2fs_find_first_set_block_bitmap2(bitmap, start, end,
|
||||
&block);
|
||||
if (retval)
|
||||
break;
|
||||
ext2fs_unmark_block_bitmap2(fs->block_map, block);
|
||||
start = block + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void basefs_allocator_free(ext2_filsys fs,
|
||||
struct base_fs_allocator *allocator)
|
||||
{
|
||||
struct basefs_entry *e;
|
||||
struct ext2fs_hashmap_entry *it = NULL;
|
||||
struct ext2fs_hashmap *entries = allocator->entries;
|
||||
|
||||
if (entries) {
|
||||
while ((e = ext2fs_hashmap_iter_in_order(entries, &it))) {
|
||||
fs_free_blocks_range(fs, allocator, &e->blocks);
|
||||
delete_block_ranges(&e->blocks);
|
||||
}
|
||||
ext2fs_hashmap_free(entries);
|
||||
}
|
||||
fs_free_blocks_bitmap(fs, allocator->dedup_block_map);
|
||||
ext2fs_free_block_bitmap(allocator->exclusive_block_map);
|
||||
ext2fs_free_block_bitmap(allocator->dedup_block_map);
|
||||
free(allocator);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a bitmap of which blocks are definitely owned by exactly one file in
|
||||
* Base FS. Blocks which are not valid or are de-duplicated are skipped. This
|
||||
* is called during allocator initialization, to ensure that libext2fs does
|
||||
* not allocate which we want to re-use.
|
||||
*
|
||||
* If a block was allocated in the initial filesystem, it can never be re-used,
|
||||
* so it will appear in neither the exclusive or dedup set. If a block is used
|
||||
* by multiple files, it will be removed from the owned set and instead added
|
||||
* to the dedup set.
|
||||
*
|
||||
* The dedup set is not removed from fs->block_map. This allows us to re-use
|
||||
* dedup blocks separately and not have them be allocated outside of file data.
|
||||
*/
|
||||
static void fs_reserve_block(ext2_filsys fs,
|
||||
struct base_fs_allocator *allocator,
|
||||
blk64_t block)
|
||||
{
|
||||
ext2fs_block_bitmap exclusive_map = allocator->exclusive_block_map;
|
||||
ext2fs_block_bitmap dedup_map = allocator->dedup_block_map;
|
||||
|
||||
if (block >= ext2fs_blocks_count(fs->super))
|
||||
return;
|
||||
|
||||
if (ext2fs_test_block_bitmap2(fs->block_map, block)) {
|
||||
if (!ext2fs_test_block_bitmap2(exclusive_map, block))
|
||||
return;
|
||||
ext2fs_unmark_block_bitmap2(exclusive_map, block);
|
||||
ext2fs_mark_block_bitmap2(dedup_map, block);
|
||||
} else {
|
||||
ext2fs_mark_block_bitmap2(fs->block_map, block);
|
||||
ext2fs_mark_block_bitmap2(exclusive_map, block);
|
||||
}
|
||||
}
|
||||
|
||||
static void fs_reserve_blocks_range(ext2_filsys fs,
|
||||
struct base_fs_allocator *allocator,
|
||||
struct block_range_list *list)
|
||||
{
|
||||
blk64_t block;
|
||||
struct block_range *blocks = list->head;
|
||||
|
||||
while (blocks) {
|
||||
for (block = blocks->start; block <= blocks->end; block++)
|
||||
fs_reserve_block(fs, allocator, block);
|
||||
blocks = blocks->next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For each file in the base FS map, ensure that its blocks are reserved in
|
||||
* the actual block map. This prevents libext2fs from allocating them for
|
||||
* general purpose use, and ensures that if the file needs data blocks, they
|
||||
* can be re-acquired exclusively for that file.
|
||||
*
|
||||
* If a file in the base map is missing, or not a regular file in the new
|
||||
* filesystem, then it's skipped to ensure that its blocks are reusable.
|
||||
*/
|
||||
static errcode_t fs_reserve_blocks(ext2_filsys fs,
|
||||
struct base_fs_allocator *allocator,
|
||||
const char *src_dir)
|
||||
{
|
||||
int nbytes;
|
||||
char full_path[PATH_MAX];
|
||||
const char *sep = "/";
|
||||
struct stat st;
|
||||
struct basefs_entry *e;
|
||||
struct ext2fs_hashmap_entry *it = NULL;
|
||||
struct ext2fs_hashmap *entries = allocator->entries;
|
||||
|
||||
if (strlen(src_dir) && src_dir[strlen(src_dir) - 1] == '/')
|
||||
sep = "";
|
||||
|
||||
while ((e = ext2fs_hashmap_iter_in_order(entries, &it))) {
|
||||
nbytes = snprintf(full_path, sizeof(full_path), "%s%s%s",
|
||||
src_dir, sep, e->path);
|
||||
if (nbytes >= sizeof(full_path))
|
||||
return ENAMETOOLONG;
|
||||
if (lstat(full_path, &st) || !S_ISREG(st.st_mode))
|
||||
continue;
|
||||
fs_reserve_blocks_range(fs, allocator, &e->blocks);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t base_fs_alloc_load(ext2_filsys fs, const char *file,
|
||||
const char *mountpoint, const char *src_dir)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
struct base_fs_allocator *allocator;
|
||||
|
||||
allocator = calloc(1, sizeof(*allocator));
|
||||
if (!allocator) {
|
||||
retval = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
retval = ext2fs_read_bitmaps(fs);
|
||||
if (retval)
|
||||
goto err_load;
|
||||
|
||||
allocator->cur_entry = NULL;
|
||||
allocator->entries = basefs_parse(file, mountpoint);
|
||||
if (!allocator->entries) {
|
||||
retval = EIO;
|
||||
goto err_load;
|
||||
}
|
||||
retval = ext2fs_allocate_block_bitmap(fs, "exclusive map",
|
||||
&allocator->exclusive_block_map);
|
||||
if (retval)
|
||||
goto err_load;
|
||||
retval = ext2fs_allocate_block_bitmap(fs, "dedup map",
|
||||
&allocator->dedup_block_map);
|
||||
if (retval)
|
||||
goto err_load;
|
||||
|
||||
retval = fs_reserve_blocks(fs, allocator, src_dir);
|
||||
if (retval)
|
||||
goto err_load;
|
||||
|
||||
/* Override the default allocator */
|
||||
fs->get_alloc_block2 = basefs_block_allocator;
|
||||
fs->priv_data = allocator;
|
||||
|
||||
goto out;
|
||||
|
||||
err_load:
|
||||
basefs_allocator_free(fs, allocator);
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Try and acquire the next usable block from the Base FS map. */
|
||||
static errcode_t get_next_block(ext2_filsys fs, struct base_fs_allocator *allocator,
|
||||
struct block_range_list* list, blk64_t *ret)
|
||||
{
|
||||
blk64_t block;
|
||||
ext2fs_block_bitmap exclusive_map = allocator->exclusive_block_map;
|
||||
ext2fs_block_bitmap dedup_map = allocator->dedup_block_map;
|
||||
|
||||
if (!list->head)
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
|
||||
block = consume_next_block(list);
|
||||
if (block >= ext2fs_blocks_count(fs->super))
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
if (ext2fs_test_block_bitmap2(exclusive_map, block)) {
|
||||
ext2fs_unmark_block_bitmap2(exclusive_map, block);
|
||||
*ret = block;
|
||||
return 0;
|
||||
}
|
||||
if (ext2fs_test_block_bitmap2(dedup_map, block)) {
|
||||
ext2fs_unmark_block_bitmap2(dedup_map, block);
|
||||
*ret = block;
|
||||
return 0;
|
||||
}
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* BaseFS lists blocks in logical block order. However, the allocator hook is
|
||||
* only called if a block needs to be allocated. In the case of a deduplicated
|
||||
* block, or a hole, the hook is not invoked. This means the next block
|
||||
* allocation request will be out of sequence. For example, consider if BaseFS
|
||||
* specifies the following (0 being a hole):
|
||||
* 1 2 3 0 4 5
|
||||
*
|
||||
* If the new file has a hole at logical block 0, we could accidentally
|
||||
* shift the entire expected block list as follows:
|
||||
* 0 1 2 0 3 4
|
||||
*
|
||||
* To account for this, we track the next expected logical block in the
|
||||
* allocator. If the current request is for a later logical block, we skip and
|
||||
* free the intermediate physical blocks that would have been allocated. This
|
||||
* ensures the original block assignment is respected.
|
||||
*/
|
||||
static void skip_blocks(ext2_filsys fs, struct base_fs_allocator *allocator,
|
||||
struct blk_alloc_ctx *ctx)
|
||||
{
|
||||
blk64_t block;
|
||||
struct block_range_list *list = &allocator->cur_entry->blocks;
|
||||
ext2fs_block_bitmap exclusive_map = allocator->exclusive_block_map;
|
||||
|
||||
while (list->head && allocator->next_lblk < ctx->lblk) {
|
||||
block = consume_next_block(list);
|
||||
if (block >= ext2fs_blocks_count(fs->super))
|
||||
continue;
|
||||
if (ext2fs_test_block_bitmap2(exclusive_map, block)) {
|
||||
ext2fs_unmark_block_bitmap2(exclusive_map, block);
|
||||
ext2fs_unmark_block_bitmap2(fs->block_map, block);
|
||||
}
|
||||
allocator->next_lblk++;
|
||||
}
|
||||
}
|
||||
|
||||
static errcode_t basefs_block_allocator(ext2_filsys fs, blk64_t goal,
|
||||
blk64_t *ret, struct blk_alloc_ctx *ctx)
|
||||
{
|
||||
errcode_t retval;
|
||||
struct base_fs_allocator *allocator = fs->priv_data;
|
||||
struct basefs_entry *e = allocator->cur_entry;
|
||||
ext2fs_block_bitmap dedup_map = allocator->dedup_block_map;
|
||||
|
||||
if (e && ctx && (ctx->flags & BLOCK_ALLOC_DATA)) {
|
||||
if (allocator->next_lblk < ctx->lblk)
|
||||
skip_blocks(fs, allocator, ctx);
|
||||
allocator->next_lblk = ctx->lblk + 1;
|
||||
|
||||
if (!get_next_block(fs, allocator, &e->blocks, ret))
|
||||
return 0;
|
||||
}
|
||||
|
||||
retval = ext2fs_new_block2(fs, goal, fs->block_map, ret);
|
||||
if (!retval) {
|
||||
ext2fs_mark_block_bitmap2(fs->block_map, *ret);
|
||||
return 0;
|
||||
}
|
||||
if (retval != EXT2_ET_BLOCK_ALLOC_FAIL)
|
||||
return retval;
|
||||
|
||||
/* Try to steal a block from the dedup pool. */
|
||||
retval = ext2fs_find_first_set_block_bitmap2(dedup_map,
|
||||
fs->super->s_first_data_block,
|
||||
ext2fs_blocks_count(fs->super) - 1, ret);
|
||||
if (!retval) {
|
||||
ext2fs_unmark_block_bitmap2(dedup_map, *ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* As a last resort, take any block from our file's list. This
|
||||
* risks bloating the diff, but means we are more likely to
|
||||
* successfully build an image.
|
||||
*/
|
||||
while (e->blocks.head) {
|
||||
if (!get_next_block(fs, allocator, &e->blocks, ret))
|
||||
return 0;
|
||||
}
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
}
|
||||
|
||||
void base_fs_alloc_cleanup(ext2_filsys fs)
|
||||
{
|
||||
basefs_allocator_free(fs, fs->priv_data);
|
||||
fs->priv_data = NULL;
|
||||
fs->get_alloc_block2 = NULL;
|
||||
}
|
||||
|
||||
errcode_t base_fs_alloc_set_target(ext2_filsys fs, const char *target_path,
|
||||
const char *name EXT2FS_ATTR((unused)),
|
||||
ext2_ino_t parent_ino EXT2FS_ATTR((unused)),
|
||||
ext2_ino_t root EXT2FS_ATTR((unused)), mode_t mode)
|
||||
{
|
||||
struct base_fs_allocator *allocator = fs->priv_data;
|
||||
|
||||
if (mode != S_IFREG)
|
||||
return 0;
|
||||
|
||||
if (allocator) {
|
||||
allocator->cur_entry = ext2fs_hashmap_lookup(allocator->entries,
|
||||
target_path,
|
||||
strlen(target_path));
|
||||
allocator->next_lblk = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t base_fs_alloc_unset_target(ext2_filsys fs,
|
||||
const char *target_path EXT2FS_ATTR((unused)),
|
||||
const char *name EXT2FS_ATTR((unused)),
|
||||
ext2_ino_t parent_ino EXT2FS_ATTR((unused)),
|
||||
ext2_ino_t root EXT2FS_ATTR((unused)), mode_t mode)
|
||||
{
|
||||
struct base_fs_allocator *allocator = fs->priv_data;
|
||||
|
||||
if (!allocator || !allocator->cur_entry || mode != S_IFREG)
|
||||
return 0;
|
||||
|
||||
fs_free_blocks_range(fs, allocator, &allocator->cur_entry->blocks);
|
||||
delete_block_ranges(&allocator->cur_entry->blocks);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef BASE_FS_ALLOCATOR_H
|
||||
# define BASE_FS_ALLOCATOR_H
|
||||
|
||||
# include <time.h>
|
||||
# include <ext2fs/ext2fs.h>
|
||||
|
||||
errcode_t base_fs_alloc_load(ext2_filsys fs, const char *file,
|
||||
const char *mountpoint, const char *src_dir);
|
||||
void base_fs_alloc_cleanup(ext2_filsys fs);
|
||||
|
||||
errcode_t base_fs_alloc_set_target(ext2_filsys fs, const char *target_path,
|
||||
const char *name, ext2_ino_t parent_ino, ext2_ino_t root, mode_t mode);
|
||||
errcode_t base_fs_alloc_unset_target(ext2_filsys fs, const char *target_path,
|
||||
const char *name, ext2_ino_t parent_ino, ext2_ino_t root, mode_t mode);
|
||||
|
||||
#endif /* !BASE_FS_ALLOCATOR_H */
|
||||
89
2025-03-19/e2fsprogs-1.46.2/contrib/android/block_list.c
Normal file
89
2025-03-19/e2fsprogs-1.46.2/contrib/android/block_list.c
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#include "block_list.h"
|
||||
#include "block_range.h"
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
struct block_list {
|
||||
FILE *f;
|
||||
const char *mountpoint;
|
||||
|
||||
const char *filename;
|
||||
struct block_range_list blocks;
|
||||
};
|
||||
|
||||
static void *init(const char *file, const char *mountpoint)
|
||||
{
|
||||
struct block_list *params = calloc(1, sizeof(*params));
|
||||
|
||||
if (!params)
|
||||
return NULL;
|
||||
params->mountpoint = mountpoint;
|
||||
params->f = fopen(file, "w+");
|
||||
if (!params->f) {
|
||||
free(params);
|
||||
return NULL;
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
static int start_new_file(char *path, ext2_ino_t ino EXT2FS_ATTR((unused)),
|
||||
struct ext2_inode *inode EXT2FS_ATTR((unused)),
|
||||
void *data)
|
||||
{
|
||||
struct block_list *params = data;
|
||||
|
||||
params->filename = LINUX_S_ISREG(inode->i_mode) ? path : NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk64_t blocknr,
|
||||
int metadata, void *data)
|
||||
{
|
||||
struct block_list *params = data;
|
||||
|
||||
if (params->filename && !metadata)
|
||||
add_blocks_to_range(¶ms->blocks, blocknr, blocknr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int inline_data(void *inline_data EXT2FS_ATTR((unused)),
|
||||
void *data EXT2FS_ATTR((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int end_new_file(void *data)
|
||||
{
|
||||
struct block_list *params = data;
|
||||
|
||||
if (!params->filename || !params->blocks.head)
|
||||
return 0;
|
||||
if (fprintf(params->f, "%s%s ", params->mountpoint,
|
||||
params->filename) < 0
|
||||
|| write_block_ranges(params->f, params->blocks.head, " ")
|
||||
|| fwrite("\n", 1, 1, params->f) != 1)
|
||||
return -1;
|
||||
|
||||
delete_block_ranges(¶ms->blocks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cleanup(void *data)
|
||||
{
|
||||
struct block_list *params = data;
|
||||
|
||||
fclose(params->f);
|
||||
free(params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fsmap_format block_list_format = {
|
||||
.init = init,
|
||||
.start_new_file = start_new_file,
|
||||
.add_block = add_block,
|
||||
.inline_data = inline_data,
|
||||
.end_new_file = end_new_file,
|
||||
.cleanup = cleanup,
|
||||
};
|
||||
8
2025-03-19/e2fsprogs-1.46.2/contrib/android/block_list.h
Normal file
8
2025-03-19/e2fsprogs-1.46.2/contrib/android/block_list.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef BLOCK_LIST_H
|
||||
# define BLOCK_LIST_H
|
||||
|
||||
# include "fsmap.h"
|
||||
|
||||
extern struct fsmap_format block_list_format;
|
||||
|
||||
#endif /* !BLOCK_LIST_H */
|
||||
80
2025-03-19/e2fsprogs-1.46.2/contrib/android/block_range.c
Normal file
80
2025-03-19/e2fsprogs-1.46.2/contrib/android/block_range.c
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#define _GNU_SOURCE
|
||||
|
||||
#include "block_range.h"
|
||||
#include <stdio.h>
|
||||
|
||||
struct block_range *new_block_range(blk64_t start, blk64_t end)
|
||||
{
|
||||
struct block_range *range = malloc(sizeof(*range));
|
||||
range->start = start;
|
||||
range->end = end;
|
||||
range->next = NULL;
|
||||
return range;
|
||||
}
|
||||
|
||||
void add_blocks_to_range(struct block_range_list *list, blk64_t blk_start,
|
||||
blk64_t blk_end)
|
||||
{
|
||||
if (list->head == NULL)
|
||||
list->head = list->tail = new_block_range(blk_start, blk_end);
|
||||
else if (list->tail->end + 1 == blk_start)
|
||||
list->tail->end += (blk_end - blk_start + 1);
|
||||
else {
|
||||
struct block_range *range = new_block_range(blk_start, blk_end);
|
||||
list->tail->next = range;
|
||||
list->tail = range;
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_head(struct block_range_list *list)
|
||||
{
|
||||
struct block_range *next_range = list->head->next;
|
||||
|
||||
free(list->head);
|
||||
if (next_range == NULL)
|
||||
list->head = list->tail = NULL;
|
||||
else
|
||||
list->head = next_range;
|
||||
}
|
||||
|
||||
void delete_block_ranges(struct block_range_list *list)
|
||||
{
|
||||
while (list->head)
|
||||
remove_head(list);
|
||||
}
|
||||
|
||||
int write_block_ranges(FILE *f, struct block_range *range,
|
||||
char *sep)
|
||||
{
|
||||
int len;
|
||||
char *buf;
|
||||
|
||||
while (range) {
|
||||
if (range->start == range->end)
|
||||
len = asprintf(&buf, "%llu%s", range->start, sep);
|
||||
else
|
||||
len = asprintf(&buf, "%llu-%llu%s", range->start,
|
||||
range->end, sep);
|
||||
if (fwrite(buf, 1, len, f) != (size_t)len) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
free(buf);
|
||||
range = range->next;
|
||||
}
|
||||
|
||||
len = strlen(sep);
|
||||
if (fseek(f, -len, SEEK_CUR) == -len)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
blk64_t consume_next_block(struct block_range_list *list)
|
||||
{
|
||||
blk64_t ret = list->head->start;
|
||||
|
||||
list->head->start += 1;
|
||||
if (list->head->start > list->head->end)
|
||||
remove_head(list);
|
||||
return ret;
|
||||
}
|
||||
29
2025-03-19/e2fsprogs-1.46.2/contrib/android/block_range.h
Normal file
29
2025-03-19/e2fsprogs-1.46.2/contrib/android/block_range.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef BLOCK_RANGE_H
|
||||
# define BLOCK_RANGE_H
|
||||
|
||||
# include <sys/types.h>
|
||||
# include <ext2fs/ext2fs.h>
|
||||
|
||||
struct block_range {
|
||||
blk64_t start;
|
||||
blk64_t end;
|
||||
struct block_range *next;
|
||||
};
|
||||
|
||||
struct block_range_list {
|
||||
struct block_range *head;
|
||||
struct block_range *tail;
|
||||
};
|
||||
|
||||
void add_blocks_to_range(struct block_range_list *list, blk64_t blk_start,
|
||||
blk64_t blk_end);
|
||||
void delete_block_ranges(struct block_range_list *list);
|
||||
int write_block_ranges(FILE *f, struct block_range *range, char *sep);
|
||||
|
||||
/*
|
||||
* Given a non-empty range list, return the next block and remove it from the
|
||||
* list.
|
||||
*/
|
||||
blk64_t consume_next_block(struct block_range_list *list);
|
||||
|
||||
#endif /* !BLOCK_RANGE_H */
|
||||
377
2025-03-19/e2fsprogs-1.46.2/contrib/android/e2fsdroid.c
Normal file
377
2025-03-19/e2fsprogs-1.46.2/contrib/android/e2fsdroid.c
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <ext2fs/ext2fs.h>
|
||||
|
||||
#include "perms.h"
|
||||
#include "base_fs.h"
|
||||
#include "block_list.h"
|
||||
#include "basefs_allocator.h"
|
||||
#include "create_inode.h"
|
||||
|
||||
#ifndef UID_GID_MAP_MAX_EXTENTS
|
||||
/*
|
||||
* The value is defined in linux/user_namspace.h.
|
||||
* The value is (arbitrarily) 5 in 4.14 and earlier, or 340 in 4.15 and later.
|
||||
* Here, the bigger value is taken. See also man user_namespace(7).
|
||||
*/
|
||||
#define UID_GID_MAP_MAX_EXTENTS 340
|
||||
#endif
|
||||
|
||||
static char *prog_name = "e2fsdroid";
|
||||
static char *in_file;
|
||||
static char *block_list;
|
||||
static char *basefs_out;
|
||||
static char *basefs_in;
|
||||
static char *mountpoint = "";
|
||||
static time_t fixed_time = -1;
|
||||
static char *fs_config_file;
|
||||
static struct selinux_opt seopt_file[8];
|
||||
static int max_nr_opt = (int)sizeof(seopt_file) / sizeof(seopt_file[0]);
|
||||
static char *product_out;
|
||||
static char *src_dir;
|
||||
static int android_configure;
|
||||
static int android_sparse_file = 1;
|
||||
|
||||
static void usage(int ret)
|
||||
{
|
||||
fprintf(stderr, "%s [-B block_list] [-D basefs_out] [-T timestamp]\n"
|
||||
"\t[-C fs_config] [-S file_contexts] [-p product_out]\n"
|
||||
"\t[-a mountpoint] [-d basefs_in] [-f src_dir] [-e] [-s]\n"
|
||||
"\t[-u uid-mapping] [-g gid-mapping] image\n",
|
||||
prog_name);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
static char *absolute_path(const char *file)
|
||||
{
|
||||
char *ret;
|
||||
char cwd[PATH_MAX];
|
||||
|
||||
if (file[0] != '/') {
|
||||
if (getcwd(cwd, PATH_MAX) == NULL) {
|
||||
fprintf(stderr, "Failed to getcwd\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
ret = malloc(strlen(cwd) + 1 + strlen(file) + 1);
|
||||
if (ret)
|
||||
sprintf(ret, "%s/%s", cwd, file);
|
||||
} else
|
||||
ret = strdup(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parse_ugid_map_entry(char* line, struct ugid_map_entry* result)
|
||||
{
|
||||
char *token, *token_saveptr;
|
||||
size_t num_tokens;
|
||||
unsigned int *parsed[] = {&result->child_id,
|
||||
&result->parent_id,
|
||||
&result->length};
|
||||
for (token = strtok_r(line, " ", &token_saveptr), num_tokens = 0;
|
||||
token && num_tokens < 3;
|
||||
token = strtok_r(NULL, " ", &token_saveptr), ++num_tokens) {
|
||||
char* endptr = NULL;
|
||||
unsigned long t = strtoul(token, &endptr, 10);
|
||||
if ((t == ULONG_MAX && errno) || (t > UINT_MAX) || *endptr) {
|
||||
fprintf(stderr, "Malformed u/gid mapping line\n");
|
||||
return 0;
|
||||
}
|
||||
*parsed[num_tokens] = (unsigned int) t;
|
||||
}
|
||||
if (num_tokens < 3 || strtok_r(NULL, " ", &token_saveptr) != NULL) {
|
||||
fprintf(stderr, "Malformed u/gid mapping line\n");
|
||||
return 0;
|
||||
}
|
||||
if (result->child_id + result->length < result->child_id ||
|
||||
result->parent_id + result->length < result->parent_id) {
|
||||
fprintf(stderr, "u/gid mapping overflow\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if [begin1, begin1+length1) and [begin2, begin2+length2) have
|
||||
* overlapping range. Otherwise 0.
|
||||
*/
|
||||
static int is_overlapping(unsigned int begin1, unsigned int length1,
|
||||
unsigned int begin2, unsigned int length2)
|
||||
{
|
||||
unsigned int end1 = begin1 + length1;
|
||||
unsigned int end2 = begin2 + length2;
|
||||
return !(end1 <= begin2 || end2 <= begin1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies if the given mapping works.
|
||||
* - Checks if the number of entries is less than or equals to
|
||||
* UID_GID_MAP_MAX_EXTENTS.
|
||||
* - Checks if there is no overlapped ranges.
|
||||
* Returns 1 if valid, otherwise 0.
|
||||
*/
|
||||
static int is_valid_ugid_map(const struct ugid_map* mapping)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
if (mapping->size > UID_GID_MAP_MAX_EXTENTS) {
|
||||
fprintf(stderr, "too many u/gid mapping entries\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < mapping->size; ++i) {
|
||||
const struct ugid_map_entry *entry1 = &mapping->entries[i];
|
||||
for (j = i + 1; j < mapping->size; ++j) {
|
||||
const struct ugid_map_entry *entry2 =
|
||||
&mapping->entries[j];
|
||||
if (is_overlapping(entry1->child_id, entry1->length,
|
||||
entry2->child_id, entry2->length)) {
|
||||
fprintf(stderr,
|
||||
"Overlapping child u/gid: [%d %d %d],"
|
||||
" [%d %d %d]\n",
|
||||
entry1->child_id, entry1->parent_id,
|
||||
entry1->length, entry2->child_id,
|
||||
entry2->parent_id, entry2->length);
|
||||
return 0;
|
||||
}
|
||||
if (is_overlapping(entry1->parent_id, entry1->length,
|
||||
entry2->parent_id, entry2->length)) {
|
||||
fprintf(stderr,
|
||||
"Overlapping parent u/gid: [%d %d %d],"
|
||||
" [%d %d %d]\n",
|
||||
entry1->child_id, entry1->parent_id,
|
||||
entry1->length, entry2->child_id,
|
||||
entry2->parent_id, entry2->length);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the UID/GID mapping argument. The argument could be a multi-line
|
||||
* string (separated by '\n', no trailing '\n' is allowed). Each line must
|
||||
* contain exact three integer tokens; the first token is |child_id|,
|
||||
* the second is |parent_id|, and the last is |length| of the mapping range.
|
||||
* See also user_namespace(7) man page.
|
||||
* On success, the parsed entries are stored in |result|, and it returns 1.
|
||||
* Otherwise, returns 0.
|
||||
*/
|
||||
static int parse_ugid_map(char* arg, struct ugid_map* result)
|
||||
{
|
||||
int i;
|
||||
char *line, *line_saveptr;
|
||||
size_t current_index;
|
||||
|
||||
/* Count the number of lines. */
|
||||
result->size = 1;
|
||||
for (i = 0; arg[i]; ++i) {
|
||||
if (arg[i] == '\n')
|
||||
++result->size;
|
||||
}
|
||||
|
||||
/* Allocate memory for entries. */
|
||||
result->entries = malloc(sizeof(struct ugid_map_entry) * result->size);
|
||||
if (!result->entries) {
|
||||
result->size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse each line */
|
||||
for (line = strtok_r(arg, "\n", &line_saveptr), current_index = 0;
|
||||
line;
|
||||
line = strtok_r(NULL, "\n", &line_saveptr), ++current_index) {
|
||||
if (!parse_ugid_map_entry(
|
||||
line, &result->entries[current_index])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return is_valid_ugid_map(result);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
char *p;
|
||||
int flags = EXT2_FLAG_RW;
|
||||
errcode_t retval;
|
||||
io_manager io_mgr;
|
||||
ext2_filsys fs = NULL;
|
||||
struct fs_ops_callbacks fs_callbacks = { NULL, NULL };
|
||||
char *token;
|
||||
int nr_opt = 0;
|
||||
ext2_ino_t inodes_count;
|
||||
ext2_ino_t free_inodes_count;
|
||||
blk64_t blocks_count;
|
||||
blk64_t free_blocks_count;
|
||||
struct ugid_map uid_map = { 0, NULL }, gid_map = { 0, NULL };
|
||||
|
||||
add_error_table(&et_ext2_error_table);
|
||||
|
||||
while ((c = getopt (argc, argv, "T:C:S:p:a:D:d:B:f:esu:g:")) != EOF) {
|
||||
switch (c) {
|
||||
case 'T':
|
||||
fixed_time = strtoul(optarg, &p, 0);
|
||||
android_configure = 1;
|
||||
break;
|
||||
case 'C':
|
||||
fs_config_file = absolute_path(optarg);
|
||||
android_configure = 1;
|
||||
break;
|
||||
case 'S':
|
||||
token = strtok(optarg, ",");
|
||||
while (token) {
|
||||
if (nr_opt == max_nr_opt) {
|
||||
fprintf(stderr, "Expected at most %d selinux opts\n",
|
||||
max_nr_opt);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
seopt_file[nr_opt].type = SELABEL_OPT_PATH;
|
||||
seopt_file[nr_opt].value = absolute_path(token);
|
||||
nr_opt++;
|
||||
token = strtok(NULL, ",");
|
||||
}
|
||||
android_configure = 1;
|
||||
break;
|
||||
case 'p':
|
||||
product_out = absolute_path(optarg);
|
||||
android_configure = 1;
|
||||
break;
|
||||
case 'a':
|
||||
mountpoint = strdup(optarg);
|
||||
break;
|
||||
case 'D':
|
||||
basefs_out = absolute_path(optarg);
|
||||
break;
|
||||
case 'd':
|
||||
basefs_in = absolute_path(optarg);
|
||||
break;
|
||||
case 'B':
|
||||
block_list = absolute_path(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
src_dir = absolute_path(optarg);
|
||||
break;
|
||||
case 'e':
|
||||
android_sparse_file = 0;
|
||||
break;
|
||||
case 's':
|
||||
flags |= EXT2_FLAG_SHARE_DUP;
|
||||
break;
|
||||
case 'u':
|
||||
if (!parse_ugid_map(optarg, &uid_map))
|
||||
exit(EXIT_FAILURE);
|
||||
android_configure = 1;
|
||||
break;
|
||||
case 'g':
|
||||
if (!parse_ugid_map(optarg, &gid_map))
|
||||
exit(EXIT_FAILURE);
|
||||
android_configure = 1;
|
||||
break;
|
||||
default:
|
||||
usage(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "Expected filename after options\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (android_sparse_file) {
|
||||
io_mgr = sparse_io_manager;
|
||||
if (asprintf(&in_file, "(%s)", argv[optind]) == -1) {
|
||||
fprintf(stderr, "Failed to allocate file name\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
io_mgr = unix_io_manager;
|
||||
in_file = strdup(argv[optind]);
|
||||
}
|
||||
retval = ext2fs_open(in_file, flags, 0, 0, io_mgr, &fs);
|
||||
if (retval) {
|
||||
com_err(prog_name, retval, "while opening file %s\n", in_file);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (src_dir) {
|
||||
ext2fs_read_bitmaps(fs);
|
||||
if (basefs_in) {
|
||||
retval = base_fs_alloc_load(fs, basefs_in, mountpoint,
|
||||
src_dir);
|
||||
if (retval) {
|
||||
com_err(prog_name, retval, "%s",
|
||||
"while reading base_fs file");
|
||||
exit(1);
|
||||
}
|
||||
fs_callbacks.create_new_inode =
|
||||
base_fs_alloc_set_target;
|
||||
fs_callbacks.end_create_new_inode =
|
||||
base_fs_alloc_unset_target;
|
||||
}
|
||||
retval = populate_fs2(fs, EXT2_ROOT_INO, src_dir,
|
||||
EXT2_ROOT_INO, &fs_callbacks);
|
||||
if (retval) {
|
||||
com_err(prog_name, retval, "%s",
|
||||
"while populating file system");
|
||||
exit(1);
|
||||
}
|
||||
if (basefs_in)
|
||||
base_fs_alloc_cleanup(fs);
|
||||
}
|
||||
|
||||
if (android_configure) {
|
||||
retval = android_configure_fs(
|
||||
fs, src_dir, product_out, mountpoint, seopt_file,
|
||||
nr_opt, fs_config_file, fixed_time, &uid_map, &gid_map);
|
||||
if (retval) {
|
||||
com_err(prog_name, retval, "%s",
|
||||
"while configuring the file system");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (block_list) {
|
||||
retval = fsmap_iter_filsys(fs, &block_list_format, block_list,
|
||||
mountpoint);
|
||||
if (retval) {
|
||||
com_err(prog_name, retval, "%s",
|
||||
"while creating the block_list");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (basefs_out) {
|
||||
retval = fsmap_iter_filsys(fs, &base_fs_format,
|
||||
basefs_out, mountpoint);
|
||||
if (retval) {
|
||||
com_err(prog_name, retval, "%s",
|
||||
"while creating the basefs file");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
inodes_count = fs->super->s_inodes_count;
|
||||
free_inodes_count = fs->super->s_free_inodes_count;
|
||||
blocks_count = ext2fs_blocks_count(fs->super);
|
||||
free_blocks_count = ext2fs_free_blocks_count(fs->super);
|
||||
|
||||
retval = ext2fs_close_free(&fs);
|
||||
if (retval) {
|
||||
com_err(prog_name, retval, "%s",
|
||||
"while writing superblocks");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Created filesystem with %u/%u inodes and %llu/%llu blocks\n",
|
||||
inodes_count - free_inodes_count, inodes_count,
|
||||
blocks_count - free_blocks_count, blocks_count);
|
||||
|
||||
remove_error_table(&et_ext2_error_table);
|
||||
return 0;
|
||||
}
|
||||
224
2025-03-19/e2fsprogs-1.46.2/contrib/android/ext2simg.c
Normal file
224
2025-03-19/e2fsprogs-1.46.2/contrib/android/ext2simg.c
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <ext2fs/ext2fs.h>
|
||||
#include <et/com_err.h>
|
||||
#include <sparse/sparse.h>
|
||||
|
||||
struct {
|
||||
int crc;
|
||||
int sparse;
|
||||
int gzip;
|
||||
char *in_file;
|
||||
char *out_file;
|
||||
bool overwrite_input;
|
||||
} params = {
|
||||
.crc = 0,
|
||||
.sparse = 1,
|
||||
.gzip = 0,
|
||||
};
|
||||
|
||||
#define ext2fs_fatal(Retval, Format, ...) \
|
||||
do { \
|
||||
com_err("error", Retval, Format, __VA_ARGS__); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} while(0)
|
||||
|
||||
#define sparse_fatal(Format) \
|
||||
do { \
|
||||
fprintf(stderr, "sparse: "Format); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} while(0)
|
||||
|
||||
static void usage(char *path)
|
||||
{
|
||||
char *progname = basename(path);
|
||||
|
||||
fprintf(stderr, "%s [ options ] <image or block device> <output image>\n"
|
||||
" -c include CRC block\n"
|
||||
" -z gzip output\n"
|
||||
" -S don't use sparse output format\n", progname);
|
||||
}
|
||||
|
||||
static struct buf_item {
|
||||
struct buf_item *next;
|
||||
void *buf[0];
|
||||
} *buf_list;
|
||||
|
||||
static void add_chunk(ext2_filsys fs, struct sparse_file *s, blk_t chunk_start, blk_t chunk_end)
|
||||
{
|
||||
int retval;
|
||||
unsigned int nb_blk = chunk_end - chunk_start;
|
||||
size_t len = nb_blk * fs->blocksize;
|
||||
int64_t offset = (int64_t)chunk_start * (int64_t)fs->blocksize;
|
||||
|
||||
if (params.overwrite_input == false) {
|
||||
if (sparse_file_add_file(s, params.in_file, offset, len, chunk_start) < 0)
|
||||
sparse_fatal("adding data to the sparse file");
|
||||
} else {
|
||||
/*
|
||||
* The input file will be overwritten, make a copy of
|
||||
* the blocks
|
||||
*/
|
||||
struct buf_item *bi = calloc(1, sizeof(struct buf_item) + len);
|
||||
if (buf_list == NULL)
|
||||
buf_list = bi;
|
||||
else {
|
||||
bi->next = buf_list;
|
||||
buf_list = bi;
|
||||
}
|
||||
|
||||
retval = io_channel_read_blk64(fs->io, chunk_start, nb_blk, bi->buf);
|
||||
if (retval < 0)
|
||||
ext2fs_fatal(retval, "reading block %u - %u", chunk_start, chunk_end);
|
||||
|
||||
if (sparse_file_add_data(s, bi->buf, len, chunk_start) < 0)
|
||||
sparse_fatal("adding data to the sparse file");
|
||||
}
|
||||
}
|
||||
|
||||
static void free_chunks(void)
|
||||
{
|
||||
struct buf_item *bi;
|
||||
|
||||
while (buf_list) {
|
||||
bi = buf_list->next;
|
||||
free(buf_list);
|
||||
buf_list = bi;
|
||||
}
|
||||
}
|
||||
|
||||
static struct sparse_file *ext_to_sparse(const char *in_file)
|
||||
{
|
||||
errcode_t retval;
|
||||
ext2_filsys fs;
|
||||
struct sparse_file *s;
|
||||
int64_t chunk_start = -1;
|
||||
blk_t first_blk, last_blk, nb_blk, cur_blk;
|
||||
|
||||
retval = ext2fs_open(in_file, 0, 0, 0, unix_io_manager, &fs);
|
||||
if (retval)
|
||||
ext2fs_fatal(retval, "while reading %s", in_file);
|
||||
|
||||
retval = ext2fs_read_block_bitmap(fs);
|
||||
if (retval)
|
||||
ext2fs_fatal(retval, "while reading block bitmap of %s", in_file);
|
||||
|
||||
first_blk = ext2fs_get_block_bitmap_start2(fs->block_map);
|
||||
last_blk = ext2fs_get_block_bitmap_end2(fs->block_map);
|
||||
nb_blk = last_blk - first_blk + 1;
|
||||
|
||||
s = sparse_file_new(fs->blocksize, (uint64_t)fs->blocksize * (uint64_t)nb_blk);
|
||||
if (!s)
|
||||
sparse_fatal("creating sparse file");
|
||||
|
||||
/*
|
||||
* The sparse format encodes the size of a chunk (and its header) in a
|
||||
* 32-bit unsigned integer (UINT32_MAX)
|
||||
* When writing the chunk, the library uses a single call to write().
|
||||
* Linux's implementation of the 'write' syscall does not allow transfers
|
||||
* larger than INT32_MAX (32-bit _and_ 64-bit systems).
|
||||
* Make sure we do not create chunks larger than this limit.
|
||||
*/
|
||||
int64_t max_blk_per_chunk = (INT32_MAX - 12) / fs->blocksize;
|
||||
|
||||
/* Iter on the blocks to merge contiguous chunk */
|
||||
for (cur_blk = first_blk; cur_blk <= last_blk; ++cur_blk) {
|
||||
if (ext2fs_test_block_bitmap2(fs->block_map, cur_blk)) {
|
||||
if (chunk_start == -1) {
|
||||
chunk_start = cur_blk;
|
||||
} else if (cur_blk - chunk_start + 1 == max_blk_per_chunk) {
|
||||
add_chunk(fs, s, chunk_start, cur_blk);
|
||||
chunk_start = -1;
|
||||
}
|
||||
} else if (chunk_start != -1) {
|
||||
add_chunk(fs, s, chunk_start, cur_blk);
|
||||
chunk_start = -1;
|
||||
}
|
||||
}
|
||||
if (chunk_start != -1)
|
||||
add_chunk(fs, s, chunk_start, cur_blk - 1);
|
||||
|
||||
ext2fs_free(fs);
|
||||
return s;
|
||||
}
|
||||
|
||||
static bool same_file(const char *in, const char *out)
|
||||
{
|
||||
struct stat st1, st2;
|
||||
|
||||
if (access(out, F_OK) == -1)
|
||||
return false;
|
||||
|
||||
if (lstat(in, &st1) == -1)
|
||||
ext2fs_fatal(errno, "stat %s\n", in);
|
||||
if (lstat(out, &st2) == -1)
|
||||
ext2fs_fatal(errno, "stat %s\n", out);
|
||||
return st1.st_ino == st2.st_ino;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
int out_fd;
|
||||
struct sparse_file *s;
|
||||
|
||||
while ((opt = getopt(argc, argv, "czS")) != -1) {
|
||||
switch(opt) {
|
||||
case 'c':
|
||||
params.crc = 1;
|
||||
break;
|
||||
case 'z':
|
||||
params.gzip = 1;
|
||||
break;
|
||||
case 'S':
|
||||
params.sparse = 0;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (optind + 1 >= argc) {
|
||||
usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
params.in_file = strdup(argv[optind++]);
|
||||
params.out_file = strdup(argv[optind]);
|
||||
params.overwrite_input = same_file(params.in_file, params.out_file);
|
||||
|
||||
s = ext_to_sparse(params.in_file);
|
||||
|
||||
out_fd = open(params.out_file, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||
if (out_fd == -1)
|
||||
ext2fs_fatal(errno, "opening %s\n", params.out_file);
|
||||
if (sparse_file_write(s, out_fd, params.gzip, params.sparse, params.crc) < 0)
|
||||
sparse_fatal("writing sparse file");
|
||||
|
||||
sparse_file_destroy(s);
|
||||
|
||||
free(params.in_file);
|
||||
free(params.out_file);
|
||||
free_chunks();
|
||||
close(out_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
169
2025-03-19/e2fsprogs-1.46.2/contrib/android/fsmap.c
Normal file
169
2025-03-19/e2fsprogs-1.46.2/contrib/android/fsmap.c
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
#include "fsmap.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "support/nls-enable.h"
|
||||
|
||||
struct walk_ext_priv_data {
|
||||
char *path;
|
||||
ext2_filsys fs;
|
||||
struct fsmap_format *format;
|
||||
};
|
||||
|
||||
static int walk_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk64_t *blocknr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk64_t ref64_blk EXT2FS_ATTR((unused)),
|
||||
int ref_offset EXT2FS_ATTR((unused)),
|
||||
void *priv)
|
||||
{
|
||||
struct walk_ext_priv_data *pdata = priv;
|
||||
struct fsmap_format *format = pdata->format;
|
||||
|
||||
return format->add_block(fs, *blocknr, blockcnt < 0, format->private);
|
||||
}
|
||||
|
||||
static errcode_t ino_iter_extents(ext2_filsys fs, ext2_ino_t ino,
|
||||
ext2_extent_handle_t extents,
|
||||
struct walk_ext_priv_data *pdata)
|
||||
{
|
||||
blk64_t block;
|
||||
errcode_t retval;
|
||||
blk64_t next_lblk = 0;
|
||||
int op = EXT2_EXTENT_ROOT;
|
||||
struct ext2fs_extent extent;
|
||||
struct fsmap_format *format = pdata->format;
|
||||
|
||||
for (;;) {
|
||||
retval = ext2fs_extent_get(extents, op, &extent);
|
||||
if (retval)
|
||||
break;
|
||||
|
||||
op = EXT2_EXTENT_NEXT;
|
||||
|
||||
if ((extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) ||
|
||||
!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF))
|
||||
continue;
|
||||
|
||||
for (; next_lblk < extent.e_lblk; next_lblk++)
|
||||
format->add_block(fs, 0, 0, format->private);
|
||||
|
||||
block = extent.e_pblk;
|
||||
for (; next_lblk < extent.e_lblk + extent.e_len; next_lblk++)
|
||||
format->add_block(fs, block++, 0, format->private);
|
||||
}
|
||||
|
||||
if (retval == EXT2_ET_EXTENT_NO_NEXT)
|
||||
retval = 0;
|
||||
if (retval) {
|
||||
com_err(__func__, retval, ("getting extents of ino \"%u\""),
|
||||
ino);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t ino_iter_blocks(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct walk_ext_priv_data *pdata)
|
||||
{
|
||||
errcode_t retval;
|
||||
struct ext2_inode inode;
|
||||
ext2_extent_handle_t extents;
|
||||
struct fsmap_format *format = pdata->format;
|
||||
|
||||
retval = ext2fs_read_inode(fs, ino, &inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
|
||||
return format->inline_data(&(inode.i_block[0]),
|
||||
format->private);
|
||||
|
||||
retval = ext2fs_extent_open(fs, ino, &extents);
|
||||
if (retval == EXT2_ET_INODE_NOT_EXTENT) {
|
||||
retval = ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_READ_ONLY,
|
||||
NULL, walk_block, pdata);
|
||||
if (retval) {
|
||||
com_err(__func__, retval, _("listing blocks of ino \"%u\""),
|
||||
ino);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = ino_iter_extents(fs, ino, extents, pdata);
|
||||
|
||||
ext2fs_extent_free(extents);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int is_dir(ext2_filsys fs, ext2_ino_t ino)
|
||||
{
|
||||
struct ext2_inode inode;
|
||||
|
||||
if (ext2fs_read_inode(fs, ino, &inode))
|
||||
return 0;
|
||||
return S_ISDIR(inode.i_mode);
|
||||
}
|
||||
|
||||
static int walk_ext_dir(ext2_ino_t dir EXT2FS_ATTR((unused)),
|
||||
int flags EXT2FS_ATTR((unused)),
|
||||
struct ext2_dir_entry *de,
|
||||
int offset EXT2FS_ATTR((unused)),
|
||||
int blocksize EXT2FS_ATTR((unused)),
|
||||
char *buf EXT2FS_ATTR((unused)), void *priv_data)
|
||||
{
|
||||
errcode_t retval;
|
||||
struct ext2_inode inode;
|
||||
char *filename, *cur_path, *name = de->name;
|
||||
int name_len = de->name_len & 0xff;
|
||||
struct walk_ext_priv_data *pdata = priv_data;
|
||||
struct fsmap_format *format = pdata->format;
|
||||
|
||||
if (!strncmp(name, ".", name_len)
|
||||
|| !strncmp(name, "..", name_len)
|
||||
|| !strncmp(name, "lost+found", 10))
|
||||
return 0;
|
||||
|
||||
if (asprintf(&filename, "%s/%.*s", pdata->path, name_len, name) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
retval = ext2fs_read_inode(pdata->fs, de->inode, &inode);
|
||||
if (retval) {
|
||||
com_err(__func__, retval, _("reading ino \"%u\""), de->inode);
|
||||
goto end;
|
||||
}
|
||||
format->start_new_file(filename, de->inode, &inode, format->private);
|
||||
retval = ino_iter_blocks(pdata->fs, de->inode, pdata);
|
||||
if (retval)
|
||||
return retval;
|
||||
format->end_new_file(format->private);
|
||||
|
||||
retval = 0;
|
||||
if (is_dir(pdata->fs, de->inode)) {
|
||||
cur_path = pdata->path;
|
||||
pdata->path = filename;
|
||||
retval = ext2fs_dir_iterate2(pdata->fs, de->inode, 0, NULL,
|
||||
walk_ext_dir, pdata);
|
||||
pdata->path = cur_path;
|
||||
}
|
||||
|
||||
end:
|
||||
free(filename);
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t fsmap_iter_filsys(ext2_filsys fs, struct fsmap_format *format,
|
||||
const char *file, const char *mountpoint)
|
||||
{
|
||||
struct walk_ext_priv_data pdata;
|
||||
errcode_t retval;
|
||||
|
||||
format->private = format->init(file, mountpoint);
|
||||
pdata.fs = fs;
|
||||
pdata.path = "";
|
||||
pdata.format = format;
|
||||
|
||||
retval = ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_ext_dir, &pdata);
|
||||
|
||||
format->cleanup(format->private);
|
||||
return retval;
|
||||
}
|
||||
29
2025-03-19/e2fsprogs-1.46.2/contrib/android/fsmap.h
Normal file
29
2025-03-19/e2fsprogs-1.46.2/contrib/android/fsmap.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef FSMAP_H
|
||||
# define FSMAP_H
|
||||
|
||||
# ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE // asprintf
|
||||
# endif
|
||||
# include <stdio.h>
|
||||
# include <stdint.h>
|
||||
# include <stdbool.h>
|
||||
# include <sys/types.h>
|
||||
# include <ext2fs/ext2fs.h>
|
||||
|
||||
struct fsmap_format {
|
||||
void* (* init)(const char *file, const char *mountpoint);
|
||||
int (* start_new_file)(char *path, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, void *data);
|
||||
int (* add_block)(ext2_filsys fs, blk64_t blocknr, int metadata,
|
||||
void *data);
|
||||
int (* inline_data)(void *inline_data, void *data);
|
||||
int (* end_new_file)(void *data);
|
||||
int (* cleanup)(void *data);
|
||||
|
||||
void *private;
|
||||
};
|
||||
|
||||
errcode_t fsmap_iter_filsys(ext2_filsys fs, struct fsmap_format *format,
|
||||
const char *file, const char *mountpoint);
|
||||
|
||||
#endif /* !FSMAP_H */
|
||||
375
2025-03-19/e2fsprogs-1.46.2/contrib/android/perms.c
Normal file
375
2025-03-19/e2fsprogs-1.46.2/contrib/android/perms.c
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE //asprintf
|
||||
#endif
|
||||
#include "perms.h"
|
||||
#include "support/nls-enable.h"
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef XATTR_SELINUX_SUFFIX
|
||||
# define XATTR_SELINUX_SUFFIX "selinux"
|
||||
#endif
|
||||
#ifndef XATTR_CAPS_SUFFIX
|
||||
# define XATTR_CAPS_SUFFIX "capability"
|
||||
#endif
|
||||
|
||||
struct inode_params {
|
||||
ext2_filsys fs;
|
||||
char *path;
|
||||
char *filename;
|
||||
char *src_dir;
|
||||
char *target_out;
|
||||
char *mountpoint;
|
||||
fs_config_f fs_config_func;
|
||||
struct selabel_handle *sehnd;
|
||||
time_t fixed_time;
|
||||
const struct ugid_map* uid_map;
|
||||
const struct ugid_map* gid_map;
|
||||
errcode_t error;
|
||||
};
|
||||
|
||||
static errcode_t ino_add_xattr(ext2_filsys fs, ext2_ino_t ino, const char *name,
|
||||
const void *value, int value_len)
|
||||
{
|
||||
errcode_t retval, close_retval;
|
||||
struct ext2_xattr_handle *xhandle;
|
||||
|
||||
retval = ext2fs_xattrs_open(fs, ino, &xhandle);
|
||||
if (retval) {
|
||||
com_err(__func__, retval, _("while opening inode %u"), ino);
|
||||
return retval;
|
||||
}
|
||||
retval = ext2fs_xattrs_read(xhandle);
|
||||
if (retval) {
|
||||
com_err(__func__, retval,
|
||||
_("while reading xattrs of inode %u"), ino);
|
||||
goto xattrs_close;
|
||||
}
|
||||
retval = ext2fs_xattr_set(xhandle, name, value, value_len);
|
||||
if (retval) {
|
||||
com_err(__func__, retval,
|
||||
_("while setting xattrs of inode %u"), ino);
|
||||
goto xattrs_close;
|
||||
}
|
||||
xattrs_close:
|
||||
close_retval = ext2fs_xattrs_close(&xhandle);
|
||||
if (close_retval) {
|
||||
com_err(__func__, close_retval,
|
||||
_("while closing xattrs of inode %u"), ino);
|
||||
return retval ? retval : close_retval;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t set_selinux_xattr(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct inode_params *params)
|
||||
{
|
||||
errcode_t retval;
|
||||
char *secontext = NULL;
|
||||
struct ext2_inode inode;
|
||||
|
||||
if (params->sehnd == NULL)
|
||||
return 0;
|
||||
|
||||
retval = ext2fs_read_inode(fs, ino, &inode);
|
||||
if (retval) {
|
||||
com_err(__func__, retval,
|
||||
_("while reading inode %u"), ino);
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = selabel_lookup(params->sehnd, &secontext, params->filename,
|
||||
inode.i_mode);
|
||||
if (retval < 0) {
|
||||
int saved_errno = errno;
|
||||
com_err(__func__, errno,
|
||||
_("searching for label \"%s\""), params->filename);
|
||||
return saved_errno;
|
||||
}
|
||||
|
||||
retval = ino_add_xattr(fs, ino, "security." XATTR_SELINUX_SUFFIX,
|
||||
secontext, strlen(secontext) + 1);
|
||||
|
||||
freecon(secontext);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns mapped UID/GID if there is a corresponding entry in |mapping|.
|
||||
* Otherwise |id| as is.
|
||||
*/
|
||||
static unsigned int resolve_ugid(const struct ugid_map* mapping,
|
||||
unsigned int id)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < mapping->size; ++i) {
|
||||
const struct ugid_map_entry* entry = &mapping->entries[i];
|
||||
if (entry->parent_id <= id &&
|
||||
id < entry->parent_id + entry->length) {
|
||||
return id + entry->child_id - entry->parent_id;
|
||||
}
|
||||
}
|
||||
|
||||
/* No entry is found. */
|
||||
return id;
|
||||
}
|
||||
|
||||
static errcode_t set_perms_and_caps(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct inode_params *params)
|
||||
{
|
||||
errcode_t retval;
|
||||
uint64_t capabilities = 0;
|
||||
struct ext2_inode inode;
|
||||
struct vfs_cap_data cap_data;
|
||||
unsigned int uid = 0, gid = 0, imode = 0;
|
||||
|
||||
retval = ext2fs_read_inode(fs, ino, &inode);
|
||||
if (retval) {
|
||||
com_err(__func__, retval, _("while reading inode %u"), ino);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Permissions */
|
||||
if (params->fs_config_func != NULL) {
|
||||
const char *filename = params->filename;
|
||||
if (strcmp(filename, params->mountpoint) == 0) {
|
||||
/* The root of the filesystem needs to be an empty string. */
|
||||
filename = "";
|
||||
}
|
||||
params->fs_config_func(filename, S_ISDIR(inode.i_mode),
|
||||
params->target_out, &uid, &gid, &imode,
|
||||
&capabilities);
|
||||
uid = resolve_ugid(params->uid_map, uid);
|
||||
gid = resolve_ugid(params->gid_map, gid);
|
||||
inode.i_uid = (__u16) uid;
|
||||
inode.i_gid = (__u16) gid;
|
||||
ext2fs_set_i_uid_high(inode, (__u16) (uid >> 16));
|
||||
ext2fs_set_i_gid_high(inode, (__u16) (gid >> 16));
|
||||
inode.i_mode = (inode.i_mode & S_IFMT) | (imode & 0xffff);
|
||||
retval = ext2fs_write_inode(fs, ino, &inode);
|
||||
if (retval) {
|
||||
com_err(__func__, retval,
|
||||
_("while writing inode %u"), ino);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* Capabilities */
|
||||
if (!capabilities)
|
||||
return 0;
|
||||
memset(&cap_data, 0, sizeof(cap_data));
|
||||
cap_data.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;
|
||||
cap_data.data[0].permitted = (uint32_t) (capabilities & 0xffffffff);
|
||||
cap_data.data[1].permitted = (uint32_t) (capabilities >> 32);
|
||||
return ino_add_xattr(fs, ino, "security." XATTR_CAPS_SUFFIX,
|
||||
&cap_data, sizeof(cap_data));
|
||||
}
|
||||
|
||||
static errcode_t set_timestamp(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct inode_params *params)
|
||||
{
|
||||
errcode_t retval;
|
||||
struct ext2_inode inode;
|
||||
struct stat stat;
|
||||
char *src_filename = NULL;
|
||||
|
||||
retval = ext2fs_read_inode(fs, ino, &inode);
|
||||
if (retval) {
|
||||
com_err(__func__, retval,
|
||||
_("while reading inode %u"), ino);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (params->fixed_time == -1 && params->src_dir) {
|
||||
/* replace mountpoint from filename with src_dir */
|
||||
if (asprintf(&src_filename, "%s/%s", params->src_dir,
|
||||
params->filename + strlen(params->mountpoint)) < 0) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
retval = lstat(src_filename, &stat);
|
||||
if (retval < 0) {
|
||||
com_err(__func__, errno,
|
||||
_("while lstat file %s"), src_filename);
|
||||
goto end;
|
||||
}
|
||||
inode.i_atime = inode.i_ctime = inode.i_mtime = stat.st_mtime;
|
||||
} else {
|
||||
inode.i_atime = inode.i_ctime = inode.i_mtime = params->fixed_time;
|
||||
}
|
||||
|
||||
retval = ext2fs_write_inode(fs, ino, &inode);
|
||||
if (retval) {
|
||||
com_err(__func__, retval,
|
||||
_("while writing inode %u"), ino);
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
free(src_filename);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int is_dir(ext2_filsys fs, ext2_ino_t ino)
|
||||
{
|
||||
struct ext2_inode inode;
|
||||
|
||||
if (ext2fs_read_inode(fs, ino, &inode))
|
||||
return 0;
|
||||
return S_ISDIR(inode.i_mode);
|
||||
}
|
||||
|
||||
static errcode_t androidify_inode(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct inode_params *params)
|
||||
{
|
||||
errcode_t retval;
|
||||
|
||||
retval = set_timestamp(fs, ino, params);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = set_selinux_xattr(fs, ino, params);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return set_perms_and_caps(fs, ino, params);
|
||||
}
|
||||
|
||||
static int walk_dir(ext2_ino_t dir EXT2FS_ATTR((unused)),
|
||||
int flags EXT2FS_ATTR((unused)),
|
||||
struct ext2_dir_entry *de,
|
||||
int offset EXT2FS_ATTR((unused)),
|
||||
int blocksize EXT2FS_ATTR((unused)),
|
||||
char *buf EXT2FS_ATTR((unused)), void *priv_data)
|
||||
{
|
||||
__u16 name_len;
|
||||
errcode_t retval;
|
||||
struct inode_params *params = (struct inode_params *)priv_data;
|
||||
|
||||
name_len = de->name_len & 0xff;
|
||||
if (!strncmp(de->name, ".", name_len)
|
||||
|| (!strncmp(de->name, "..", name_len)))
|
||||
return 0;
|
||||
|
||||
if (asprintf(¶ms->filename, "%s/%.*s", params->path, name_len,
|
||||
de->name) < 0) {
|
||||
params->error = ENOMEM;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!strncmp(de->name, "lost+found", 10)) {
|
||||
retval = set_selinux_xattr(params->fs, de->inode, params);
|
||||
if (retval)
|
||||
goto end;
|
||||
} else {
|
||||
retval = androidify_inode(params->fs, de->inode, params);
|
||||
if (retval)
|
||||
goto end;
|
||||
if (is_dir(params->fs, de->inode)) {
|
||||
char *cur_path = params->path;
|
||||
char *cur_filename = params->filename;
|
||||
params->path = params->filename;
|
||||
retval = ext2fs_dir_iterate2(params->fs, de->inode, 0, NULL,
|
||||
walk_dir, params);
|
||||
if (retval)
|
||||
goto end;
|
||||
params->path = cur_path;
|
||||
params->filename = cur_filename;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
free(params->filename);
|
||||
params->error |= retval;
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t __android_configure_fs(ext2_filsys fs, char *src_dir,
|
||||
char *target_out,
|
||||
char *mountpoint,
|
||||
fs_config_f fs_config_func,
|
||||
struct selabel_handle *sehnd,
|
||||
time_t fixed_time,
|
||||
const struct ugid_map* uid_map,
|
||||
const struct ugid_map* gid_map)
|
||||
{
|
||||
errcode_t retval;
|
||||
struct inode_params params = {
|
||||
.fs = fs,
|
||||
.src_dir = src_dir,
|
||||
.target_out = target_out,
|
||||
.fs_config_func = fs_config_func,
|
||||
.sehnd = sehnd,
|
||||
.fixed_time = fixed_time,
|
||||
.path = mountpoint,
|
||||
.filename = mountpoint,
|
||||
.mountpoint = mountpoint,
|
||||
.uid_map = uid_map,
|
||||
.gid_map = gid_map,
|
||||
.error = 0
|
||||
};
|
||||
|
||||
/* walk_dir will add the "/". Don't add it twice. */
|
||||
if (strlen(mountpoint) == 1 && mountpoint[0] == '/')
|
||||
params.path = "";
|
||||
|
||||
retval = androidify_inode(fs, EXT2_ROOT_INO, ¶ms);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ext2fs_dir_iterate2(fs, EXT2_ROOT_INO, 0, NULL, walk_dir,
|
||||
¶ms);
|
||||
if (retval)
|
||||
return retval;
|
||||
return params.error;
|
||||
}
|
||||
|
||||
errcode_t android_configure_fs(ext2_filsys fs, char *src_dir, char *target_out,
|
||||
char *mountpoint,
|
||||
struct selinux_opt *seopts EXT2FS_ATTR((unused)),
|
||||
unsigned int nopt EXT2FS_ATTR((unused)),
|
||||
char *fs_config_file, time_t fixed_time,
|
||||
const struct ugid_map* uid_map,
|
||||
const struct ugid_map* gid_map)
|
||||
{
|
||||
errcode_t retval;
|
||||
fs_config_f fs_config_func = NULL;
|
||||
struct selabel_handle *sehnd = NULL;
|
||||
|
||||
/* Retrieve file contexts */
|
||||
#if !defined(__ANDROID__)
|
||||
if (nopt > 0) {
|
||||
sehnd = selabel_open(SELABEL_CTX_FILE, seopts, nopt);
|
||||
if (!sehnd) {
|
||||
int saved_errno = errno;
|
||||
com_err(__func__, errno,
|
||||
_("while opening file contexts \"%s\""),
|
||||
seopts[0].value);
|
||||
return saved_errno;
|
||||
}
|
||||
}
|
||||
#else
|
||||
sehnd = selinux_android_file_context_handle();
|
||||
if (!sehnd) {
|
||||
com_err(__func__, EINVAL,
|
||||
_("while opening android file_contexts"));
|
||||
return EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Load the FS config */
|
||||
if (fs_config_file) {
|
||||
retval = load_canned_fs_config(fs_config_file);
|
||||
if (retval < 0) {
|
||||
com_err(__func__, retval,
|
||||
_("while loading fs_config \"%s\""),
|
||||
fs_config_file);
|
||||
return retval;
|
||||
}
|
||||
fs_config_func = canned_fs_config;
|
||||
} else if (mountpoint)
|
||||
fs_config_func = fs_config;
|
||||
|
||||
return __android_configure_fs(fs, src_dir, target_out, mountpoint,
|
||||
fs_config_func, sehnd, fixed_time,
|
||||
uid_map, gid_map);
|
||||
}
|
||||
66
2025-03-19/e2fsprogs-1.46.2/contrib/android/perms.h
Normal file
66
2025-03-19/e2fsprogs-1.46.2/contrib/android/perms.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#ifndef ANDROID_PERMS_H
|
||||
# define ANDROID_PERMS_H
|
||||
|
||||
# include "config.h"
|
||||
# include <ext2fs/ext2fs.h>
|
||||
|
||||
typedef void (*fs_config_f)(const char *path, int dir,
|
||||
const char *target_out_path,
|
||||
unsigned *uid, unsigned *gid,
|
||||
unsigned *mode, uint64_t *capabilities);
|
||||
|
||||
/*
|
||||
* Represents a range of UID/GID mapping.
|
||||
* This maps the id in [|parent_id|, |parent_id| + |length|) into
|
||||
* [|child_id|, |child_id| + |length|)
|
||||
*/
|
||||
struct ugid_map_entry {
|
||||
unsigned int child_id;
|
||||
unsigned int parent_id;
|
||||
unsigned int length;
|
||||
};
|
||||
|
||||
struct ugid_map {
|
||||
/* The number of elements in |entries|. */
|
||||
size_t size;
|
||||
|
||||
/* An array of entries. If |size| is 0, this is a null pointer. */
|
||||
struct ugid_map_entry* entries;
|
||||
};
|
||||
|
||||
# ifdef _WIN32
|
||||
struct selabel_handle;
|
||||
static inline errcode_t android_configure_fs(ext2_filsys fs,
|
||||
char *src_dir,
|
||||
char *target_out,
|
||||
char *mountpoint,
|
||||
void *seopts,
|
||||
unsigned int nopt,
|
||||
char *fs_config_file,
|
||||
time_t fixed_time,
|
||||
const struct ugid_map* uid_map,
|
||||
const struct ugdi_map* gid_map)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
# else
|
||||
# include <selinux/selinux.h>
|
||||
# include <selinux/label.h>
|
||||
# if defined(__ANDROID__)
|
||||
# include <selinux/android.h>
|
||||
# endif
|
||||
# include <private/android_filesystem_config.h>
|
||||
# include <private/canned_fs_config.h>
|
||||
# include <private/fs_config.h>
|
||||
|
||||
errcode_t android_configure_fs(ext2_filsys fs, char *src_dir,
|
||||
char *target_out,
|
||||
char *mountpoint,
|
||||
struct selinux_opt *seopts,
|
||||
unsigned int nopt,
|
||||
char *fs_config_file, time_t fixed_time,
|
||||
const struct ugid_map* uid_map,
|
||||
const struct ugid_map* gid_map);
|
||||
|
||||
# endif
|
||||
#endif /* !ANDROID_PERMS_H */
|
||||
45
2025-03-19/e2fsprogs-1.46.2/contrib/build-rpm
Normal file
45
2025-03-19/e2fsprogs-1.46.2/contrib/build-rpm
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#!/bin/sh
|
||||
|
||||
# enable xtrace output if requested
|
||||
if [ -n ${ENABLE_XTRACE:-''} ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
# Build an e2fsprogs RPM from cvs
|
||||
|
||||
pwd=`pwd`
|
||||
currdir=`basename $pwd`
|
||||
pkgname=`grep Name: e2fsprogs.spec | awk '{print $2;}'`
|
||||
pkgvers=`grep Version: e2fsprogs.spec | awk '{print $2;}'`
|
||||
builddir=${pkgname}-${pkgvers}
|
||||
|
||||
# ensure that $TMP is set to something
|
||||
TMP=${TMP:-'/tmp'}
|
||||
|
||||
cd ..
|
||||
tmpdir=`mktemp -d ${RPM_TMPDIR:-$TMP}/rpmtmp.XXXXXX`
|
||||
|
||||
# We need to build a tarball for the SRPM using $builddir as the
|
||||
# directory name (since that's what RPM will expect it to unpack
|
||||
# into). That may require a symlink.
|
||||
|
||||
# Make a recursive-symlink copy of the source dir
|
||||
cp -sR `pwd`/$currdir $tmpdir/$builddir || exit 1
|
||||
|
||||
# Remove any build files from the temporary tarball directory
|
||||
[ -f $tmpdir/$builddir/Makefile ] && make -C $tmpdir/$builddir distclean
|
||||
|
||||
EXCLUDE="--exclude .hg* --exclude .pc*"
|
||||
(cd $tmpdir && tar czfh ${builddir}.tar.gz $EXCLUDE $builddir)
|
||||
|
||||
[ "`rpmbuild --version 2> /dev/null`" ] && RPM=rpmbuild || RPM=rpm
|
||||
|
||||
$RPM --define "_sourcedir $tmpdir" \
|
||||
--define "_topdir ${RPM_TOPDIR:-$(rpm -E %_topdir)}" \
|
||||
--define "_tmpdir ${RPM_TMPDIR:-$TMP}" \
|
||||
--define "extra_config_flags ${EXTRA_CONFIG_FLAGS:-''}" \
|
||||
-ba $currdir/e2fsprogs.spec
|
||||
|
||||
rpm_exit=$?
|
||||
rm -rf $tmpdir
|
||||
exit $rpm_exit
|
||||
118
2025-03-19/e2fsprogs-1.46.2/contrib/dconf
Normal file
118
2025-03-19/e2fsprogs-1.46.2/contrib/dconf
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#!/bin/sh
|
||||
#$Id$
|
||||
# Create Adobe-PostScript file that graphically displays the output of
|
||||
# dumpe2fs(8). Use "dumpe2fs | dconf" to create a PostScript file on stdout.
|
||||
# Developed and tested for Linux 1.0.
|
||||
# Copyright (c) 1994
|
||||
# Ulrich Windl
|
||||
# ALte Regensburger Strasse 11a
|
||||
# D-93149 Nittenau, Germany
|
||||
# <Ulrich.Windl@rz.uni-regensburg.de>
|
||||
SELF=`basename $0`
|
||||
AWKFILE=/tmp/${SELF}.awk
|
||||
TEMPFILE=/tmp/${SELF}.tmp
|
||||
echo '
|
||||
BEGIN {
|
||||
print "B"
|
||||
}
|
||||
/^Inode count:/ {
|
||||
ic=$3; next
|
||||
}
|
||||
/^Block count:/ {
|
||||
bc=$3; next
|
||||
}
|
||||
/^First block:/ {
|
||||
fb=$3; next
|
||||
}
|
||||
/^Block size:/ {
|
||||
bs=$3; next
|
||||
}
|
||||
/^Blocks per group:/ {
|
||||
bpg=$4
|
||||
printf("BC %d\n", bpg)
|
||||
printf("GC %d\n", (bc + bpg - 1) / bpg)
|
||||
next
|
||||
}
|
||||
/^Inodes per group:/ {
|
||||
ipg=$4; next
|
||||
}
|
||||
/^Last write time:/ {
|
||||
lwtime=$0; gsub("Last write time:[ ]+", "", lwtime)
|
||||
printf("T %s\n", lwtime)
|
||||
next
|
||||
}
|
||||
/^Group [0-9]+:/ {
|
||||
group=$2; gsub(":", "", group)
|
||||
block=""
|
||||
group_start=group*bpg+fb
|
||||
group_end=group_start+bpg
|
||||
printf("G %d : %d - %d\n", group, group_start, group_end)
|
||||
next
|
||||
}
|
||||
/^[ ]+Free blocks: / {
|
||||
for ( i=3; i < NF; ++i ) {
|
||||
block=$i; gsub(",", "", block)
|
||||
if ( index(block, "-") == 0 ) block=block "-" block
|
||||
pos=index(block, "-")
|
||||
printf("FB %d-%d\n",
|
||||
substr(block, 0, pos) - group_start,
|
||||
substr(block, pos + 1) - group_start)
|
||||
}
|
||||
if ( block == "" ) printf("Group %d is full\n", group)
|
||||
print "----"
|
||||
next
|
||||
}
|
||||
END {
|
||||
printf("E %s\n", lwtime)
|
||||
}' >$AWKFILE
|
||||
awk -f $AWKFILE $* >$TEMPFILE
|
||||
echo '
|
||||
BEGIN {
|
||||
printf("%%!PS-Adobe\n")
|
||||
printf("%%%%BoundingBox: 0 0 1 1\n")
|
||||
printf("/rect {/y2 exch def /x2 exch def /y1 exch def /x1 exch def\n")
|
||||
printf(" newpath x1 y1 moveto x2 y1 lineto x2 y2 lineto\n")
|
||||
printf(" x1 y2 lineto closepath} def\n")
|
||||
printf("/fb {rect gsave 1.0 setgray fill grestore} def\n")
|
||||
printf("/dg {rect gsave gsave 0.0 setgray fill grestore\n")
|
||||
printf(" 0.5 setgray stroke grestore} def\n")
|
||||
printf("/textxy {moveto show} bind def\n")
|
||||
printf("0.0001 setlinewidth\n")
|
||||
}
|
||||
$1 == "GC" && NF == 2 {
|
||||
number_of_groups=$2
|
||||
printf("/Times-Roman findfont %g scalefont setfont\n",
|
||||
1.0 / number_of_groups)
|
||||
next
|
||||
}
|
||||
$1 == "BC" && NF == 2 {
|
||||
blocks_per_group=$2; next
|
||||
}
|
||||
$1 == "T" && NF > 1 {
|
||||
printf("(%s) %g %g textxy\n",
|
||||
substr($0, 2), 0, 1.02)
|
||||
next
|
||||
}
|
||||
$1 == "G" && NF == 6 && $3 == ":" && $5 == "-" {
|
||||
group_index=$2
|
||||
gs=$4
|
||||
ge=$6
|
||||
height=1.0 / number_of_groups
|
||||
vstart=group_index * height
|
||||
printf("%% group %d of %d:\n0 %g 1 %g dg\n",
|
||||
group_index, number_of_groups, vstart, vstart + height)
|
||||
printf("(Group %s) 1.02 %g textxy\n", group_index, vstart)
|
||||
next
|
||||
}
|
||||
$1 == "FB" && NF == 2 {
|
||||
pos = index($2, "-")
|
||||
printf("%% hole %s\n%g %g %g %g fb\n",
|
||||
$2, substr($2, 0, pos) / blocks_per_group, vstart,
|
||||
(substr($2, pos + 1) + 1) / blocks_per_group, vstart + height)
|
||||
next
|
||||
}
|
||||
END {
|
||||
printf("%%%%EOF\n")
|
||||
}
|
||||
' >$AWKFILE
|
||||
awk -f $AWKFILE $TEMPFILE
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue