summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Stultz <john.stultz@linaro.org>2011-08-19 16:41:55 -0700
committerJohn Stultz <john.stultz@linaro.org>2011-08-19 16:41:55 -0700
commitd3828df964e542533765b23f9a343657c7860e17 (patch)
treea7c34aae8835dc9db8a0df8adafdffe9ea85f651
parent7c52cc1dd1b8930107cce801a161df10b8a34275 (diff)
parentefcf89c8eb62b7c0c5976cb94f892c891afea199 (diff)
Merge branch 'upstream/android-3.0' into linaro-android-3.0
-rw-r--r--drivers/net/wireless/bcmdhd/dhd.h7
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_common.c57
-rw-r--r--include/linux/kernel.h3
-rw-r--r--kernel/panic.c8
-rw-r--r--net/netfilter/xt_qtaguid.c309
5 files changed, 243 insertions, 141 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h
index ea8f67ce8b4..b0df6c77200 100644
--- a/drivers/net/wireless/bcmdhd/dhd.h
+++ b/drivers/net/wireless/bcmdhd/dhd.h
@@ -71,6 +71,12 @@ enum dhd_bus_state {
DHD_BUS_DATA /* Ready for frame transfers */
};
+/* Firmware requested operation mode */
+#define STA_MASK 0x0001
+#define HOSTAPD_MASK 0x0002
+#define WFD_MASK 0x0004
+#define SOFTAP_FW_MASK 0x0008
+
enum dhd_bus_wake_state {
WAKE_LOCK_OFF,
WAKE_LOCK_PRIV,
@@ -173,6 +179,7 @@ typedef struct dhd_pub {
wl_country_t dhd_cspec; /* Current Locale info */
char eventmask[WL_EVENTING_MASK_LEN];
+ int op_mode; /* STA, HostAPD, WFD, SoftAP */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK)
struct wake_lock wakelock[WAKE_LOCK_MAX];
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
index 2ad61868484..66d60420069 100644
--- a/drivers/net/wireless/bcmdhd/dhd_common.c
+++ b/drivers/net/wireless/bcmdhd/dhd_common.c
@@ -1535,7 +1535,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
uint bcn_timeout = 4;
uint retry_max = 3;
int arpoe = 1;
- int arp_ol = 0xf;
int scan_assoc_time = 40;
int scan_unassoc_time = 40;
const char *str;
@@ -1552,7 +1551,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#if defined(SOFTAP)
uint dtim = 1;
#endif
-#ifdef AP
+#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
#endif /* AP */
#if defined(AP) || defined(WLP2P)
@@ -1562,6 +1561,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
struct ether_addr ea_addr;
#endif /* GET_CUSTOM_MAC_ENABLE */
+ dhd->op_mode = 0;
#ifdef GET_CUSTOM_MAC_ENABLE
ret = dhd_custom_get_mac_address(ea_addr.octet);
if (!ret) {
@@ -1610,9 +1610,39 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
}
#endif /* SET_RANDOM_MAC_SOFTAP */
- DHD_ERROR(("Firmware up: Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
- dhd->mac.octet[0], dhd->mac.octet[1], dhd->mac.octet[2],
- dhd->mac.octet[3], dhd->mac.octet[4], dhd->mac.octet[5]));
+#if !defined(AP) && defined(WLP2P)
+ /* Check if firmware with WFD support used */
+ if (strstr(fw_path, "_p2p") != NULL) {
+ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret));
+ } else {
+ dhd->op_mode |= WFD_MASK;
+ arpoe = 0;
+ }
+ }
+#endif /* !defined(AP) && defined(WLP2P) */
+
+#if !defined(AP) && defined(WL_CFG80211)
+ /* Check if firmware with HostAPD support used */
+ if (strstr(fw_path, "_apsta") != NULL) {
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret));
+ } else {
+ dhd->op_mode |= HOSTAPD_MASK;
+ arpoe = 0;
+ }
+ }
+#endif /* !defined(AP) && defined(WL_CFG80211) */
+ DHD_ERROR(("Firmware up: op_mode=%d, "
+ "Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+ dhd->op_mode,
+ dhd->mac.octet[0], dhd->mac.octet[1], dhd->mac.octet[2],
+ dhd->mac.octet[3], dhd->mac.octet[4], dhd->mac.octet[5]));
/* Set Country code */
if (dhd->dhd_cspec.ccode[0] != 0) {
@@ -1655,16 +1685,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
/* Setup assoc_retry_max count to reconnect target AP in dongle */
bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-#ifdef AP
+#if defined(AP) && !defined(WLP2P)
/* Turn off MPC in AP mode */
bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-#endif /* AP */
-#if defined(AP) || defined(WLP2P)
- /* Enable APSTA mode */
bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-#endif /* defined(AP) || defined(WLP2P) */
+#endif /* defined(AP) && !defined(WLP2P) */
#if defined(SOFTAP)
if (ap_fw_loaded == TRUE) {
dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
@@ -1727,12 +1754,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
sizeof(scan_unassoc_time), TRUE, 0);
- /* Set ARP offload */
- bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-
/* add a default packet filter pattern */
str = "pkt_filter_add";
str_len = strlen(str);
@@ -1786,9 +1807,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#ifdef ARP_OFFLOAD_SUPPORT
/* Set and enable ARP offload feature for STA only */
- if (dhd_arp_enable && !ap_fw_loaded) {
+ if (arpoe && !ap_fw_loaded) {
dhd_arp_offload_set(dhd, dhd_arp_mode);
- dhd_arp_offload_enable(dhd, dhd_arp_enable);
+ dhd_arp_offload_enable(dhd, arpoe);
} else {
dhd_arp_offload_set(dhd, 0);
dhd_arp_offload_enable(dhd, FALSE);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 953352a8833..47e8dbea85c 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -736,4 +736,7 @@ extern int __build_bug_on_failed;
# define REBUILD_DUE_TO_FTRACE_MCOUNT_RECORD
#endif
+/* To identify board information in panic logs, set this */
+extern char *mach_panic_string;
+
#endif
diff --git a/kernel/panic.c b/kernel/panic.c
index 5578d0adc27..a136da2f396 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -27,6 +27,9 @@
#define PANIC_TIMER_STEP 100
#define PANIC_BLINK_SPD 18
+/* Machine specific panic information string */
+char *mach_panic_string;
+
int panic_on_oops;
static unsigned long tainted_mask;
static int pause_on_oops;
@@ -345,6 +348,11 @@ late_initcall(init_oops_id);
void print_oops_end_marker(void)
{
init_oops_id();
+
+ if (mach_panic_string)
+ printk(KERN_WARNING "Board Information: %s\n",
+ mach_panic_string);
+
printk(KERN_WARNING "---[ end trace %016llx ]---\n",
(unsigned long long)oops_id);
}
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index b04b4710574..b9dcfde9976 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -183,7 +183,6 @@ struct tag_stat {
* matching parent uid_tag.
*/
struct data_counters *parent_counters;
- struct proc_dir_entry *proc_ptr;
};
struct iface_stat {
@@ -215,8 +214,11 @@ struct iface_stat_work {
* This is the tag against which tag_stat.counters will be billed.
*/
struct sock_tag {
- struct rb_node node;
- struct sock *sk;
+ struct rb_node sock_node;
+ struct sock *sk; /* Only used as a number, never dereferenced */
+ /* The socket is needed for sockfd_put() */
+ struct socket *socket;
+
tag_t tag;
};
@@ -345,24 +347,31 @@ static void tag_node_tree_insert(struct tag_node *data, struct rb_root *root)
static void tag_stat_tree_insert(struct tag_stat *data, struct rb_root *root)
{
- tag_node_tree_insert((struct tag_node *)data, root);
+ tag_node_tree_insert(&data->tn, root);
}
static struct tag_stat *tag_stat_tree_search(struct rb_root *root, tag_t tag)
{
- return (struct tag_stat *)tag_node_tree_search(root, tag);
+ struct tag_node *node = tag_node_tree_search(root, tag);
+ if (!node)
+ return NULL;
+ return rb_entry(&node->node, struct tag_stat, tn.node);
}
static void tag_counter_set_tree_insert(struct tag_counter_set *data,
struct rb_root *root)
{
- tag_node_tree_insert((struct tag_node *)data, root);
+ tag_node_tree_insert(&data->tn, root);
}
static struct tag_counter_set *tag_counter_set_tree_search(struct rb_root *root,
tag_t tag)
{
- return (struct tag_counter_set *)tag_node_tree_search(root, tag);
+ struct tag_node *node = tag_node_tree_search(root, tag);
+ if (!node)
+ return NULL;
+ return rb_entry(&node->node, struct tag_counter_set, tn.node);
+
}
static struct sock_tag *sock_tag_tree_search(struct rb_root *root,
@@ -371,7 +380,8 @@ static struct sock_tag *sock_tag_tree_search(struct rb_root *root,
struct rb_node *node = root->rb_node;
while (node) {
- struct sock_tag *data = rb_entry(node, struct sock_tag, node);
+ struct sock_tag *data = rb_entry(node, struct sock_tag,
+ sock_node);
ptrdiff_t result = sk - data->sk;
if (result < 0)
node = node->rb_left;
@@ -389,7 +399,8 @@ static void sock_tag_tree_insert(struct sock_tag *data, struct rb_root *root)
/* Figure out where to put new node */
while (*new) {
- struct sock_tag *this = rb_entry(*new, struct sock_tag, node);
+ struct sock_tag *this = rb_entry(*new, struct sock_tag,
+ sock_node);
ptrdiff_t result = data->sk - this->sk;
parent = *new;
if (result < 0)
@@ -401,8 +412,8 @@ static void sock_tag_tree_insert(struct sock_tag *data, struct rb_root *root)
}
/* Add new node and rebalance tree. */
- rb_link_node(&data->node, parent, new);
- rb_insert_color(&data->node, root);
+ rb_link_node(&data->sock_node, parent, new);
+ rb_insert_color(&data->sock_node, root);
}
static int read_proc_u64(char *page, char **start, off_t off,
@@ -412,6 +423,7 @@ static int read_proc_u64(char *page, char **start, off_t off,
uint64_t value;
char *p = page;
uint64_t *iface_entry = data;
+
if (!data)
return 0;
@@ -430,6 +442,7 @@ static int read_proc_bool(char *page, char **start, off_t off,
bool value;
char *p = page;
bool *bool_entry = data;
+
if (!data)
return 0;
@@ -447,7 +460,7 @@ static int get_active_counter_set(tag_t tag)
struct tag_counter_set *tcs;
MT_DEBUG("qtaguid: get_active_counter_set(tag=0x%llx)"
- " (uid=%d)\n",
+ " (uid=%u)\n",
tag, get_uid_from_tag(tag));
/* For now we only handle UID tags for active sets */
tag = get_utag_from_tag(tag);
@@ -469,11 +482,10 @@ static struct iface_stat *get_iface_entry(const char *ifname)
/* Find the entry for tracking the specified tag within the interface */
if (ifname == NULL) {
- pr_info("iface_stat: NULL device name\n");
+ pr_info("qtaguid: iface_stat: get() NULL device name\n");
return NULL;
}
-
/* Iterate over interfaces */
list_for_each_entry(iface_entry, &iface_stat_list, list) {
if (!strcmp(ifname, iface_entry->ifname))
@@ -525,12 +537,14 @@ static struct iface_stat *iface_alloc(const char *ifname)
new_iface = kzalloc(sizeof(*new_iface), GFP_ATOMIC);
if (new_iface == NULL) {
- pr_err("qtaguid: iface_stat: create(): failed to alloc iface_stat\n");
+ pr_err("qtaguid: iface_stat: create(%s): "
+ "iface_stat alloc failed\n", ifname);
return NULL;
}
new_iface->ifname = kstrdup(ifname, GFP_ATOMIC);
if (new_iface->ifname == NULL) {
- pr_err("qtaguid: iface_stat: create(): failed to alloc ifname\n");
+ pr_err("qtaguid: iface_stat: create(%s): "
+ "ifname alloc failed\n", ifname);
kfree(new_iface);
return NULL;
}
@@ -544,8 +558,8 @@ static struct iface_stat *iface_alloc(const char *ifname)
*/
isw = kmalloc(sizeof(*isw), GFP_ATOMIC);
if (!isw) {
- pr_err("qtaguid: iface_stat: create(): "
- "failed to alloc work for %s\n", new_iface->ifname);
+ pr_err("qtaguid: iface_stat: create(%s): "
+ "work alloc failed\n", new_iface->ifname);
kfree(new_iface->ifname);
kfree(new_iface);
return NULL;
@@ -571,10 +585,11 @@ void iface_stat_create(const struct net_device *net_dev,
__be32 ipaddr = 0;
struct iface_stat *new_iface;
- IF_DEBUG("qtaguid: iface_stat: create(): ifa=%p netdev=%p->name=%s\n",
- ifa, net_dev, net_dev ? net_dev->name : "");
+ IF_DEBUG("qtaguid: iface_stat: create(%s): ifa=%p netdev=%p\n",
+ net_dev ? net_dev->name : "?",
+ ifa, net_dev);
if (!net_dev) {
- pr_err("qtaguid: iface_stat: create(): no net dev!\n");
+ pr_err("qtaguid: iface_stat: create(): no net dev\n");
return;
}
@@ -582,16 +597,16 @@ void iface_stat_create(const struct net_device *net_dev,
if (!ifa) {
in_dev = in_dev_get(net_dev);
if (!in_dev) {
- pr_err("qtaguid: iface_stat: create(): "
- "no inet dev for %s!\n", ifname);
+ pr_err("qtaguid: iface_stat: create(%s): no inet dev\n",
+ ifname);
return;
}
- IF_DEBUG("qtaguid: iface_stat: create(): in_dev=%p ifname=%p\n",
- in_dev, ifname);
+ IF_DEBUG("qtaguid: iface_stat: create(%s): in_dev=%p\n",
+ ifname, in_dev);
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
- IF_DEBUG("qtaguid: iface_stat: create(): "
- "ifa=%p ifname=%s ifa_label=%s\n",
- ifa, ifname,
+ IF_DEBUG("qtaguid: iface_stat: create(%s): "
+ "ifa=%p ifa_label=%s\n",
+ ifname, ifa,
ifa->ifa_label ? ifa->ifa_label : "(null)");
if (ifa->ifa_label && !strcmp(ifname, ifa->ifa_label))
break;
@@ -599,8 +614,7 @@ void iface_stat_create(const struct net_device *net_dev,
}
if (!ifa) {
- IF_DEBUG("qtaguid: iface_stat: create(): "
- "dev %s has no matching IP\n",
+ IF_DEBUG("qtaguid: iface_stat: create(%s): no matching IP\n",
ifname);
goto done_put;
}
@@ -609,29 +623,29 @@ void iface_stat_create(const struct net_device *net_dev,
spin_lock_bh(&iface_stat_list_lock);
entry = get_iface_entry(ifname);
if (entry != NULL) {
- IF_DEBUG("qtaguid: iface_stat: create(): dev %s entry=%p\n",
+ IF_DEBUG("qtaguid: iface_stat: create(%s): entry=%p\n",
ifname, entry);
if (ipv4_is_loopback(ipaddr)) {
entry->active = false;
- IF_DEBUG("qtaguid: iface_stat: create(): "
- "disable tracking of loopback dev %s\n",
+ IF_DEBUG("qtaguid: iface_stat: create(%s): "
+ "disable tracking of loopback dev\n",
ifname);
} else {
entry->active = true;
- IF_DEBUG("qtaguid: iface_stat: create(): "
- "enable tracking of dev %s with ip=%pI4\n",
+ IF_DEBUG("qtaguid: iface_stat: create(%s): "
+ "enable tracking. ip=%pI4\n",
ifname, &ipaddr);
}
goto done_unlock_put;
} else if (ipv4_is_loopback(ipaddr)) {
- IF_DEBUG("qtaguid: iface_stat: create(): ignore loopback dev %s"
- " ip=%pI4\n", ifname, &ipaddr);
+ IF_DEBUG("qtaguid: iface_stat: create(%s): "
+ "ignore loopback dev. ip=%pI4\n", ifname, &ipaddr);
goto done_unlock_put;
}
new_iface = iface_alloc(ifname);
- IF_DEBUG("qtaguid: iface_stat: create(): done "
- "entry=%p dev=%s ip=%pI4\n", new_iface, ifname, &ipaddr);
+ IF_DEBUG("qtaguid: iface_stat: create(%s): done "
+ "entry=%p ip=%pI4\n", ifname, new_iface, &ipaddr);
done_unlock_put:
spin_unlock_bh(&iface_stat_list_lock);
@@ -659,17 +673,16 @@ void iface_stat_create_ipv6(const struct net_device *net_dev,
in_dev = in_dev_get(net_dev);
if (!in_dev) {
- pr_err("qtaguid: iface_stat: create6(): no inet dev for %s!\n",
+ pr_err("qtaguid: iface_stat: create6(%s): no inet dev\n",
ifname);
return;
}
- IF_DEBUG("qtaguid: iface_stat: create6(): in_dev=%p ifname=%p\n",
- in_dev, ifname);
+ IF_DEBUG("qtaguid: iface_stat: create6(%s): in_dev=%p\n",
+ ifname, in_dev);
if (!ifa) {
- IF_DEBUG("qtaguid: iface_stat: create6(): "
- "dev %s has no matching IP\n",
+ IF_DEBUG("qtaguid: iface_stat: create6(%s): no matching IP\n",
ifname);
goto done_put;
}
@@ -678,30 +691,30 @@ void iface_stat_create_ipv6(const struct net_device *net_dev,
spin_lock_bh(&iface_stat_list_lock);
entry = get_iface_entry(ifname);
if (entry != NULL) {
- IF_DEBUG("qtaguid: iface_stat: create6(): dev %s entry=%p\n",
+ IF_DEBUG("qtaguid: iface_stat: create6(%s): entry=%p\n",
ifname, entry);
if (addr_type & IPV6_ADDR_LOOPBACK) {
entry->active = false;
- IF_DEBUG("qtaguid: iface_stat: create6(): "
- "disable tracking of loopback dev %s\n",
+ IF_DEBUG("qtaguid: iface_stat: create6(%s): "
+ "disable tracking of loopback dev\n",
ifname);
} else {
entry->active = true;
- IF_DEBUG("qtaguid: iface_stat: create6(): "
- "enable tracking of dev %s with ip=%pI6c\n",
+ IF_DEBUG("qtaguid: iface_stat: create6(%s): "
+ "enable tracking. ip=%pI6c\n",
ifname, &ifa->addr);
}
goto done_unlock_put;
} else if (addr_type & IPV6_ADDR_LOOPBACK) {
- IF_DEBUG("qtaguid: iface_stat: create6(): "
- "ignore loopback dev %s ip=%pI6c\n",
+ IF_DEBUG("qtaguid: iface_stat: create6(%s): "
+ "ignore loopback dev. ip=%pI6c\n",
ifname, &ifa->addr);
goto done_unlock_put;
}
new_iface = iface_alloc(ifname);
- IF_DEBUG("qtaguid: iface_stat: create6(): done "
- "entry=%p dev=%s ip=%pI6c\n", new_iface, ifname, &ifa->addr);
+ IF_DEBUG("qtaguid: iface_stat: create6(%s): done "
+ "entry=%p ip=%pI6c\n", ifname, new_iface, &ifa->addr);
done_unlock_put:
spin_unlock_bh(&iface_stat_list_lock);
@@ -760,22 +773,22 @@ static void iface_stat_update(struct net_device *dev)
spin_lock_bh(&iface_stat_list_lock);
entry = get_iface_entry(dev->name);
if (entry == NULL) {
- IF_DEBUG("qtaguid: iface_stat: dev %s monitor not found\n",
+ IF_DEBUG("qtaguid: iface_stat_update: dev=%s not tracked\n",
dev->name);
spin_unlock_bh(&iface_stat_list_lock);
return;
}
+ IF_DEBUG("qtaguid: iface_stat_update: dev=%s entry=%p\n",
+ dev->name, entry);
if (entry->active) {
entry->tx_bytes += stats->tx_bytes;
entry->tx_packets += stats->tx_packets;
entry->rx_bytes += stats->rx_bytes;
entry->rx_packets += stats->rx_packets;
entry->active = false;
- IF_DEBUG("qtaguid: iface_stat: Updating stats for "
- "dev %s which went down\n", dev->name);
} else {
- IF_DEBUG("qtaguid: iface_stat: Did not update stats for "
- "dev %s which went down\n", dev->name);
+ IF_DEBUG("qtaguid: iface_stat_update: dev=%s inactive\n",
+ dev->name);
}
spin_unlock_bh(&iface_stat_list_lock);
}
@@ -785,7 +798,7 @@ static void tag_stat_update(struct tag_stat *tag_entry,
{
int active_set;
active_set = get_active_counter_set(tag_entry->tn.tag);
- MT_DEBUG("qtaguid: tag_stat_update(tag=0x%llx (uid=%d) set=%d "
+ MT_DEBUG("qtaguid: tag_stat_update(tag=0x%llx (uid=%u) set=%d "
"dir=%d proto=%d bytes=%d)\n",
tag_entry->tn.tag, get_uid_from_tag(tag_entry->tn.tag),
active_set, direction, proto, bytes);
@@ -806,11 +819,11 @@ static struct tag_stat *create_if_tag_stat(struct iface_stat *iface_entry,
{
struct tag_stat *new_tag_stat_entry = NULL;
IF_DEBUG("qtaguid: iface_stat: create_if_tag_stat(): ife=%p tag=0x%llx"
- " (uid=%d)\n",
+ " (uid=%u)\n",
iface_entry, tag, get_uid_from_tag(tag));
new_tag_stat_entry = kzalloc(sizeof(*new_tag_stat_entry), GFP_ATOMIC);
if (!new_tag_stat_entry) {
- pr_err("qtaguid: iface_stat: failed to alloc new tag entry\n");
+ pr_err("qtaguid: iface_stat: tag stat alloc failed\n");
goto done;
}
new_tag_stat_entry->tn.tag = tag;
@@ -831,19 +844,20 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
struct iface_stat *iface_entry;
struct tag_stat *new_tag_stat;
MT_DEBUG("qtaguid: if_tag_stat_update(ifname=%s "
- "uid=%d sk=%p dir=%d proto=%d bytes=%d)\n",
+ "uid=%u sk=%p dir=%d proto=%d bytes=%d)\n",
ifname, uid, sk, direction, proto, bytes);
iface_entry = get_iface_entry(ifname);
if (!iface_entry) {
- pr_err("qtaguid: iface_stat: interface %s not found\n", ifname);
+ pr_err("qtaguid: iface_stat: stat_update() %s not found\n",
+ ifname);
return;
}
/* It is ok to process data when an iface_entry is inactive */
- MT_DEBUG("qtaguid: iface_stat: stat_update() got entry=%p\n",
- iface_entry);
+ MT_DEBUG("qtaguid: iface_stat: stat_update() dev=%s entry=%p\n",
+ ifname, iface_entry);
/*
* Look for a tagged sock.
@@ -860,7 +874,7 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
tag = combine_atag_with_uid(acct_tag, uid);
}
MT_DEBUG("qtaguid: iface_stat: stat_update(): "
- " looking for tag=0x%llx (uid=%d) in ife=%p\n",
+ " looking for tag=0x%llx (uid=%u) in ife=%p\n",
tag, get_uid_from_tag(tag), iface_entry);
/* Loop over tag list under this interface for {acct_tag,uid_tag} */
spin_lock_bh(&iface_entry->tag_stat_list_lock);
@@ -913,12 +927,6 @@ static int iface_netdev_event_handler(struct notifier_block *nb,
switch (event) {
case NETDEV_UP:
- case NETDEV_REBOOT:
- case NETDEV_CHANGE:
- case NETDEV_REGISTER: /* Most likely no IP */
- case NETDEV_CHANGEADDR: /* MAC addr change */
- case NETDEV_CHANGENAME:
- case NETDEV_FEAT_CHANGE: /* Might be usefull when cell type changes */
iface_stat_create(dev, NULL);
break;
case NETDEV_UNREGISTER:
@@ -992,25 +1000,26 @@ static int __init iface_stat_init(struct proc_dir_entry *parent_procdir)
iface_stat_procdir = proc_mkdir(iface_stat_procdirname, parent_procdir);
if (!iface_stat_procdir) {
- pr_err("qtaguid: iface_stat: failed to create proc entry\n");
+ pr_err("qtaguid: iface_stat: init failed to create proc entry\n");
err = -1;
goto err;
}
err = register_netdevice_notifier(&iface_netdev_notifier_blk);
if (err) {
- pr_err("qtaguid: iface_stat: failed to register dev event handler\n");
+ pr_err("qtaguid: iface_stat: init "
+ "failed to register dev event handler\n");
goto err_zap_entry;
}
err = register_inetaddr_notifier(&iface_inetaddr_notifier_blk);
if (err) {
- pr_err("qtaguid: iface_stat: "
+ pr_err("qtaguid: iface_stat: init "
"failed to register ipv4 dev event handler\n");
goto err_unreg_nd;
}
err = register_inet6addr_notifier(&iface_inet6addr_notifier_blk);
if (err) {
- pr_err("qtaguid: iface_stat: "
+ pr_err("qtaguid: iface_stat: init "
"failed to register ipv6 dev event handler\n");
goto err_unreg_ip4_addr;
}
@@ -1116,6 +1125,9 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
uid_t sock_uid;
bool res;
+ if (unlikely(module_passive))
+ return (info->match ^ info->invert) == 0;
+
MT_DEBUG("qtaguid[%d]: entered skb=%p par->in=%p/out=%p fam=%d\n",
par->hooknum, skb, par->in, par->out, par->family);
@@ -1145,7 +1157,7 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
par->hooknum, sk, sk->sk_socket,
sk->sk_socket ? sk->sk_socket->file : (void *)-1LL);
filp = sk->sk_socket ? sk->sk_socket->file : NULL;
- MT_DEBUG("qtaguid[%d]: filp...uid=%d\n",
+ MT_DEBUG("qtaguid[%d]: filp...uid=%u\n",
par->hooknum, filp ? filp->f_cred->fsuid : -1);
}
@@ -1254,12 +1266,13 @@ static int qtaguid_ctrl_proc_read(char *page, char **num_items_returned,
node = rb_next(node)) {
if (item_index++ < items_to_skip)
continue;
- sock_tag_entry = rb_entry(node, struct sock_tag, node);
+ sock_tag_entry = rb_entry(node, struct sock_tag, sock_node);
uid = get_uid_from_tag(sock_tag_entry->tag);
- CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%d)\n",
- sock_tag_entry->sk,
- sock_tag_entry->tag,
- uid);
+ CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%u)\n",
+ sock_tag_entry->sk,
+ sock_tag_entry->tag,
+ uid
+ );
len = snprintf(outp, char_count,
"sock=%p tag=0x%llx (uid=%u)\n",
sock_tag_entry->sk, sock_tag_entry->tag, uid);
@@ -1315,10 +1328,9 @@ static int ctrl_cmd_delete(const char *input)
struct tag_stat *ts_entry;
struct tag_counter_set *tcs_entry;
- CT_DEBUG("qtaguid: ctrl_delete(%s): entered\n", input);
argc = sscanf(input, "%c %llu %u", &cmd, &acct_tag, &uid);
CT_DEBUG("qtaguid: ctrl_delete(%s): argc=%d cmd=%c "
- "acct_tag=0x%llx uid=%u\n", input, argc, cmd,
+ "user_tag=0x%llx uid=%u\n", input, argc, cmd,
acct_tag, uid);
if (argc < 2) {
res = -EINVAL;
@@ -1332,8 +1344,9 @@ static int ctrl_cmd_delete(const char *input)
if (argc < 3) {
uid = current_fsuid();
} else if (!can_impersonate_uid(uid)) {
- pr_info("qtaguid: ctrl_delete(%s): insuficient priv\n",
- input);
+ pr_info("qtaguid: ctrl_delete(%s): "
+ "insufficient priv from pid=%u uid=%u\n",
+ input, current->pid, current_fsuid());
res = -EPERM;
goto err;
}
@@ -1342,7 +1355,7 @@ static int ctrl_cmd_delete(const char *input)
spin_lock_bh(&sock_tag_list_lock);
node = rb_first(&sock_tag_tree);
while (node) {
- st_entry = rb_entry(node, struct sock_tag, node);
+ st_entry = rb_entry(node, struct sock_tag, sock_node);
entry_uid = get_uid_from_tag(st_entry->tag);
node = rb_next(node);
if (entry_uid != uid)
@@ -1350,11 +1363,12 @@ static int ctrl_cmd_delete(const char *input)
if (!acct_tag || st_entry->tag == tag) {
CT_DEBUG("qtaguid: ctrl_delete(): "
- "erase st: sk=%p tag=0x%llx (uid=%d)\n",
+ "erase st: sk=%p tag=0x%llx (uid=%u)\n",
st_entry->sk,
st_entry->tag,
entry_uid);
- rb_erase(&st_entry->node, &sock_tag_tree);
+ rb_erase(&st_entry->sock_node, &sock_tag_tree);
+ sockfd_put(st_entry->socket);
kfree(st_entry);
}
}
@@ -1367,7 +1381,7 @@ static int ctrl_cmd_delete(const char *input)
tcs_entry = tag_counter_set_tree_search(&tag_counter_set_tree, tag);
if (tcs_entry) {
CT_DEBUG("qtaguid: ctrl_delete(): "
- "erase tcs: tag=0x%llx (uid=%d) set=%d\n",
+ "erase tcs: tag=0x%llx (uid=%u) set=%d\n",
tcs_entry->tn.tag,
get_uid_from_tag(tcs_entry->tn.tag),
tcs_entry->active_set);
@@ -1408,7 +1422,6 @@ static int ctrl_cmd_delete(const char *input)
res = 0;
err:
- CT_DEBUG("qtaguid: ctrl_delete(%s) res=%d\n", input, res);
return res;
}
@@ -1421,7 +1434,6 @@ static int ctrl_cmd_counter_set(const char *input)
struct tag_counter_set *tcs;
int counter_set;
- CT_DEBUG("qtaguid: ctrl_counterset(%s): entered\n", input);
argc = sscanf(input, "%c %d %u", &cmd, &counter_set, &uid);
CT_DEBUG("qtaguid: ctrl_counterset(%s): argc=%d cmd=%c "
"set=%d uid=%u\n", input, argc, cmd,
@@ -1437,8 +1449,9 @@ static int ctrl_cmd_counter_set(const char *input)
goto err;
}
if (!can_manipulate_uids()) {
- pr_info("qtaguid: ctrl_counterset(%s): insufficient priv\n",
- input);
+ pr_info("qtaguid: ctrl_counterset(%s): "
+ "insufficient priv from pid=%u uid=%u\n",
+ input, current->pid, current_fsuid());
res = -EPERM;
goto err;
}
@@ -1459,7 +1472,7 @@ static int ctrl_cmd_counter_set(const char *input)
tcs->tn.tag = tag;
tag_counter_set_tree_insert(tcs, &tag_counter_set_tree);
CT_DEBUG("qtaguid: ctrl_counterset(%s): added tcs tag=0x%llx "
- "(uid=%d) set=%d\n",
+ "(uid=%u) set=%d\n",
input, tag, get_uid_from_tag(tag), counter_set);
}
tcs->active_set = counter_set;
@@ -1468,7 +1481,6 @@ static int ctrl_cmd_counter_set(const char *input)
res = 0;
err:
- CT_DEBUG("qtaguid: ctrl_counterset(%s) res=%d\n", input, res);
return res;
}
@@ -1479,6 +1491,7 @@ static int ctrl_cmd_tag(const char *input)
uid_t uid = 0;
tag_t acct_tag = 0;
struct socket *el_socket;
+ int refcnt = -1;
int res, argc;
struct sock_tag *sock_tag_entry;
@@ -1491,55 +1504,80 @@ static int ctrl_cmd_tag(const char *input)
res = -EINVAL;
goto err;
}
- el_socket = sockfd_lookup(sock_fd, &res);
+ el_socket = sockfd_lookup(sock_fd, &res); /* This locks the file */
if (!el_socket) {
pr_info("qtaguid: ctrl_tag(%s): failed to lookup"
" sock_fd=%d err=%d\n", input, sock_fd, res);
goto err;
}
+ refcnt = atomic_read(&el_socket->file->f_count);
+ CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->f_count=%d\n",
+ input, refcnt);
if (argc < 3) {
acct_tag = 0;
} else if (!valid_atag(acct_tag)) {
pr_info("qtaguid: ctrl_tag(%s): invalid tag\n", input);
res = -EINVAL;
- goto err;
- }
+ goto err_put;
+ }
+ CT_DEBUG("qtaguid: ctrl_tag(%s): "
+ "uid=%u euid=%u fsuid=%u "
+ "in_group=%d in_egroup=%d\n",
+ input, current_uid(), current_euid(), current_fsuid(),
+ in_group_p(proc_stats_readall_gid),
+ in_egroup_p(proc_stats_readall_gid));
if (argc < 4) {
uid = current_fsuid();
} else if (!can_impersonate_uid(uid)) {
- pr_info("qtaguid: ctrl_tag(%s): insuficient priv\n",
- input);
+ pr_info("qtaguid: ctrl_tag(%s): "
+ "insufficient priv from pid=%u uid=%u\n",
+ input, current->pid, current_fsuid());
res = -EPERM;
- goto err;
+ goto err_put;
}
spin_lock_bh(&sock_tag_list_lock);
sock_tag_entry = get_sock_stat_nl(el_socket->sk);
if (sock_tag_entry) {
+ /*
+ * This is a re-tagging, so release the sock_fd that was
+ * locked at the time of the 1st tagging.
+ */
+ sockfd_put(sock_tag_entry->socket);
+ refcnt--;
sock_tag_entry->tag = combine_atag_with_uid(acct_tag,
uid);
} else {
sock_tag_entry = kzalloc(sizeof(*sock_tag_entry),
GFP_ATOMIC);
if (!sock_tag_entry) {
+ pr_err("qtaguid: ctrl_tag(%s): "
+ "socket tag alloc failed\n",
+ input);
+ spin_unlock_bh(&sock_tag_list_lock);
res = -ENOMEM;
- goto err;
+ goto err_put;
}
sock_tag_entry->sk = el_socket->sk;
+ sock_tag_entry->socket = el_socket;
sock_tag_entry->tag = combine_atag_with_uid(acct_tag,
uid);
sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree);
}
spin_unlock_bh(&sock_tag_list_lock);
+ /* We keep the ref to the socket (file) until it is untagged */
+ CT_DEBUG("qtaguid: ctrl_tag(%s): done. socket->...->f_count=%d\n",
+ input,
+ el_socket ? atomic_read(&el_socket->file->f_count) : -1);
+ return 0;
- CT_DEBUG("qtaguid: tag: sock_tag_entry->sk=%p "
- "...->tag=0x%llx (uid=%u)\n",
- sock_tag_entry->sk, sock_tag_entry->tag,
- get_uid_from_tag(sock_tag_entry->tag));
- res = 0;
-
+err_put:
+ /* Release the sock_fd that was grabbed by sockfd_lookup(). */
+ sockfd_put(el_socket);
+ refcnt--;
err:
- CT_DEBUG("qtaguid: ctrl_tag(%s) res=%d\n", input, res);
+ CT_DEBUG("qtaguid: ctrl_tag(%s): done. socket->...->f_count=%d\n",
+ input, refcnt);
return res;
}
@@ -1548,10 +1586,10 @@ static int ctrl_cmd_untag(const char *input)
char cmd;
int sock_fd = 0;
struct socket *el_socket;
+ int refcnt = -1;
int res, argc;
struct sock_tag *sock_tag_entry;
- CT_DEBUG("qtaguid: ctrl_untag(%s): entered\n", input);
argc = sscanf(input, "%c %d", &cmd, &sock_fd);
CT_DEBUG("qtaguid: ctrl_untag(%s): argc=%d cmd=%c sock_fd=%d\n",
input, argc, cmd, sock_fd);
@@ -1559,28 +1597,49 @@ static int ctrl_cmd_untag(const char *input)
res = -EINVAL;
goto err;
}
- el_socket = sockfd_lookup(sock_fd, &res);
+ el_socket = sockfd_lookup(sock_fd, &res); /* This locks the file */
if (!el_socket) {
pr_info("qtaguid: ctrl_untag(%s): failed to lookup"
" sock_fd=%d err=%d\n", input, sock_fd, res);
goto err;
}
+ refcnt = atomic_read(&el_socket->file->f_count);
+ CT_DEBUG("qtaguid: ctrl_untag(%s): socket->...->f_count=%d\n",
+ input, refcnt);
spin_lock_bh(&sock_tag_list_lock);
sock_tag_entry = get_sock_stat_nl(el_socket->sk);
if (!sock_tag_entry) {
spin_unlock_bh(&sock_tag_list_lock);
res = -EINVAL;
- goto err;
+ goto err_put;
}
- /* The socket already belongs to the current process
- * so it can do whatever it wants to it. */
- rb_erase(&sock_tag_entry->node, &sock_tag_tree);
+ /*
+ * The socket already belongs to the current process
+ * so it can do whatever it wants to it.
+ */
+ rb_erase(&sock_tag_entry->sock_node, &sock_tag_tree);
+
+ /*
+ * Release the sock_fd that was grabbed at tag time,
+ * and once more for the sockfd_lookup() here.
+ */
+ sockfd_put(sock_tag_entry->socket);
spin_unlock_bh(&sock_tag_list_lock);
+ sockfd_put(el_socket);
+ refcnt -= 2;
kfree(sock_tag_entry);
+ CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%d\n",
+ input, refcnt);
- res = 0;
+ return 0;
+
+err_put:
+ /* Release the sock_fd that was grabbed by sockfd_lookup(). */
+ sockfd_put(el_socket);
+ refcnt--;
err:
- CT_DEBUG("qtaguid: ctrl_untag(%s): res=%d\n", input, res);
+ CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%d\n",
+ input, refcnt);
return res;
}
@@ -1589,7 +1648,6 @@ static int qtaguid_ctrl_parse(const char *input, int count)
char cmd;
int res;
- CT_DEBUG("qtaguid: ctrl(%s): entered\n", input);
cmd = input[0];
/* Collect params for commands */
switch (cmd) {
@@ -1667,10 +1725,12 @@ static int pp_stats_line(struct proc_print_info *ppi, int cnt_set)
tag_t tag = ppi->ts_entry->tn.tag;
uid_t stat_uid = get_uid_from_tag(tag);
if (!can_read_other_uid_stats(stat_uid)) {
- CT_DEBUG("qtaguid: insufficient priv for stat line:"
- "%s 0x%llx %u\n",
+ CT_DEBUG("qtaguid: stats line: "
+ "%s 0x%llx %u: "
+ "insufficient priv from pid=%u uid=%u\n",
ppi->iface_entry->ifname,
- get_atag_from_tag(tag), stat_uid);
+ get_atag_from_tag(tag), stat_uid,
+ current->pid, current_fsuid());
return 0;
}
cnts = &ppi->ts_entry->counters;
@@ -1748,8 +1808,11 @@ static int qtaguid_stats_proc_read(char *page, char **num_items_returned,
ppi.num_items_returned = num_items_returned;
if (unlikely(module_passive)) {
+ len = pp_stats_line(&ppi, 0);
+ /* The header should always be shorter than the buffer. */
+ WARN_ON(len >= ppi.char_count);
*eof = 1;
- return 0;
+ return len;
}
CT_DEBUG("qtaguid:proc stats page=%p *num_items_returned=%p off=%ld "