Merge Mainline

This commit is contained in:
AmadeusGhost 2020-05-29 12:18:05 +08:00
commit 2a12903b64
30 changed files with 170 additions and 3450 deletions

View File

@ -6,81 +6,82 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=gq-client
PKG_NAME:=GoQuiet
PKG_VERSION:=1.2.2
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/cbeuw/GoQuiet.git
PKG_SOURCE_VERSION:=013cdfdf72000dcd4691799c37a0cf960ab4c82f
PKG_SOURCE_SUBDIR:=$(PKG_NAME)
PKG_SOURCE:=$(PKG_SOURCE_SUBDIR)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_SOURCE_SUBDIR)
PKG_BUILD_DEPENDS:=golang/host
PKG_BUILD_PARALLEL:=1
PKG_USE_MIPS16:=0
GO_PKG:=github.com/cbeuw/GoQuiet
GO_PKG_LDFLAGS:=-s -w
include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
define Package/$(PKG_NAME)/temple
define Package/gq-client
SECTION:=net
CATEGORY:=Network
TITLE:=GoQuiet
DEPENDS:=+libpthread
TITLE:=GoQuiet Client
DEPENDS:=$(GO_ARCH_DEPENDS) +libpthread
URL:=https://github.com/cbeuw/GoQuiet
endef
define Package/$(PKG_NAME)
$(call Package/$(PKG_NAME)/temple)
SUBMENU:=Web Servers/Proxies
endef
define Package/gq-server
$(call Package/$(PKG_NAME)/temple)
SECTION:=net
CATEGORY:=Network
TITLE:=GoQuiet Server
DEPENDS:=$(GO_ARCH_DEPENDS) +libpthread
URL:=https://github.com/cbeuw/GoQuiet
SUBMENU:=Web Servers/Proxies
endef
define Package/$(PKG_NAME)/description
GoQuiet-client
define Package/gq-client/description
GoQuiet-Client
endef
define Package/gq-server/description
GoQuiet-server
GoQuiet-Server
endef
ifeq ($(ARCH),x86_64)
GOQUIET_NAME:=gq-client-linux-amd64-$(PKG_VERSION)
GOQUIETSERVER_NAME:=gq-server-linux-amd64-$(PKG_VERSION)
endif
ifeq ($(ARCH),i386)
GOQUIET_NAME:=gq-client-linux-386-$(PKG_VERSION)
GOQUIETSERVER_NAME:=gq-server-linux-386-$(PKG_VERSION)
endif
ifeq ($(ARCH),mipsel)
GOQUIET_NAME:=gq-client-linux-mips64-$(PKG_VERSION)
endif
ifeq ($(ARCH),mips)
GOQUIET_NAME:=gq-client-linux-mips-$(PKG_VERSION)
endif
ifeq ($(ARCH),arm)
GOQUIET_NAME:=gq-client-linux-arm-$(PKG_VERSION)
GOQUIETSERVER_NAME:=gq-server-linux-arm-$(PKG_VERSION)
endif
ifeq ($(ARCH),aarch64)
GOQUIET_NAME:=gq-client-linux-arm64-$(PKG_VERSION)
GOQUIETSERVER_NAME:=gq-server-linux-arm64-$(PKG_VERSION)
endif
define Build/Prepare
[ ! -f $(PKG_BUILD_DIR)/gq-client ] && wget -O $(PKG_BUILD_DIR)/gq-client https://github.com/cbeuw/GoQuiet/releases/download/v$(PKG_VERSION)/$(GOQUIET_NAME)
[ ! -f $(PKG_BUILD_DIR)/gq-server ] && wget -O $(PKG_BUILD_DIR)/gq-server https://github.com/cbeuw/GoQuiet/releases/download/v$(PKG_VERSION)/$(GOQUIETSERVER_NAME)
tar -zxf $(DL_DIR)/$(PKG_SOURCE) -C $(PKG_BUILD_DIR) --strip-components 1
endef
define Build/Configure
chmod +x $(PKG_BUILD_DIR)/gq-client && upx --ultra-brute $(PKG_BUILD_DIR)/gq-client
chmod +x $(PKG_BUILD_DIR)/gq-server && upx --ultra-brute $(PKG_BUILD_DIR)/gq-server
endef
define Build/Compile
$(eval GO_PKG_BUILD_PKG:=$(GO_PKG)/cmd/gq-client)
$(call GoPackage/Build/Configure)
$(call GoPackage/Build/Compile)
$(STAGING_DIR_HOST)/bin/upx --lzma --best $(GO_PKG_BUILD_BIN_DIR)/gq-client
$(eval GO_PKG_BUILD_PKG:=$(GO_PKG)/cmd/gq-server)
$(call GoPackage/Build/Configure)
$(call GoPackage/Build/Compile)
$(STAGING_DIR_HOST)/bin/upx --lzma --best $(GO_PKG_BUILD_BIN_DIR)/gq-server
endef
define Package/$(PKG_NAME)/install
define Package/gq-client/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/gq-client $(1)/usr/bin/
$(INSTALL_BIN) $(GO_PKG_BUILD_BIN_DIR)/gq-client $(1)/usr/bin/
endef
define Package/gq-server/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/gq-server $(1)/usr/bin/
$(INSTALL_BIN) $(GO_PKG_BUILD_BIN_DIR)/gq-server $(1)/usr/bin/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))
$(eval $(call GoBinPackage,gq-client))
$(eval $(call GoBinPackage,gq-server))
$(eval $(call BuildPackage,gq-client))
$(eval $(call BuildPackage,gq-server))

View File

@ -1,14 +1,17 @@
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=oaf
PKG_VERSION:=3.0
PKG_RELEASE:=2
PKG_RELEASE:=1
PKG_SOURCE_URL:=https://github.com/destan19/OpenAppFilter.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2020-05-26
PKG_SOURCE_VERSION:=bba08ecedaf97bd4bbb991e32b89eb81ad017da6
include $(INCLUDE_DIR)/package.mk
PKG_AUTOLOAD:=oaf
RSTRIP:=:
define KernelPackage/oaf
@ -19,13 +22,18 @@ define KernelPackage/oaf
FILES:=$(PKG_BUILD_DIR)/oaf.ko
DEPENDS:=+kmod-ipt-conntrack
KCONFIG:=
AUTOLOAD:=$(call AutoLoad,0,$(PKG_AUTOLOAD))
endef
define KernelPackage/oaf/description
open appfilter kernel module
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
tar xJf $(DL_DIR)/$(PKG_SOURCE) -C $(TMP_DIR)
$(CP) $(TMP_DIR)/$(PKG_NAME)-$(PKG_VERSION)/oaf/src/* $(PKG_BUILD_DIR)
rm -rf $(TMP_DIR)/$(PKG_NAME)-$(PKG_VERSION)
endef
MAKE_OPTS:= \
$(KERNEL_MAKE_FLAGS) \
@ -40,4 +48,3 @@ define Build/Compile
endef
$(eval $(call KernelPackage,oaf))

View File

@ -1,2 +0,0 @@
oaf-objs := app_filter.o af_utils.o regexp.o cJSON.o app_filter_config.o af_log.o af_client.o af_client_fs.o
obj-m += oaf.o

View File

@ -1,323 +0,0 @@
/*
Author:Derry
Date: 2019/11/12
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <net/tcp.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_acct.h>
#include <linux/skbuff.h>
#include <net/ip.h>
#include <linux/types.h>
#include <net/sock.h>
#include <linux/etherdevice.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/list.h>
#include "af_client.h"
#include "af_client_fs.h"
#include "af_log.h"
#include "af_utils.h"
DEFINE_RWLOCK(af_client_lock);
u32 total_client = 0;
struct list_head af_client_list_table[MAX_AF_CLIENT_HASH_SIZE];
static void
nf_client_list_init(void)
{
int i;
AF_CLIENT_LOCK_W();
for(i = 0; i < MAX_AF_CLIENT_HASH_SIZE; i ++){
INIT_LIST_HEAD(&af_client_list_table[i]);
}
AF_CLIENT_UNLOCK_W();
AF_INFO("client list init......ok\n");
}
static void
nf_client_list_clear(void)
{
int i;
af_client_info_t * p = NULL;
char mac_str[32] = {0};
AF_DEBUG("clean list\n");
AF_CLIENT_LOCK_W();
for (i = 0; i < MAX_AF_CLIENT_HASH_SIZE;i++){
while(!list_empty(&af_client_list_table[i])){
p = list_first_entry(&af_client_list_table[i], af_client_info_t, hlist);
memset(mac_str, 0x0, sizeof(mac_str));
sprintf(mac_str, MAC_FMT, MAC_ARRAY(p->mac));
AF_DEBUG("clean mac:%s\n", mac_str);
list_del(&(p->hlist));
kfree(p);
}
}
AF_CLIENT_UNLOCK_W();
}
int get_mac_hash_code(unsigned char *mac)
{
if (!mac)
return 0;
else
return mac[5] & (MAX_AF_CLIENT_HASH_SIZE - 1);
}
af_client_info_t * find_af_client(unsigned char *mac)
{
af_client_info_t *node;
unsigned int index;
index = get_mac_hash_code(mac);
list_for_each_entry(node, &af_client_list_table[index], hlist){
if (0 == memcmp(node->mac, mac, 6)){
node->update_jiffies = jiffies;
return node;
}
}
return NULL;
}
af_client_info_t *find_af_client_by_ip(unsigned int ip)
{
af_client_info_t *node;
int i;
for(i = 0; i < MAX_AF_CLIENT_HASH_SIZE; i++){
list_for_each_entry(node, &af_client_list_table[i], hlist){
if (node->ip == ip){
AF_LMT_DEBUG("match node->ip=%pI4, ip=%pI4\n", &node->ip, &ip);
return node;
}
}
}
return NULL;
}
static af_client_info_t *
nf_client_add(unsigned char *mac)
{
af_client_info_t *node;
int index = 0;
node = (af_client_info_t *)kmalloc(sizeof(af_client_info_t), GFP_ATOMIC);
if (node == NULL) {
AF_ERROR("kmalloc failed\n");
return NULL;
}
memset(node, 0, sizeof(af_client_info_t));
memcpy(node->mac, mac, MAC_ADDR_LEN);
node->create_jiffies = jiffies;
node->update_jiffies = jiffies;
index = get_mac_hash_code(mac);
AF_LMT_INFO("new client mac="MAC_FMT"\n", MAC_ARRAY(node->mac));
total_client++;
list_add(&(node->hlist), &af_client_list_table[index]);
return node;
}
void check_client_expire(void)
{
af_client_info_t *node;
int i;
AF_CLIENT_LOCK_W();
for (i = 0; i < MAX_AF_CLIENT_HASH_SIZE; i++){
list_for_each_entry(node, &af_client_list_table[i], hlist) {
AF_DEBUG("mac:"MAC_FMT" update:%lu interval:%lu\n", MAC_ARRAY(node->mac),
node->update_jiffies, (jiffies - node->update_jiffies) / HZ);
if (jiffies > (node->update_jiffies + MAX_CLIENT_ACTIVE_TIME * HZ)) {
AF_INFO("del client:"MAC_FMT"\n", MAC_ARRAY(node->mac));
list_del(&(node->hlist));
kfree(node);
AF_CLIENT_UNLOCK_W();
return;
}
}
}
AF_CLIENT_UNLOCK_W();
}
#define MAX_EXPIRED_VISIT_INFO_COUNT 10
void flush_expired_visit_info(af_client_info_t *node)
{
int i;
int count = 0;
u_int32_t cur_timep = 0;
int timeout = 0;
cur_timep = af_get_timestamp_sec();
for (i = 0; i < MAX_RECORD_APP_NUM; i++){
if (node->visit_info[i].app_id == 0){
return;
}
}
for (i = 0; i < MAX_RECORD_APP_NUM; i++){
if (count >= MAX_EXPIRED_VISIT_INFO_COUNT)
break;
if (node->visit_info[i].total_num > 3){
timeout = 180;
}
else{
timeout = 60;
}
if (cur_timep - node->visit_info[i].latest_time > timeout){
// ³¬Ê±Çå³ý¼Ç¼
memset(&node->visit_info[i], 0x0, sizeof(app_visit_info_t));
count++;
}
}
}
void af_visit_info_timer_handle(void){
af_client_info_t *node;
int i;
AF_CLIENT_LOCK_W();
for (i = 0; i < MAX_AF_CLIENT_HASH_SIZE; i++){
list_for_each_entry(node, &af_client_list_table[i], hlist) {
flush_expired_visit_info(node);
}
}
AF_CLIENT_UNLOCK_W();
}
static inline int get_packet_dir(struct net_device *in)
{
if (0 == strncmp(in->name, "br", 2)){
return PKT_DIR_UP;
}
else{
return PKT_DIR_DOWN;
}
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
static u_int32_t nfclient_hook(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state) {
#else
static u_int32_t nfclient_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *)){
#endif
struct ethhdr *ethhdr = NULL;
unsigned char smac[ETH_ALEN];
af_client_info_t *nfc = NULL;
int pkt_dir = 0;
// 4.10-->4.11 nfct-->_nfct
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
struct nf_conn *ct = (struct nf_conn *)skb->_nfct;
#else
struct nf_conn *ct = (struct nf_conn *)skb->nfct;
#endif
if (ct == NULL) {
return NF_ACCEPT;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
if(!skb->dev)
return NF_ACCEPT;
pkt_dir = get_packet_dir(skb->dev);
#else
if (!in){
AF_ERROR("in is NULL\n");
return NF_ACCEPT;
}
pkt_dir = get_packet_dir(in);
#endif
if(PKT_DIR_UP != pkt_dir)
return NF_ACCEPT;
ethhdr = eth_hdr(skb);
if (ethhdr) {
memcpy(smac, ethhdr->h_source, ETH_ALEN);
} else {
memcpy(smac, &skb->cb[40], ETH_ALEN);
}
struct iphdr *iph = NULL;
iph = ip_hdr(skb);
if (!iph) {
return NF_ACCEPT;
}
AF_CLIENT_LOCK_W();
nfc = find_af_client(smac);
if (!nfc){
if (skb->dev)
AF_DEBUG("from dev:%s [%s] %pI4--->%pI4", skb->dev->name, (iph->protocol == IPPROTO_TCP ? "TCP" : "UDP"),
&iph->saddr, &iph->daddr);
nfc = nf_client_add(smac);
}
if(nfc && nfc->ip != iph->saddr){
AF_DEBUG("update node "MAC_FMT" ip %pI4--->%pI4\n", MAC_ARRAY(nfc->mac), &nfc->ip, &iph->saddr);
nfc->ip = iph->saddr;
}
AF_CLIENT_UNLOCK_W();
return NF_ACCEPT;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
static struct nf_hook_ops af_client_ops[] = {
{
.hook = nfclient_hook,
.pf = PF_INET,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_FIRST + 1,
},
};
#else
static struct nf_hook_ops af_client_ops[] = {
{
.hook = nfclient_hook,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_FIRST + 1,
},
};
#endif
int af_client_init(void)
{
nf_client_list_init();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
nf_register_net_hooks(&init_net, af_client_ops, ARRAY_SIZE(af_client_ops));
#else
nf_register_hooks(af_client_ops, ARRAY_SIZE(af_client_ops));
#endif
AF_INFO("init app afclient ........ok\n");
return 0;
}
void af_client_exit(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
nf_unregister_net_hooks(&init_net, af_client_ops, ARRAY_SIZE(af_client_ops));
#else
nf_unregister_hooks(af_client_ops, ARRAY_SIZE(af_client_ops));
#endif
nf_client_list_clear();
return ;
}

View File

@ -1,69 +0,0 @@
#ifndef __AF_CLIENT_H__
#define __AF_CLIENT_H__
extern rwlock_t af_client_lock;
extern u32 nfc_debug_level;
#define MAX_AF_CLIENT_HASH_SIZE 64
#define MAC_ADDR_LEN 6
#define NF_CLIENT_TIMER_EXPIRE 1
#define MAX_CLIENT_ACTIVE_TIME 90
#define AF_CLIENT_LOCK_R() read_lock_bh(&af_client_lock);
#define AF_CLIENT_UNLOCK_R() read_unlock_bh(&af_client_lock);
#define AF_CLIENT_LOCK_W() write_lock_bh(&af_client_lock);
#define AF_CLIENT_UNLOCK_W() write_unlock_bh(&af_client_lock);
#define NIPQUAD(addr) \
((unsigned char *)&addr)[0], \
((unsigned char *)&addr)[1], \
((unsigned char *)&addr)[2], \
((unsigned char *)&addr)[3]
#define NIPQUAD_FMT "%u.%u.%u.%u"
enum NFC_PKT_DIR{
PKT_DIR_DOWN,
PKT_DIR_UP
};
#define MAX_VISIT_HISTORY_TIME 24
#define MAX_RECORD_APP_NUM 64
typedef struct app_visit_info{
unsigned int app_id;
unsigned int total_num;
unsigned int drop_num;
unsigned long latest_time;
unsigned int latest_action;
unsigned long history_time[MAX_VISIT_HISTORY_TIME];
unsigned int action[MAX_VISIT_HISTORY_TIME];
}app_visit_info_t;
typedef struct af_client_info {
struct list_head hlist;
unsigned char mac[MAC_ADDR_LEN];
unsigned int ip;
unsigned long create_jiffies;
unsigned long update_jiffies;
unsigned int visit_app_num;
app_visit_info_t visit_info[MAX_RECORD_APP_NUM];
}af_client_info_t;
#define MAC_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
int af_client_init(void);
void af_client_exit(void);
af_client_info_t * find_af_client_by_ip(unsigned int ip);
void check_client_expire(void);
void af_visit_info_timer_handle(void);
#endif

View File

@ -1,224 +0,0 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/netlink.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/version.h>
#include <net/sock.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <linux/netfilter_bridge.h>
#include <linux/version.h>
#include <linux/time.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <linux/etherdevice.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include "cJSON.h"
#include "af_log.h"
#include "af_client.h"
extern struct list_head af_client_list_table[MAX_AF_CLIENT_HASH_SIZE];
struct af_client_iter_state {
unsigned int bucket;
void *head;
};
static void *af_client_get_first(struct seq_file *seq)
{
struct af_client_iter_state *st = seq->private;
for (st->bucket = 0;st->bucket < MAX_AF_CLIENT_HASH_SIZE;st->bucket++){
if(!list_empty(&(af_client_list_table[st->bucket]))){
st->head = &(af_client_list_table[st->bucket]);
return af_client_list_table[st->bucket].next;
}
}
return NULL;
}
static void *af_client_get_next(struct seq_file *seq,
void *head)
{
struct af_client_iter_state *st = seq->private;
struct hlist_node * node = (struct hlist_node *)head;
node = node->next;
if (node != st->head){
return node;
}
else{
st->bucket++;
for (;st->bucket < MAX_AF_CLIENT_HASH_SIZE;st->bucket++) {
if(!list_empty(&(af_client_list_table[st->bucket]))){
st->head = &(af_client_list_table[st->bucket]);
return af_client_list_table[st->bucket].next;
}
}
return NULL;
}
}
static void *af_client_get_idx(struct seq_file *seq, loff_t pos)
{
void *head = af_client_get_first(seq);
if (head)
while (pos && (head = af_client_get_next(seq, head)))
pos--;
return pos ? NULL : head;
}
static void *af_client_seq_start(struct seq_file *s, loff_t *pos)
{
AF_CLIENT_LOCK_R();
if (*pos == 0){
return SEQ_START_TOKEN;
}
return af_client_get_idx(s, *pos - 1);
}
static void *af_client_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
if (v == SEQ_START_TOKEN)
return af_client_get_idx(s, 0);
return af_client_get_next(s, v);
}
static void af_client_seq_stop(struct seq_file *s, void *v)
{
seq_printf(s, "%s", "]");
AF_CLIENT_UNLOCK_R();
}
static int af_client_seq_show(struct seq_file *s, void *v)
{
unsigned char mac_str[32] = {0};
unsigned char ip_str[32] = {0};
static int index = 0;
int i;
int j;
if (v == SEQ_START_TOKEN) {
index = 0;
seq_printf(s, "%s", "[");
return 0;
}
if(index > 0)
seq_printf(s, "%s", ",");
index++;
af_client_info_t *node = (af_client_info_t *)v;
cJSON *root_obj = cJSON_CreateObject();
if(!root_obj){
AF_ERROR("create json obj failed");
return 0;
}
sprintf(mac_str, MAC_FMT, MAC_ARRAY(node->mac));
sprintf(ip_str, "%pI4", &node->ip);
cJSON_AddStringToObject(root_obj, "mac", mac_str);
cJSON_AddStringToObject(root_obj, "ip", ip_str);
cJSON_AddNumberToObject(root_obj, "app_num", node->visit_app_num);
cJSON *visit_info_array = cJSON_CreateArray();
for(i = 0; i < MAX_RECORD_APP_NUM; i++){
if(node->visit_info[i].app_id == 0)
continue;
if(node->visit_info[i].total_num < 3)
continue;
cJSON *visit_obj = cJSON_CreateObject();
cJSON_AddNumberToObject(visit_obj, "appid", node->visit_info[i].app_id);
cJSON_AddNumberToObject(visit_obj, "latest_action", node->visit_info[i].latest_action);
cJSON_AddNumberToObject(visit_obj, "latest_time", node->visit_info[i].latest_time);
cJSON_AddNumberToObject(visit_obj, "total_num", node->visit_info[i].total_num);
cJSON_AddNumberToObject(visit_obj, "drop_num", node->visit_info[i].drop_num);
cJSON *history_array = cJSON_CreateArray();
for(j = 0; j < MAX_VISIT_HISTORY_TIME; j++){
if(node->visit_info[i].history_time[j] <= 0)
continue;
cJSON *history_obj = cJSON_CreateObject();
cJSON_AddNumberToObject(visit_obj, "action", node->visit_info[i].history_time[j]);
cJSON_AddNumberToObject(visit_obj, "time", node->visit_info[i].action[j]);
cJSON_AddItemToArray(history_array, history_obj);
}
cJSON_AddItemToObject(visit_obj, "history_info", history_array);
cJSON_AddItemToArray(visit_info_array, visit_obj);
}
cJSON_AddItemToObject(root_obj, "visit_info", visit_info_array);
char *out = cJSON_Print(root_obj);
if(!out)
return 0;
cJSON_Minify(out);
seq_printf(s, "%s", out);
kfree(out);
return 0;
}
static const struct seq_operations nf_client_seq_ops = {
.start = af_client_seq_start,
.next = af_client_seq_next,
.stop = af_client_seq_stop,
.show = af_client_seq_show
};
static int af_client_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
struct af_client_iter_state *iter;
int err;
iter = kzalloc(sizeof(*iter), GFP_KERNEL);
if (!iter)
return -ENOMEM;
err = seq_open(file, &nf_client_seq_ops);
if (err) {
kfree(iter);
return err;
}
seq = file->private_data;
seq->private = iter;
return 0;
}
static const struct file_operations af_client_fops = {
.owner = THIS_MODULE,
.open = af_client_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
#define AF_CLIENT_PROC_STR "af_client"
int init_af_client_procfs(void)
{
struct proc_dir_entry *pde;
struct net *net = &init_net;
pde = proc_create(AF_CLIENT_PROC_STR, 0440, net->proc_net, &af_client_fops);
if (!pde) {
AF_ERROR("nf_client proc file created error\n");
return -1;
}
return 0;
}
void finit_af_client_procfs(void)
{
struct net *net = &init_net;
remove_proc_entry(AF_CLIENT_PROC_STR, net->proc_net);
}

View File

@ -1,7 +0,0 @@
#ifndef __AF_CLIENT_FS_H__
#define __AF_CLIENT_FS_H__
int init_af_client_procfs(void);
void finit_af_client_procfs(void);
#endif

View File

@ -1,79 +0,0 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/version.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <linux/sysctl.h>
#include "af_log.h"
int af_log_lvl = 1;
int af_test_mode = 0;
// todo: rename af_log.c
int g_oaf_enable __read_mostly = 0;
/*
cat /proc/sys/oaf/debug
*/
static struct ctl_table oaf_table[] = {
{
.procname = "debug",
.data = &af_log_lvl,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "test_mode",
.data = &af_test_mode,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
.procname = "enable",
.data = &g_oaf_enable,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = proc_dointvec,
},
{
}
};
static struct ctl_table oaf_root_table[] = {
{
.procname = "oaf",
.mode = 0555,
.child = oaf_table,
},
{}
};
static struct ctl_table_header *oaf_table_header;
static int af_init_log_sysctl(void)
{
struct ctl_table_header *hdr;
oaf_table_header = register_sysctl_table(oaf_root_table);
if (oaf_table_header == NULL){
printk("init log sysctl...failed\n");
return -ENOMEM;
}
printk("init oaf sysctl...ok\n");
return 0;
}
static int af_fini_log_sysctl(void)
{
if (oaf_table_header)
unregister_sysctl_table(oaf_table_header);
return 0;
}
int af_log_init(void){
af_init_log_sysctl();
}
int af_log_exit(void){
af_fini_log_sysctl();
}

View File

@ -1,32 +0,0 @@
#ifndef __AF_DEBUG_H__
#define __AF_DEBUG_H__
extern int af_log_lvl;
extern int af_test_mode;
#define LOG(level, fmt, ...) do { \
if ((level) <= af_log_lvl) { \
printk(fmt, ##__VA_ARGS__); \
} \
} while (0)
#define LLOG(level, fmt, ...) do { \
if ((level) <= af_log_lvl) { \
pr_info_ratelimited(fmt, ##__VA_ARGS__); \
} \
} while (0)
#define AF_ERROR(...) LOG(0, ##__VA_ARGS__)
#define AF_WARN(...) LOG(1, ##__VA_ARGS__)
#define AF_INFO(...) LOG(2, ##__VA_ARGS__)
#define AF_DEBUG(...) LOG(3, ##__VA_ARGS__)
#define AF_LMT_ERROR(...) LLOG(0, ##__VA_ARGS__)
#define AF_LMT_WARN(...) LLOG(1, ##__VA_ARGS__)
#define AF_LMT_INFO(...) LLOG(2, ##__VA_ARGS__)
#define AF_LMT_DEBUG(...) LLOG(3, ##__VA_ARGS__)
#define TEST_MODE() (af_test_mode)
int af_log_init(void);
int af_log_exit(void);
#endif

View File

@ -1,309 +0,0 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/version.h>
#include "af_utils.h"
u_int32_t af_get_timestamp_sec(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0)
struct timespec64 ts;
ktime_get_ts64(&ts);
return (u_int32_t)ts.tv_sec;
#else
struct timespec ts;
ts = current_kernel_time();
return ts.tv_sec;
#endif
}
int check_local_network_ip(unsigned int ip)
{
if ((ip & 0xffff0000) == 0xc0a80000)
return 1;
else if ((ip & 0xfff00000) == 0xac100000)
return 1;
else if ((ip & 0xff000000) == 0x0a000000)
return 1;
else
return 0;
}
void dump_str(char *name, unsigned char *p, int len)
{
#define MAX_DUMP_STR_LEN 64
char buf[MAX_DUMP_STR_LEN] = {0};
int i;
if (len > MAX_DUMP_STR_LEN) {
len = MAX_DUMP_STR_LEN - 1;
}
printk("%s: ",name);
strncpy(buf, p, len);
printk("[%s]\n", buf);
}
void dump_hex(char *name, unsigned char *p, int len)
{
#define MAX_DUMP_STR_LEN 64
int i;
if (len > MAX_DUMP_STR_LEN) {
len = MAX_DUMP_STR_LEN - 1;
}
printk("%s: ",name);
for (i = 0; i < len; i++) {
if (i % 16 == 0)
printk("\n");
printk("%02X ",*(p + i));
}
printk("\n");
}
#ifndef va_arg
typedef signed int acpi_native_int;
#ifndef _VALIST
#define _VALIST
typedef char *va_list;
#endif
#define _AUPBND (sizeof (acpi_native_int) - 1)
#define _ADNBND (sizeof (acpi_native_int) - 1)
#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap) (void) 0
#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
#endif
#ifndef TOLOWER
#define TOLOWER(x) ((x) | 0x20)
#endif
static long long k_simple_strtoll(const char *cp, char **endp, unsigned int base)
{
if (*cp == '-')
return -simple_strtoull(cp + 1, endp, base);
return simple_strtoull(cp, endp, base);
}
static int skip_atoi(const char **s)
{
int i=0;
while (isdigit(**s))
i = i*10 + *((*s)++) - '0';
return i;
}
char *skip_spaces(const char *str)
{
while (isspace(*str) && ((unsigned char )*str != 0xa0))
++str;
return (char *)str;
}
static int k_vsscanf(const char *buf, const char *fmt, va_list args)
{
const char *str = buf;
char *next;
char digit;
int num = 0;
u8 qualifier;
u8 base;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
int field_width;
#else
s16 field_width;
#endif
bool is_sign;
while (*fmt && *str) {
if (isspace(*fmt)) {
fmt = skip_spaces(++fmt);
str = skip_spaces(str);
}
if (*fmt != '%' && *fmt) {
if (*fmt++ != *str++)
break;
continue;
}
if (!*fmt)
break;
++fmt;
if (*fmt == '*') {
while (!isspace(*fmt) && *fmt != '%' && *fmt)
fmt++;
while (!isspace(*str) && *str)
str++;
continue;
}
field_width = -1;
if (isdigit(*fmt))
field_width = skip_atoi(&fmt);
qualifier = -1;
if (*fmt == 'h' || TOLOWER(*fmt) == 'l' ||
TOLOWER(*fmt) == 'z') {
qualifier = *fmt++;
if (unlikely(qualifier == *fmt)) {
if (qualifier == 'h') {
qualifier = 'H';
fmt++;
} else if (qualifier == 'l') {
qualifier = 'L';
fmt++;
}
}
}
if (!*fmt || !*str)
break;
base = 10;
is_sign = 0;
switch (*fmt++) {
case 'c':
{
char *s = (char *)va_arg(args, char*);
if (field_width == -1)
field_width = 1;
do {
*s++ = *str++;
} while (--field_width > 0 && *str);
num++;
}
continue;
case 's':
{
char *s = (char *)va_arg(args, char *);
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22)
if(field_width == -1)
field_width = INT_MAX;
#else
if (field_width == -1)
field_width = SHRT_MAX;
#endif
str = skip_spaces(str);
while (*str && (!isspace(*str) || ((unsigned char )*str == 0xA0) )&& field_width--)
*s++ = *str++;
*s = '\0';
num++;
}
continue;
case 'n':
{
int *i = (int *)va_arg(args, int*);
*i = str - buf;
}
continue;
case 'o':
base = 8;
break;
case 'x':
case 'X':
base = 16;
break;
case 'i':
base = 0;
case 'd':
is_sign = 1;
case 'u':
break;
case '%':
if (*str++ != '%')
return num;
continue;
default:
return num;
}
str = skip_spaces(str);
digit = *str;
if (is_sign && digit == '-')
digit = *(str + 1);
if (!digit
|| (base == 16 && !isxdigit(digit))
|| (base == 10 && !isdigit(digit))
|| (base == 8 && (!isdigit(digit) || digit > '7'))
|| (base == 0 && !isdigit(digit)))
break;
switch (qualifier) {
case 'H':
if (is_sign) {
signed char *s = (signed char *)va_arg(args, signed char *);
*s = (signed char)simple_strtol(str, &next, base);
} else {
unsigned char *s = (unsigned char *)va_arg(args, unsigned char *);
*s = (unsigned char)simple_strtoul(str, &next, base);
}
break;
case 'h':
if (is_sign) {
short *s = (short *)va_arg(args, short *);
*s = (short)simple_strtol(str, &next, base);
} else {
unsigned short *s = (unsigned short *)va_arg(args, unsigned short *);
*s = (unsigned short)simple_strtoul(str, &next, base);
}
break;
case 'l':
if (is_sign) {
long *l = (long *)va_arg(args, long *);
*l = simple_strtol(str, &next, base);
} else {
unsigned long *l = (unsigned long *)va_arg(args, unsigned long *);
*l = simple_strtoul(str, &next, base);
}
break;
case 'L':
if (is_sign) {
long long *l = (long long *)va_arg(args, long long *);
*l = k_simple_strtoll(str, &next, base);
} else {
unsigned long long *l = (unsigned long long *)va_arg(args, unsigned long long *);
*l = simple_strtoull(str, &next, base);
}
break;
case 'Z':
case 'z':
{
size_t *s = (size_t *)va_arg(args, size_t *);
*s = (size_t)simple_strtoul(str, &next, base);
}
break;
default:
if (is_sign) {
int *i = (int *)va_arg(args, int *);
*i = (int)simple_strtol(str, &next, base);
} else {
unsigned int *i = (unsigned int *)va_arg(args, unsigned int*);
*i = (unsigned int)simple_strtoul(str, &next, base);
}
break;
}
num++;
if (!next)
break;
str = next;
}
if (*fmt == '%' && *(fmt + 1) == 'n') {
int *p = (int *)va_arg(args, int *);
*p = str - buf;
}
return num;
}
int k_sscanf(const char *buf, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = k_vsscanf(buf, fmt, args);
va_end(args);
return i;
}

View File

@ -1,14 +0,0 @@
#ifndef AF_UTILS_H
#define AF_UTILS_H
u_int32_t af_get_timestamp_sec(void);
int check_local_network_ip(unsigned int ip);
void dump_str(char *name, unsigned char *p, int len);
void dump_hex(char *name, unsigned char *p, int len);
int k_sscanf(const char *buf, const char *fmt, ...);
#endif

View File

@ -1,983 +0,0 @@
/*
author: destan19@126.com
: OpenWrt
date:2019/1/10
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <net/tcp.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_acct.h>
#include <linux/skbuff.h>
#include <net/ip.h>
#include <linux/types.h>
#include <net/sock.h>
#include <linux/etherdevice.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include "app_filter.h"
#include "af_utils.h"
#include "af_log.h"
#include "af_client.h"
#include "af_client_fs.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("destan19@126.com");
MODULE_DESCRIPTION("app filter module");
MODULE_VERSION("3.0.1");
struct list_head af_feature_head = LIST_HEAD_INIT(af_feature_head);
DEFINE_RWLOCK(af_feature_lock);
#define feature_list_read_lock() read_lock_bh(&af_feature_lock);
#define feature_list_read_unlock() read_unlock_bh(&af_feature_lock);
#define feature_list_write_lock() write_lock_bh(&af_feature_lock);
#define feature_list_write_unlock() write_unlock_bh(&af_feature_lock);
#if 0
static void show_feature_list(void)
{
af_feature_node_t *n,*node;
unsigned int count = 0;
feature_list_read_lock();
if(!list_empty(&af_feature_head)) { // handle qos
list_for_each_entry_safe(node, n, &af_feature_head, head) {
count ++;
printk("[%d] id=%d appname:%s, dport:%d, host:%s, request:%s\n",
count,
node->app_id, node->app_name,
node->dport,node->host_url, node->request_url);
int i;
for (i = 0;i < node->pos_num;i++){
printk("(%d:%x)-->",
node->pos_info[i].pos,
node->pos_info[i].value);
}
printk("\n----------------------------------------\n\n\n");
}
}
feature_list_read_unlock();
}
static af_feature_node_t* af_find_feature(char *app_id)
{
af_feature_node_t *node;
feature_list_read_lock();
if (!list_empty(&af_feature_head)) {
list_for_each_entry(node, &af_feature_head, head) {
if (node->app_id == app_id){
feature_list_read_unlock();
return node;
}
}
}
feature_list_read_unlock();
return NULL;
}
#endif
int __add_app_feature(int appid,
char *name,
int proto,
int src_port,
int dst_port,
char *host_url,
char *request_url,
char *dict)
{
af_feature_node_t *node = NULL;
node = kzalloc(sizeof(af_feature_node_t), GFP_KERNEL);
if (node == NULL) {
printk("malloc feature memory error\n");
return -1;
}
else {
node->app_id = appid;
strcpy(node->app_name, name);
node->proto = proto;
node->dport = dst_port;
node->sport = src_port;
strcpy(node->host_url, host_url);
strcpy(node->request_url, request_url);
// 00:0a-01:11
char *p = dict;
char *begin = dict;
char pos[32] = {0};
int index = 0;
int value = 0;
while (*p++) {
if (*p == '|'){
memset(pos, 0x0, sizeof(pos));
strncpy(pos, begin, p - begin);
k_sscanf(pos, "%d:%x",&index, &value);
begin = p + 1;
node->pos_info[node->pos_num].pos = index;
node->pos_info[node->pos_num].value = value;
node->pos_num++;
}
}
if (begin != dict) {
strncpy(pos, begin, p - begin);
k_sscanf(pos, "%d:%x",&index, &value);
node->pos_info[node->pos_num].pos = index;
node->pos_info[node->pos_num].value = value;
node->pos_num++;
}
feature_list_write_lock();
list_add(&(node->head), &af_feature_head);
feature_list_write_unlock();
}
return 0;
}
//[tcp;;443;baidu.com;;]
int add_app_feature(int appid, char *name, char *feature)
{
char proto_str[16] = {0};
char src_port_str[16] = {0};
char dst_port_str[16] = {0};
char host_url[32] = {0};
char request_url[128] = {0};
char dict[128] = {0};
int proto = IPPROTO_TCP;
if (!name || !feature) {
AF_ERROR("error, name or feature is null\n");
return -1;
}
// tcp;8000;www.sina.com;0:get_name;00:0a-01:11
char *p = feature;
char *begin = feature;
int param_num = 0;
while(*p++) {
if (*p != ';')
continue;
switch(param_num){
case AF_PROTO_PARAM_INDEX:
strncpy(proto_str, begin, p - begin);
break;
case AF_SRC_PORT_PARAM_INDEX:
strncpy(src_port_str, begin, p - begin);
break;
case AF_DST_PORT_PARAM_INDEX:
strncpy(dst_port_str, begin, p - begin);
break;
case AF_HOST_URL_PARAM_INDEX:
strncpy(host_url, begin, p - begin);
break;
case AF_REQUEST_URL_PARAM_INDEX:
strncpy(request_url, begin, p - begin);
break;
}
param_num ++;
begin = p + 1;
}
if (AF_DICT_PARAM_INDEX != param_num && strlen(feature) > MIN_FEATURE_STR_LEN) {
AF_ERROR("22 invalid feature:%s\n", feature);
return -1;
}
strncpy(dict, begin, p - begin);
if (0 == strcmp(proto_str, "tcp"))
proto = IPPROTO_TCP;
else if (0 == strcmp(proto_str, "udp"))
proto = IPPROTO_UDP;
else {
AF_DEBUG("proto %s is not support\n", proto_str);
return -1;
}
int dst_port = 0;
int src_port = 0;
sscanf(src_port_str, "%d", &src_port);
sscanf(dst_port_str, "%d", &dst_port);
__add_app_feature(appid,
name,
proto,
src_port,
dst_port,
host_url,
request_url,
dict);
return 0;
}
void af_init_feature(char *feature_str)
{
int app_id;
char app_name[128] = {0};
char feature_buf[MAX_FEATURE_LINE_LEN] = {0};
if (strstr(feature_str,"#"))
return;
k_sscanf(feature_str, "%d%[^:]", &app_id, app_name);
char *p = feature_str;
char *pos = NULL;
int len = 0;
while(*p++) {
if (*p == '['){
pos = p + 1;
continue;
}
if (*p == ']' && pos != NULL) {
len = p - pos;
}
}
if (pos && len)
strncpy(feature_buf, pos, len);
char feature[MAX_FEATURE_STR_LEN];;
int i;
memset(feature, 0x0, sizeof(feature));
p = feature_buf;
char *begin = feature_buf;
while(*p++){
if (*p == ',') {
memset(feature, 0x0, sizeof(feature));
strncpy((char *)feature, begin, p - begin);
add_app_feature(app_id, app_name, feature);
begin = p + 1;
}
}
if (p != begin){
memset(feature, 0x0, sizeof(feature));
strncpy((char *)feature, begin, p - begin);
add_app_feature(app_id, app_name, feature);
}
}
void load_feature_buf_from_file(char **config_buf)
{
struct inode *inode = NULL;
struct file *fp = NULL;
mm_segment_t fs;
off_t size;
fp = filp_open(AF_FEATURE_CONFIG_FILE, O_RDONLY, 0);
if(IS_ERR(fp)) {
printk("open feature file failed\n");
return;
}
inode = fp->f_inode;
size = inode->i_size;
AF_INFO("feature file size: %u\n", size);
if (size == 0) {
AF_WARN("warning, file size = %u\n", size);
return;
}
*config_buf = (char *) kzalloc( sizeof(char) * size, GFP_KERNEL);
if(NULL == *config_buf ) {
AF_ERROR("alloc buf fail\n");
filp_close(fp, NULL);
return -1;
}
fs = get_fs();
set_fs(KERNEL_DS);
// 4.14rc3 vfs_read-->kernel_read
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)
kernel_read(fp, *config_buf, size, &(fp->f_pos));
#else
vfs_read(fp, *config_buf, size, &(fp->f_pos));
#endif
set_fs(fs);
filp_close(fp, NULL);
return size;
}
void load_feature_config(void)
{
AF_INFO("begin load feature config.....\n");
char *feature_buf = NULL;
load_feature_buf_from_file(&feature_buf);
if (!feature_buf) {
AF_ERROR("error, feature buf is null\n");
return;
}
char *p;
char *begin;
p = begin = feature_buf;
char line[MAX_FEATURE_LINE_LEN] = {0};
while(*p++) {
if (*p == '\n'){
if (p - begin < MIN_FEATURE_LINE_LEN || p - begin > MAX_FEATURE_LINE_LEN ) {
begin = p + 1;
continue;
}
memset(line, 0x0, sizeof(line));
strncpy(line, begin, p - begin);
af_init_feature(line);
begin = p + 1;
}
}
if (p != begin) {
if (p - begin < MIN_FEATURE_LINE_LEN || p - begin > MAX_FEATURE_LINE_LEN )
return;
memset(line, 0x0, sizeof(line));
strncpy(line, begin, p - begin);
af_init_feature(line);
begin = p + 1;
}
if (feature_buf)
kfree(feature_buf);
}
static void af_clean_feature_list(void)
{
af_feature_node_t *n,*node;
feature_list_write_lock();
while(!list_empty(&af_feature_head)) {
node = list_first_entry(&af_feature_head, af_feature_node_t, head);
list_del(&(node->head));
kfree(node);
}
feature_list_write_unlock();
}
int parse_flow_base(struct sk_buff *skb, flow_info_t *flow)
{
struct tcphdr * tcph = NULL;
struct udphdr * udph = NULL;
struct nf_conn *ct = NULL;
struct iphdr *iph = NULL;
if (!skb) {
return -1;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
ct = (struct nf_conn *)skb->_nfct;
#else
ct = (struct nf_conn *)skb->nfct;
#endif
if (!ct) {
return -1;
}
iph = ip_hdr(skb);
if (!iph) {
return -1;
}
flow->ct = ct;
flow->src = iph->saddr;
flow->dst = iph->daddr;
flow->l4_protocol = iph->protocol;
switch (iph->protocol) {
case IPPROTO_TCP:
tcph = (struct tcphdr *)(iph + 1);
flow->l4_data = skb->data + iph->ihl * 4 + tcph->doff * 4;
flow->l4_len = ntohs(iph->tot_len) - iph->ihl * 4 - tcph->doff * 4;
flow->dport = htons(tcph->dest);
flow->sport = htons(tcph->source);
return 0;
case IPPROTO_UDP:
udph = (struct udphdr *)(iph + 1);
flow->l4_data = skb->data + iph->ihl * 4 + 8;
flow->l4_len = ntohs(udph->len) - 8;
flow->dport = htons(udph->dest);
flow->sport = htons(udph->source);
return 0;
case IPPROTO_ICMP:
break;
default:
return -1;
}
return -1;
}
/*
desc: https url信息flow中
return:
-1: error
0: match
author: Derry
Date:2018/12/19
*/
int parse_https_proto(flow_info_t *flow) {
int i ;
short url_len = 0 ;
char * p = flow->l4_data;
int data_len = flow->l4_len;
if (NULL == flow) {
AF_ERROR("flow is NULL\n");
return -1;
}
if (NULL == p || data_len == 0) {
return -1;
}
if (!(p[0] == 0x16 && p[1] == 0x03 && p[2] == 0x01))
return -1;
for(i = 0; i < data_len; i++) {
if(i + HTTPS_URL_OFFSET >= data_len) {
return -1;
}
if(p[i] == 0x0 && p[i + 1] == 0x0 && p[i + 2] == 0x0 && p[i + 3] != 0x0) {
// 2 bytes
memcpy(&url_len , p + i + HTTPS_LEN_OFFSET, 2);
if(ntohs(url_len) <= 0 || ntohs(url_len) > data_len) {
continue ;
}
if(i + HTTPS_URL_OFFSET + ntohs(url_len) < data_len) {
//dump_hex("https hex", p, data_len);
flow->https.match = AF_TRUE;
flow->https.url_pos = p + i + HTTPS_URL_OFFSET;
//dump_str("https url", flow->https.url_pos, 5);
flow->https.url_len = ntohs(url_len);
return 0;
}
}
}
return -1;
}
void parse_http_proto(flow_info_t *flow)
{
if (!flow) {
AF_ERROR("flow is null\n");
return;
}
if (flow->l4_protocol != IPPROTO_TCP) {
return;
}
int i = 0;
int start = 0;
char *data = flow->l4_data;
int data_len = flow->l4_len;
if (data_len < MIN_HTTP_DATA_LEN) {
return;
}
if (flow->sport != 80 && flow->dport != 80)
return;
for (i = 0; i < data_len; i++) {
if (data[i] == 0x0d && data[i + 1] == 0x0a){
if (0 == memcmp(&data[start], "POST ", 5)) {
flow->http.match = AF_TRUE;
flow->http.method = HTTP_METHOD_POST;
flow->http.url_pos = data + start + 5;
flow->http.url_len = i - start - 5;
//dump_str("get request", flow->http.url_pos, flow->http.url_len);
}
else if(0 == memcmp(&data[start], "GET ", 4)) {
flow->http.match = AF_TRUE;
flow->http.method = HTTP_METHOD_GET;
flow->http.url_pos = data + start + 4;
flow->http.url_len = i - start - 4;
//dump_str("post request", flow->http.url_pos, flow->http.url_len);
}
else if (0 == memcmp(&data[start], "Host:", 5) ){
flow->http.host_pos = data + start + 6;
flow->http.host_len = i - start - 6;
//dump_str("host ", flow->http.host_pos, flow->http.host_len);
}
// 判断http头部结束
if (data[i + 2] == 0x0d && data[i + 3] == 0x0a){
flow->http.data_pos = data + i + 4;
flow->http.data_len = data_len - i - 4;
break;
}
// 0x0d 0x0a
start = i + 2;
}
}
}
static void dump_http_flow_info(http_proto_t *http) {
if (!http) {
AF_ERROR("http ptr is NULL\n");
return ;
}
if (!http->match)
return;
if (http->method == HTTP_METHOD_GET){
printk("Http method: "HTTP_GET_METHOD_STR"\n");
}
else if (http->method == HTTP_METHOD_POST) {
printk("Http method: "HTTP_POST_METHOD_STR"\n");
}
if (http->url_len > 0 && http->url_pos){
dump_str("Request url", http->url_pos, http->url_len);
}
if (http->host_len > 0 && http->host_pos){
dump_str("Host", http->host_pos, http->host_len);
}
printk("--------------------------------------------------------\n\n\n");
}
static void dump_https_flow_info(https_proto_t *https) {
if (!https) {
AF_ERROR("https ptr is NULL\n");
return ;
}
if (!https->match)
return;
if (https->url_len > 0 && https->url_pos){
dump_str("https server name", https->url_pos, https->url_len);
}
printk("--------------------------------------------------------\n\n\n");
}
static void dump_flow_info(flow_info_t *flow)
{
if (!flow) {
AF_ERROR("flow is null\n");
return;
}
if (flow->l4_len > 0){
AF_LMT_INFO("src="NIPQUAD_FMT",dst="NIPQUAD_FMT",sport: %d, dport: %d, data_len: %d\n",
NIPQUAD(flow->src), NIPQUAD(flow->dst), flow->sport, flow->dport, flow->l4_len);
}
if (flow->l4_protocol == IPPROTO_TCP) {
if (AF_TRUE == flow->http.match) {
printk("-------------------http protocol-------------------------\n");
printk("protocol:TCP , sport: %-8d, dport: %-8d, data_len: %-8d\n",
flow->sport, flow->dport, flow->l4_len);
dump_http_flow_info(&flow->http);
}
if (AF_TRUE == flow->https.match) {
printk("-------------------https protocol-------------------------\n");
dump_https_flow_info(&flow->https);
}
}
}
int af_match_by_pos(flow_info_t *flow, af_feature_node_t *node)
{
int i;
unsigned int pos = 0;
if (!flow || !node)
return AF_FALSE;
if (node->pos_num > 0) {
for (i = 0;i < node->pos_num; i++){
// -1
if(node->pos_info[i].pos < 0) {
pos = flow->l4_len + node->pos_info[i].pos;
}
else{
pos = node->pos_info[i].pos;
}
if (pos >= flow->l4_len){
return AF_FALSE;
}
if (flow->l4_data[pos] != node->pos_info[i].value){
return AF_FALSE;
}
}
AF_DEBUG("match by pos, appid=%d\n", node->app_id);
return AF_TRUE;
}
return AF_FALSE;
}
int af_match_by_url(flow_info_t *flow, af_feature_node_t *node)
{
char reg_url_buf[MAX_URL_MATCH_LEN] = {0};
if (!flow || !node)
return AF_FALSE;
// match host or https url
if (flow->https.match == AF_TRUE && flow->https.url_pos) {
if (flow->https.url_len >= MAX_URL_MATCH_LEN)
strncpy(reg_url_buf, flow->https.url_pos, MAX_URL_MATCH_LEN - 1);
else
strncpy(reg_url_buf, flow->https.url_pos, flow->https.url_len);
}
else if (flow->http.match == AF_TRUE && flow->http.host_pos) {
if (flow->http.host_len >= MAX_URL_MATCH_LEN)
strncpy(reg_url_buf, flow->http.host_pos, MAX_URL_MATCH_LEN - 1);
else
strncpy(reg_url_buf, flow->http.host_pos, flow->http.host_len);
}
if (strlen(reg_url_buf) > 0 && strlen(node->host_url) > 0
&& regexp_match(node->host_url, reg_url_buf)){
AF_DEBUG("match url:%s reg = %s, appid=%d\n",
reg_url_buf, node->host_url, node->app_id);
return AF_TRUE;
}
// match request url
if (flow->http.match == AF_TRUE && flow->http.url_pos) {
memset(reg_url_buf, 0x0, sizeof(reg_url_buf));
if (flow->http.url_len >= MAX_URL_MATCH_LEN)
strncpy(reg_url_buf, flow->http.url_pos, MAX_URL_MATCH_LEN - 1);
else
strncpy(reg_url_buf, flow->http.url_pos, flow->http.url_len);
if(strlen(reg_url_buf) > 0 && strlen(node->request_url)
&& regexp_match(node->request_url, reg_url_buf)){
AF_DEBUG("match request:%s reg:%s appid=%d\n",
reg_url_buf, node->request_url, node->app_id);
return AF_TRUE;
}
}
return AF_FALSE;
}
int af_match_one(flow_info_t *flow, af_feature_node_t *node)
{
int ret = AF_FALSE;
if (!flow || !node){
AF_ERROR("node or flow is NULL\n");
return AF_FALSE;
}
if (flow->l4_len == 0)
return AF_FALSE;
// 匹配端口
if (node->sport != 0 && flow->sport != node->sport ){
return AF_FALSE;
}
if (node->dport != 0 && flow->dport != node->dport) {
return AF_FALSE;
}
if (strlen(node->request_url) > 0 ||
strlen(node->host_url) > 0){
ret = af_match_by_url(flow, node);
}
else if (node->pos_num > 0){
ret = af_match_by_pos(flow, node);
}
else{
AF_DEBUG("node is empty, match sport:%d,dport:%d, appid = %d\n",
node->sport, node->dport, node->app_id);
return AF_TRUE;
}
return ret;
}
int app_filter_match(flow_info_t *flow)
{
af_feature_node_t *n,*node;
feature_list_read_lock();
if(!list_empty(&af_feature_head)) {
list_for_each_entry_safe(node, n, &af_feature_head, head) {
if(af_match_one(flow, node))
{
flow->app_id = node->app_id;
if (af_get_app_status(node->app_id)){
flow->drop = AF_TRUE;
feature_list_read_unlock();
return AF_TRUE;
}
else {
flow->drop = AF_FALSE;
feature_list_read_unlock();
return AF_FALSE;
}
}
}
}
feature_list_read_unlock();
return AF_FALSE;
}
#define APP_FILTER_DROP_BITS 0xf0000000
static int af_get_visit_index(af_client_info_t *node, int app_id){
int i;
for(i = 0; i < MAX_RECORD_APP_NUM; i++){
if(node->visit_info[i].app_id == app_id || node->visit_info[i].app_id == 0){
return i;
}
}
// default 0
return 0;
}
int __af_update_client_app_info(flow_info_t *flow, af_client_info_t *node)
{
int i;
int index = -1;
if(!node)
return -1;
if(!flow)
return -1;
AF_INFO("%s %d visit_app_num = %d\n", __func__, __LINE__, node->visit_app_num);
int found = 0;
index = af_get_visit_index(node, flow->app_id);
if(index < 0 || index >= MAX_RECORD_APP_NUM){
AF_ERROR("invalid index:%d\n\n", index);
return 0;
}
node->visit_info[index].total_num++;
if(flow->drop)
node->visit_info[index].drop_num++;
node->visit_info[index].app_id = flow->app_id;
node->visit_info[index].latest_time = af_get_timestamp_sec();
AF_DEBUG("update time = %u\n", node->visit_info[index].latest_time);
node->visit_info[index].latest_action = flow->drop;
AF_INFO("[%d] %pI4 visit %d, time=%d action=%s, %d/%d\n", index, &node->ip, flow->app_id,
node->visit_info[index].latest_time, node->visit_info[index].latest_action ? "Drop" : "Accept",
node->visit_info[index].drop_num, node->visit_info[index].total_num);
// todo: history
return 0;
}
void af_update_client_app_info(flow_info_t *flow)
{
int i;
int index = 0;
af_client_info_t *node = NULL;
if(!flow)
return;
if(flow->app_id <= 0)
return;
AF_CLIENT_LOCK_W();
node = find_af_client_by_ip(flow->src);
if(node){
__af_update_client_app_info(flow, node);
}
AF_CLIENT_UNLOCK_W();
}
/* 在netfilter框架注册的钩子 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
static u_int32_t app_filter_hook(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state) {
#else
static u_int32_t app_filter_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *)){
#endif
unsigned long long total_packets = 0;
flow_info_t flow;
// 4.10-->4.11 nfct-->_nfct
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
struct nf_conn *ct = (struct nf_conn *)skb->_nfct;
#else
struct nf_conn *ct = (struct nf_conn *)skb->nfct;
#endif
if (!g_oaf_enable){
return NF_ACCEPT;
}
if(ct == NULL) {
return NF_ACCEPT;
}
if(!nf_ct_is_confirmed(ct)){
return NF_ACCEPT;
}
#if defined(CONFIG_NF_CONNTRACK_MARK)
if(ct->mark != 0)
if(APP_FILTER_DROP_BITS == (ct->mark & APP_FILTER_DROP_BITS)){
return NF_DROP;
}
#endif
#if 0
// 3.12.74-->3.13-rc1
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
struct nf_conn_acct *acct;
acct = nf_conn_acct_find(ct);
if(!acct)
return NF_ACCEPT;
total_packets = (unsigned long long)atomic64_read(&acct->counter[IP_CT_DIR_ORIGINAL].packets)
+ (unsigned long long)atomic64_read(&acct->counter[IP_CT_DIR_REPLY].packets);
#else
struct nf_conn_counter *counter;
counter = nf_conn_acct_find(ct);
if (!counter)
return NF_ACCEPT;
total_packets = (unsigned long long)atomic64_read(&counter[IP_CT_DIR_ORIGINAL].packets)
+ (unsigned long long)atomic64_read(&counter[IP_CT_DIR_REPLY].packets);
#endif
if(total_packets > MAX_PARSE_PKT_NUM){
return NF_ACCEPT;
}
#endif
memset((char *)&flow, 0x0, sizeof(flow_info_t));
if(parse_flow_base(skb, &flow) < 0)
return NF_ACCEPT;
parse_http_proto(&flow);
parse_https_proto(&flow);
if (TEST_MODE())
dump_flow_info(&flow);
app_filter_match(&flow);
af_update_client_app_info(&flow);
if(flow.drop){
#if defined(CONFIG_NF_CONNTRACK_MARK)
ct->mark |= APP_FILTER_DROP_BITS;
#endif
AF_LMT_INFO("##drop appid = %d\n\n\n", flow.app_id);
return NF_DROP;
}
return NF_ACCEPT;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
static struct nf_hook_ops app_filter_ops[] __read_mostly = {
{
.hook = app_filter_hook,
.pf = PF_INET,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_MANGLE + 1,
},
};
#else
static struct nf_hook_ops app_filter_ops[] __read_mostly = {
{
.hook = app_filter_hook,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_MANGLE + 1,
},
};
#endif
#include "cJSON.h"
void TEST_cJSON(void)
{
cJSON * root = NULL;
char *out = NULL;
root = cJSON_CreateObject();
if (!root) {
AF_ERROR("create obj failed\n");
return;
}
cJSON_AddNumberToObject(root, "id", 123);
cJSON_AddStringToObject(root, "name", "derry");
out = cJSON_Print(root);
printk("out = %s\n", out);
cJSON_Delete(root);
kfree(out);
}
struct timer_list oaf_timer;
#define OAF_TIMER_INTERVAL 15
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
static void oaf_timer_func(struct timer_list *t)
#else
static void oaf_timer_func(unsigned long ptr)
#endif
{
// check_client_expire();
af_visit_info_timer_handle();
mod_timer(&oaf_timer, jiffies + OAF_TIMER_INTERVAL * HZ);
}
void init_oaf_timer(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
timer_setup(&oaf_timer, oaf_timer_func, 0);
#else
setup_timer(&oaf_timer, oaf_timer_func, OAF_TIMER_INTERVAL * HZ);
#endif
mod_timer(&oaf_timer, jiffies + OAF_TIMER_INTERVAL * HZ);
AF_INFO("init oaf timer...ok");
}
void fini_port_timer(void)
{
del_timer_sync(&oaf_timer);
AF_INFO("del oaf timer...ok");
}
/*
*/
static int __init app_filter_init(void)
{
AF_INFO("appfilter version:"AF_VERSION"\n");
af_log_init();
af_register_dev();
af_init_app_status();
load_feature_config();
init_af_client_procfs();
// show_feature_list();
af_client_init();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
nf_register_net_hooks(&init_net, app_filter_ops, ARRAY_SIZE(app_filter_ops));
#else
nf_register_hooks(app_filter_ops, ARRAY_SIZE(app_filter_ops));
#endif
init_oaf_timer();
AF_INFO("init app filter ........ok\n");
return 0;
}
/*
退
*/
static void app_filter_fini(void)
{
AF_INFO("app filter module exit\n");
fini_port_timer();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
nf_unregister_net_hooks(&init_net, app_filter_ops, ARRAY_SIZE(app_filter_ops));
#else
nf_unregister_hooks(app_filter_ops, ARRAY_SIZE(app_filter_ops));
#endif
af_clean_feature_list();
af_unregister_dev();
af_log_exit();
af_client_exit();
finit_af_client_procfs();
return ;
}
module_init(app_filter_init);
module_exit(app_filter_fini);

View File

@ -1,117 +0,0 @@
#ifndef APP_FILTER_H
#define APP_FILTER_H
#define AF_VERSION "3.0.1"
#define AF_FEATURE_CONFIG_FILE "/etc/appfilter/feature.cfg"
#define MAX_PARSE_PKT_NUM 16
#define MIN_HTTP_DATA_LEN 16
#define MAX_APP_NAME_LEN 64
#define MAX_FEATURE_NUM_PER_APP 16
#define MIN_FEATURE_STR_LEN 16
#define MAX_FEATURE_STR_LEN 128
#define MAX_HOST_URL_LEN 128
#define MAX_REQUEST_URL_LEN 128
#define MAX_FEATURE_BITS 16
#define MAX_POS_INFO_PER_FEATURE 16
#define MAX_FEATURE_LINE_LEN 256
#define MIN_FEATURE_LINE_LEN 16
#define MAX_URL_MATCH_LEN 64
//#define CONFIG_KERNEL_FUNC_TEST 1
#define HTTP_GET_METHOD_STR "GET"
#define HTTP_POST_METHOD_STR "POST"
#define HTTP_HEADER "HTTP"
#define NIPQUAD(addr) \
((unsigned char *)&addr)[0], \
((unsigned char *)&addr)[1], \
((unsigned char *)&addr)[2], \
((unsigned char *)&addr)[3]
#define NIPQUAD_FMT "%u.%u.%u.%u"
#define AF_TRUE 1
#define AF_FALSE 0
#define AF_APP_TYPE(a) (a) / 1000
#define AF_APP_ID(a) (a) % 1000
#define HTTPS_URL_OFFSET 9
#define HTTPS_LEN_OFFSET 7
enum AF_FEATURE_PARAM_INDEX{
AF_PROTO_PARAM_INDEX,
AF_SRC_PORT_PARAM_INDEX,
AF_DST_PORT_PARAM_INDEX,
AF_HOST_URL_PARAM_INDEX,
AF_REQUEST_URL_PARAM_INDEX,
AF_DICT_PARAM_INDEX,
};
enum e_http_method{
HTTP_METHOD_GET = 1,
HTTP_METHOD_POST,
};
typedef struct http_proto{
int match;
int method;
char *url_pos;
int url_len;
char *host_pos;
int host_len;
char *data_pos;
int data_len;
}http_proto_t;
typedef struct https_proto{
int match;
char *url_pos;
int url_len;
}https_proto_t;
typedef struct flow_info{
struct nf_conn *ct; // Á¬½Ó¸ú×ÙÖ¸Õë
u_int32_t src;
u_int32_t dst;
int l4_protocol;
u_int16_t sport;
u_int16_t dport;
unsigned char *l4_data;
int l4_len;
http_proto_t http;
https_proto_t https;
u_int32_t app_id;
u_int8_t drop;
}flow_info_t;
typedef struct af_pos_info{
int pos;
unsigned char value;
}af_pos_info_t;
typedef struct af_feature_node{
struct list_head head;
u_int32_t app_id;
char app_name[MAX_APP_NAME_LEN];
char feature_str[MAX_FEATURE_NUM_PER_APP][MAX_FEATURE_STR_LEN];
u_int32_t proto;
u_int32_t sport;
u_int32_t dport;
char host_url[MAX_HOST_URL_LEN];
char request_url[MAX_REQUEST_URL_LEN];
int pos_num;
af_pos_info_t pos_info[MAX_POS_INFO_PER_FEATURE];
}af_feature_node_t;
int af_register_dev(void);
void af_unregister_dev(void);
void af_init_app_status(void);
int af_get_app_status(int appid);
int regexp_match(char *reg, char *text);
extern int g_oaf_enable;
#endif

View File

@ -1,294 +0,0 @@
/*
author: destan19@126.com
΢ÐŹ«ÖÚºÅ: OpenWrt
date:2019/1/10
*/
#include <linux/init.h>
#include <linux/module.h>
#include <net/tcp.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_conntrack.h>
#include <linux/skbuff.h>
#include <net/ip.h>
#include <linux/types.h>
#include <net/sock.h>
#include <linux/etherdevice.h>
#include <linux/cdev.h>
#include <linux/vmalloc.h>
#include <linux/device.h>
#include "cJSON.h"
#include "app_filter.h"
#include "af_utils.h"
#include "af_log.h"
#define AF_MAX_APP_TYPE_NUM 16
#define AF_MAX_APP_NUM 256
#define AF_DEV_NAME "appfilter"
DEFINE_RWLOCK(af_rule_lock);
#define af_rule_read_lock() read_lock_bh(&af_rule_lock);
#define af_rule_read_unlock() read_unlock_bh(&af_rule_lock);
#define af_rule_write_lock() write_lock_bh(&af_rule_lock);
#define af_rule_write_unlock() write_unlock_bh(&af_rule_lock);
static struct mutex af_cdev_mutex;
struct af_config_dev {
dev_t id;
struct cdev char_dev;
struct class *c;
};
struct af_config_dev g_af_dev;
struct af_cdev_file {
size_t size;
char buf[256 << 10];
};
enum AF_CONFIG_CMD{
AF_CMD_ADD_APPID = 1,
AF_CMD_DEL_APPID,
AF_CMD_CLEAN_APPID,
};
char g_app_id_array[AF_MAX_APP_TYPE_NUM][AF_MAX_APP_NUM] = {0};
void af_show_app_status(void)
{
int i, j;
printk("#########show app status##########\n");
for (i = 0; i < AF_MAX_APP_TYPE_NUM; i++) {
for (j = 0; j < AF_MAX_APP_NUM; j++) {
af_rule_read_lock();
if (g_app_id_array[i][j] == AF_TRUE) {
printk("%d, %d\n", i, j);
}
af_rule_read_unlock();
}
}
printk("\n\n\n");
}
int af_change_app_status(cJSON * data_obj, int status)
{
int i;
int id;
int type;
if (!data_obj) {
AF_ERROR("data obj is null\n");
return -1;
}
cJSON *appid_arr = cJSON_GetObjectItem(data_obj, "apps");
if (!appid_arr){
AF_ERROR("apps obj is null\n");
return -1;
}
for (i = 0; i < cJSON_GetArraySize(appid_arr); i++) {
cJSON *appid_obj = cJSON_GetArrayItem(appid_arr, i);
if (!appid_obj){
AF_ERROR("appid obj is null\n");
return -1;
}
id = AF_APP_ID(appid_obj->valueint);
type = AF_APP_TYPE(appid_obj->valueint);
AF_DEBUG("appid:%d, type = %d, id = %d\n", appid_obj->valueint, type, id);
af_rule_write_lock();
g_app_id_array[type][id] = status;
af_rule_write_unlock();
}
return 0;
}
void af_init_app_status(void)
{
int i, j;
for (i = 0; i < AF_MAX_APP_TYPE_NUM; i++) {
for (j = 0; j < AF_MAX_APP_NUM; j++) {
af_rule_write_lock();
g_app_id_array[i][j] = AF_FALSE;
af_rule_write_unlock();
}
}
}
int af_get_app_status(int appid)
{
int status = 0;
int id = AF_APP_ID(appid);
int type = AF_APP_TYPE(appid);
af_rule_read_lock();
status = g_app_id_array[type][id];
af_rule_read_unlock();
return status;
}
/*
add:
{
"op":1,
"data"{
"apps":[]
}
}
clean
{
"op":3,
}
*/
int af_config_handle(char *config, unsigned int len)
{
cJSON * config_obj = NULL;
cJSON * cmd_obj = NULL;
cJSON * data_obj = NULL;
if (!config || len == 0) {
AF_ERROR("config or len is invalid\n");
return -1;
}
config_obj = cJSON_Parse(config);
if (!config_obj){
AF_ERROR("config_obj is NULL\n");
return -1;
}
cmd_obj = cJSON_GetObjectItem(config_obj, "op");
if (!cmd_obj){
AF_ERROR("not find op object\n");
return -1;
}
data_obj = cJSON_GetObjectItem(config_obj, "data");
switch(cmd_obj->valueint) {
case AF_CMD_ADD_APPID:
if (!data_obj)
break;
af_change_app_status(data_obj, AF_TRUE);
break;
case AF_CMD_DEL_APPID:
if (!data_obj)
break;
af_change_app_status(data_obj, AF_FALSE);
break;
case AF_CMD_CLEAN_APPID:
af_init_app_status();
break;
default:
AF_ERROR("invalid cmd %d\n", cmd_obj->valueint);
return -1;
}
af_show_app_status();
return 0;
}
static int af_cdev_open(struct inode *inode, struct file *filp)
{
struct af_cdev_file *file;
file = vzalloc(sizeof(*file));
if (!file)
return -EINVAL;
mutex_lock(&af_cdev_mutex);
filp->private_data = file;
return 0;
}
static ssize_t af_cdev_read(struct file *filp, char *buf, size_t count, loff_t *off)
{
return 0;
}
static int af_cdev_release(struct inode *inode, struct file *filp)
{
struct af_cdev_file *file = filp->private_data;
printk("config size: %d,data = %s\n", (int)file->size, file->buf);
af_config_handle(file->buf, file->size);
filp->private_data = NULL;
mutex_unlock(&af_cdev_mutex);
vfree(file);
return 0;
}
static ssize_t af_cdev_write(struct file *filp, const char *buffer, size_t count, loff_t *off)
{
struct af_cdev_file *file = filp->private_data;
int ret;
if (file->size + count > sizeof(file->buf)) {
printk("config overflow, cur_size: %d, block_size: %d, max_size: %d",
(int)file->size, (int)count, (int)sizeof(file->buf));
return -EINVAL;
}
ret = copy_from_user(file->buf + file->size, buffer, count);
if (ret != 0)
return -EINVAL;
file->size += count;
return count;
}
static struct file_operations af_cdev_ops = {
owner: THIS_MODULE,
release: af_cdev_release,
open: af_cdev_open,
write: af_cdev_write,
read: af_cdev_read,
};
int af_register_dev(void)
{
struct device *dev;
int res;
mutex_init(&af_cdev_mutex);
res = alloc_chrdev_region(&g_af_dev.id, 0, 1, AF_DEV_NAME);
if (res != 0) {
return -EINVAL;
}
cdev_init(&g_af_dev.char_dev, &af_cdev_ops);
res = cdev_add(&g_af_dev.char_dev, g_af_dev.id, 1);
if (res < 0) {
goto REGION_OUT;
}
g_af_dev.c= class_create(THIS_MODULE, AF_DEV_NAME);
if (IS_ERR_OR_NULL(g_af_dev.c)) {
goto CDEV_OUT;
}
dev = device_create(g_af_dev.c, NULL, g_af_dev.id, NULL, AF_DEV_NAME);
if (IS_ERR_OR_NULL(dev)) {
goto CLASS_OUT;
}
printk("register char dev....ok\n");
return 0;
CLASS_OUT:
class_destroy(g_af_dev.c);
CDEV_OUT:
cdev_del(&g_af_dev.char_dev);
REGION_OUT:
unregister_chrdev_region(g_af_dev.id, 1);
printk("register char dev....fail\n");
return -EINVAL;
}
void af_unregister_dev(void)
{
device_destroy(g_af_dev.c, g_af_dev.id);
class_destroy(g_af_dev.c);
cdev_del(&g_af_dev.char_dev);
unregister_chrdev_region(g_af_dev.id, 1);
printk("unregister char dev....ok\n");
}

View File

@ -1,519 +0,0 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// cJSON
// JSON parser in C.
#if 0
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
#endif
#include "cJSON.h"
#include <linux/module.h>
#include <linux/slab.h>
#if 0
#if defined(WINDOWS) || defined(__WIN32__) || defined(WIN32) || defined(_WIN32)
#define strcasecmp stricmp
#define strdup _strdup
#endif
#endif
#if 0
static void *(*cJSON_malloc)(size_t sz) = malloc;
static void *(*cJSON_realloc)(void *ptr, size_t sz) = realloc;
static void (*cJSON_free)(void *ptr) = free;
#endif
static void *cJSON_malloc(size_t sz) {
return kmalloc(sz, GFP_KERNEL);
}
static void *cJSON_realloc(void *ptr, size_t sz)
{
return krealloc(ptr, sz, GFP_KERNEL);
}
static void cJSON_free(void *ptr)
{
kfree(ptr);
}
static char* cJSON_strdup(const char* str)
{
size_t len;
char* copy;
len = strlen(str) + 1;
if (!(copy = (char*)cJSON_malloc(len))) return 0;
memcpy(copy,str,len);
return copy;
}
#if 0
void cJSON_InitHooks(cJSON_Hooks* hooks)
{
if (!hooks) { /* Reset hooks */
cJSON_malloc = malloc;
cJSON_realloc = realloc;
cJSON_free = free;
return;
}
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
cJSON_realloc= (hooks->realloc_fn)?hooks->realloc_fn:realloc;
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
}
#endif
// Internal constructor.
static cJSON *cJSON_New_Item(void)
{
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
if (node) memset(node,0,sizeof(cJSON));
return node;
}
// Delete a cJSON structure.
void cJSON_Delete(cJSON *c)
{
cJSON *next;
while (c)
{
next=c->next;
if (c->child) cJSON_Delete(c->child);
if (c->valuestring) cJSON_free(c->valuestring);
if (c->string) cJSON_free(c->string);
cJSON_free(c);
c=next;
}
}
/* Parse the input text to generate a number, and populate the result into item. */
static const char *parse_number(cJSON *item,const char *num)
{
int n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
if (*num=='-') sign=-1,num++; /* Has sign? */
if (*num=='0') num++; /* is zero */
if (*num>='1' && *num<='9') do n=(n*10)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
item->valueint=(int)n;
item->type=cJSON_Number;
return num;
}
/* Render the number nicely from the given item into a string. */
static char *print_number(cJSON *item)
{
char *str;
str=(char*)cJSON_malloc(21);
if (str)
sprintf(str,"%d",item->valueint);
return str;
}
// Parse the input text into an unescaped cstring, and populate item.
static const char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
static const char *parse_string(cJSON *item,const char *str)
{
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc;
if (*str!='\"') return 0; // not a string!
while (*ptr!='\"' && *ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes.
out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly.
if (!out) return 0;
ptr=str+1;ptr2=out;
while (*ptr!='\"' && *ptr>31)
{
if (*ptr!='\\') *ptr2++=*ptr++;
else
{
ptr++;
switch (*ptr)
{
case 'b': *ptr2++='\b'; break;
case 'f': *ptr2++='\f'; break;
case 'n': *ptr2++='\n'; break;
case 'r': *ptr2++='\r'; break;
case 't': *ptr2++='\t'; break;
case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY.
sscanf(ptr+1,"%4x",&uc); // get the unicode char.
len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len;
switch (len) {
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 1: *--ptr2 =(uc | firstByteMark[len]);
}
ptr2+=len;ptr+=4;
break;
default: *ptr2++=*ptr; break;
}
ptr++;
}
}
*ptr2=0;
if (*ptr=='\"') ptr++;
item->valuestring=out;
item->type=cJSON_String;
return ptr;
}
// Render the cstring provided to an escaped version that can be printed.
static char *print_string_ptr(const char *str)
{
const char *ptr;char *ptr2,*out;int len=0;
ptr=str;while (*ptr && ++len) {if (*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;}
out=(char*)cJSON_malloc(len+3);
ptr2=out;ptr=str;
*ptr2++='\"';
while (*ptr)
{
if (*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
else
{
*ptr2++='\\';
switch (*ptr++)
{
case '\\': *ptr2++='\\'; break;
case '\"': *ptr2++='\"'; break;
case '\b': *ptr2++='b'; break;
case '\f': *ptr2++='f'; break;
case '\n': *ptr2++='n'; break;
case '\r': *ptr2++='r'; break;
case '\t': *ptr2++='t'; break;
default: ptr2--; break; // eviscerate with prejudice.
}
}
}
*ptr2++='\"';*ptr2++=0;
return out;
}
// Invote print_string_ptr (which is useful) on an item.
static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);}
// Predeclare these prototypes.
static const char *parse_value(cJSON *item,const char *value);
static char *print_value(cJSON *item,int depth);
static const char *parse_array(cJSON *item,const char *value);
static char *print_array(cJSON *item,int depth);
static const char *parse_object(cJSON *item,const char *value);
static char *print_object(cJSON *item,int depth);
// Utility to jump whitespace and cr/lf
static const char *skip(const char *in) {while (in && *in<=32) in++; return in;}
// Parse an object - create a new root, and populate.
cJSON *cJSON_Parse(const char *value)
{
cJSON *c=cJSON_New_Item();
if (!c) return 0; /* memory fail */
if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;}
return c;
}
// Render a cJSON item/entity/structure to text.
char *cJSON_Print(cJSON *item) {return print_value(item,0);}
// Parser core - when encountering text, process appropriately.
static const char *parse_value(cJSON *item,const char *value)
{
if (!value) return 0; // Fail on null.
if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
if (*value=='\"') { return parse_string(item,value); }
if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
if (*value=='[') { return parse_array(item,value); }
if (*value=='{') { return parse_object(item,value); }
return 0; // failure.
}
// Render a value to text.
static char *print_value(cJSON *item,int depth)
{
char *out=0;
switch (item->type)
{
case cJSON_NULL: out=cJSON_strdup("null"); break;
case cJSON_False: out=cJSON_strdup("false");break;
case cJSON_True: out=cJSON_strdup("true"); break;
case cJSON_Number: out=print_number(item);break;
case cJSON_String: out=print_string(item);break;
case cJSON_Array: out=print_array(item,depth);break;
case cJSON_Object: out=print_object(item,depth);break;
}
return out;
}
// Build an array from input text.
static const char *parse_array(cJSON *item,const char *value)
{
cJSON *child;
if (*value!='[') return 0; // not an array!
item->type=cJSON_Array;
value=skip(value+1);
if (*value==']') return value+1; // empty array.
item->child=child=cJSON_New_Item();
if (!item->child) return 0; // memory fail
value=skip(parse_value(child,skip(value))); // skip any spacing, get the value.
if (!value) return 0;
while (*value==',')
{
cJSON *new_item;
if (!(new_item=cJSON_New_Item())) return 0; // memory fail
child->next=new_item;new_item->prev=child;child=new_item;
value=skip(parse_value(child,skip(value+1)));
if (!value) return 0; // memory fail
}
if (*value==']') return value+1; // end of array
return 0; // malformed.
}
// Render an array to text
static char *print_array(cJSON *item,int depth)
{
char *out,*ptr,*ret;int len=5;
cJSON *child=item->child;
out=(char*)cJSON_malloc(len);*out='[';
ptr=out+1;*ptr=0;
while (child)
{
ret=print_value(child,depth+1);
if (!ret) {cJSON_free(out);return 0;} // Check for failure!
len+=strlen(ret)+3;
out=(char*)cJSON_realloc(out,len);
ptr=out+strlen(out);
ptr+=sprintf(ptr,ret);
if (child->next) {*ptr++=',';*ptr++=' ';*ptr=0;}
child=child->next;
cJSON_free(ret);
}
*ptr++=']';*ptr++=0;
return out;
}
// Build an object from the text.
static const char *parse_object(cJSON *item,const char *value)
{
cJSON *child;
if (*value!='{') return 0; // not an object!
item->type=cJSON_Object;
value=skip(value+1);
if (*value=='}') return value+1; // empty array.
item->child=child=cJSON_New_Item();
value=skip(parse_string(child,skip(value)));
if (!value) return 0;
child->string=child->valuestring;child->valuestring=0;
if (*value!=':') return 0; // fail!
value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value.
if (!value) return 0;
while (*value==',')
{
cJSON *new_item;
if (!(new_item=cJSON_New_Item())) return 0; // memory fail
child->next=new_item;new_item->prev=child;child=new_item;
value=skip(parse_string(child,skip(value+1)));
if (!value) return 0;
child->string=child->valuestring;child->valuestring=0;
if (*value!=':') return 0; // fail!
value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value.
if (!value) return 0;
}
if (*value=='}') return value+1; // end of array
return 0; // malformed.
}
// Render an object to text.
static char *print_object(cJSON *item,int depth)
{
char *out,*ptr,*ret,*str;int len=7,i;
cJSON *child=item->child;
depth++;len+=depth;out=(char*)cJSON_malloc(len);*out='{';
ptr=out+1;*ptr++='\n';*ptr=0;
while (child)
{
str=print_string_ptr(child->string);
if (!str) {cJSON_free(out);return 0;}
ret=print_value(child,depth);
if (!ret) {cJSON_free(str);cJSON_free(out);return 0;} // Check for failure!
len+=strlen(ret)+strlen(str)+4+depth;
out=(char*)cJSON_realloc(out,len);
ptr=out+strlen(out);
for (i=0;i<depth;i++) *ptr++='\t';
ptr+=sprintf(ptr,str);
*ptr++=':';*ptr++='\t';
ptr+=sprintf(ptr,ret);
if (child->next) *ptr++=',';
*ptr++='\n';*ptr=0;
child=child->next;
cJSON_free(str);cJSON_free(ret);
}
for (i=0;i<depth-1;i++) *ptr++='\t';
*ptr++='}';*ptr++=0;
return out;
}
#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
static void skip_oneline_comment(char **input)
{
*input += static_strlen("//");
for (; (*input)[0] != '\0'; ++(*input))
{
if ((*input)[0] == '\n') {
*input += static_strlen("\n");
return;
}
}
}
static void skip_multiline_comment(char **input)
{
*input += static_strlen("/*");
for (; (*input)[0] != '\0'; ++(*input))
{
if (((*input)[0] == '*') && ((*input)[1] == '/'))
{
*input += static_strlen("*/");
return;
}
}
}
static void minify_string(char **input, char **output) {
(*output)[0] = (*input)[0];
*input += static_strlen("\"");
*output += static_strlen("\"");
for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
(*output)[0] = (*input)[0];
if ((*input)[0] == '\"') {
(*output)[0] = '\"';
*input += static_strlen("\"");
*output += static_strlen("\"");
return;
} else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
(*output)[1] = (*input)[1];
*input += static_strlen("\"");
*output += static_strlen("\"");
}
}
}
void cJSON_Minify(char *json)
{
char *into = json;
if (json == NULL)
{
return;
}
while (json[0] != '\0')
{
switch (json[0])
{
case ' ':
case '\t':
case '\r':
case '\n':
json++;
break;
case '/':
if (json[1] == '/')
{
skip_oneline_comment(&json);
}
else if (json[1] == '*')
{
skip_multiline_comment(&json);
} else {
json++;
}
break;
case '\"':
minify_string(&json, (char**)&into);
break;
default:
into[0] = json[0];
json++;
into++;
}
}
/* and null-terminate. */
*into = '\0';
}
// Get Array size/item / object item.
int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item) item--,c=c->next; return c;}
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && strcasecmp(c->string,string)) c=c->next; return c;}
// Utility for array list handling.
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
// Add item to array/object.
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
// Create basic types:
cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;}
cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();item->type=cJSON_True;return item;}
cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();item->type=cJSON_False;return item;}
cJSON *cJSON_CreateNumber(int num) {cJSON *item=cJSON_New_Item();item->type=cJSON_Number;item->valueint=(int)num;return item;}
cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();item->type=cJSON_String;item->valuestring=cJSON_strdup(string);return item;}
cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();item->type=cJSON_Array;return item;}
cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();item->type=cJSON_Object;return item;}
// Create Arrays:
cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}

View File

@ -1,94 +0,0 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON__h
#define cJSON__h
#include <linux/slab.h>
// cJSON Types:
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
// The cJSON structure:
typedef struct cJSON {
struct cJSON *next,*prev; // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem
struct cJSON *child; // An array or object item will have a child pointer pointing to a chain of the items in the array/object.
int type; // The type of the item, as above.
char *valuestring; // The item's string, if type==cJSON_String
int valueint; // The item's number, if type==cJSON_Number
char *string; // The item's name string, if this item is the child of, or is in the list of subitems of an object.
} cJSON;
typedef struct cJSON_Hooks {
void *(*malloc_fn)(size_t sz);
void *(*realloc_fn)(void *ptr, size_t sz);
void (*free_fn)(void *ptr);
} cJSON_Hooks;
// Supply malloc, realloc and free functions to cJSON
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished.
extern cJSON *cJSON_Parse(const char *value);
// Render a cJSON entity to text for transfer/storage. Free the char* when finished.
extern char *cJSON_Print(cJSON *item);
// Delete a cJSON entity and all subentities.
extern void cJSON_Delete(cJSON *c);
// Returns the number of items in an array (or object).
extern int cJSON_GetArraySize(cJSON *array);
// Retrieve item number "item" from array "array". Returns NULL if unsuccessful.
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
// Get item "string" from object. Case insensitive.
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
// These calls create a cJSON item of the appropriate type.
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateNumber(int num);
extern cJSON *cJSON_CreateString(const char *string);
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);
extern void cJSON_Minify(char *json);
// These utilities create an Array of count items.
extern cJSON *cJSON_CreateIntArray(int *numbers,int count);
// Append item to the specified array/object.
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
#endif

View File

@ -1,302 +0,0 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/slab.h>
//#include "regexp.h"
typedef enum{CHAR, DOT, BEGIN, END, STAR, PLUS, QUES, LIST, TYPENUM}TYPE;
typedef struct RE{
TYPE type;
int ch;
char *ccl;
int nccl;
struct RE *next;
}RE;
int match_longest = 0;
char *match_first = NULL;
static void * getmem(size_t size)
{
void *tmp;
if((tmp = kmalloc(size, GFP_ATOMIC))==NULL)
{
printk("malloc failed");
return NULL;
}
return tmp;
}
static size_t creat_list(char *str, int start, int end)
{
size_t cnt = end - start + 1;
for(; start <= end ;start++)
*str++ = start;
return (cnt > 0)?cnt:0;
}
static int in_list(char ch, RE *regexp)
{
char *str = regexp->ccl;
if(regexp->type != LIST)
return 0;
for(; *str && ch != *str; str++)
;
return (*str != '\0') ^ regexp->nccl;
}
static void regexp_free(RE *regexp)
{
RE *tmp;
for(; regexp; regexp = tmp)
{
tmp = regexp->next;
kfree(regexp);
}
}
static RE* compile(char *regexp)
{
RE head, *tail, *tmp;
char *pstr;
int err_flag = 0;
for(tail = &head; *regexp != '\0' && err_flag == 0; regexp++)
{
tmp = getmem(sizeof(RE));
switch(*regexp){
case '\\':
regexp++;
if(*regexp == 'd')
{
tmp->type = LIST;
tmp->nccl = 0;
tmp->ccl = getmem(11);
creat_list(tmp->ccl, '0','9');
tmp->ccl[11] = '\0';
}else if(*regexp == 'D')
{
tmp->type = LIST;
tmp->nccl = 1;
tmp->ccl = getmem(11);
creat_list(tmp->ccl, '0','9');
tmp->ccl[11] = '\0';
}else
{
tmp->type = CHAR;
tmp->ch = *(regexp + 1);
}
break;
case '.':
tmp->type = DOT;
break;
case '^':
tmp->type = BEGIN;
tmp->ch = '^';
break;
case '$':
tmp->type = END;
tmp->ch = '$';
break;
case '*':
tmp->type = STAR;
break;
case '+':
tmp->type = PLUS;
break;
case '?':
tmp->type = QUES;
break;
case '[':
pstr = tmp->ccl = getmem(256);
tmp->nccl = 0;
if(*++regexp == '^')
{
tmp->nccl = 1;
regexp++;
}
while(*regexp != '\0' && *regexp != ']')
{
if(*regexp != '-')
{
*pstr++ = *regexp++;
continue;
}
if(pstr == tmp->ccl || *(regexp + 1) == ']')
{
err_flag = 1;
break;
}
pstr += creat_list(pstr, *(regexp - 1) + 1, *(regexp + 1));
regexp += 2;
}
*pstr = '\0';
if(*regexp == '\0')
err_flag = 1;
tmp->type = LIST;
break;
default:
tmp->type = CHAR;
tmp->ch = *regexp;
}
tail->next = tmp;
tail = tmp;
}
tail->next = NULL;
if(err_flag)
{
regexp_free(head.next);
return NULL;
}
return head.next;
}
#define MATCH_ONE(reg, text) \
(reg->type == DOT || in_list(*text, reg) || *text == reg->ch)
#define MATCH_ONE_P(reg, text) \
(in_list(*text++, reg) || *(text - 1) == reg->ch || reg->type == DOT)
static int matchhere(RE *regexp, char *text);
static int matchstar(RE *cur, RE *regexp, char *text)
{
do{
if(matchhere(regexp, text))
return 1;
}while(*text != '\0' && MATCH_ONE_P(cur, text));
return 0;
}
static int matchstar_l(RE *cur, RE *regexp, char *text)
{
char *t;
for(t = text; *t != '\0' && MATCH_ONE(cur, t); t++)
;
do{
if(matchhere(regexp, t))
return 1;
}while(t-- > text);
return 0;
}
static int matchplus(RE *cur, RE *regexp, char *text)
{
while(*text != '\0' && MATCH_ONE_P(cur, text))
{
if(matchhere(regexp, text))
return 1;
}
return 0;
}
static int matchplus_l(RE *cur, RE *regexp, char *text)
{
char *t;
for(t = text; *t != '\0' && MATCH_ONE(cur, t); t++)
;
for(; t > text; t--)
{
if(matchhere(regexp, t))
return 1;
}
return 0;
}
static int matchques(RE *cur, RE *regexp, char *text)
{
int cnt = 1;
char *t = text;
if(*t != '\0' && cnt-- && MATCH_ONE(cur, t))
t++;
do{
if(matchhere(regexp, t))
return 1;
}while(t-- > text);
return 0;
}
static int (*matchfun[TYPENUM][2])(RE *, RE *, char *) = {
0, 0, 0, 0, 0, 0, 0, 0,
matchstar, matchstar_l,
matchplus, matchplus_l,
matchques, matchques,
};
static int matchhere(RE *regexp, char *text)
{
if(regexp == NULL)
return 1;
if(regexp->type == END && regexp->next == NULL)
return *text == '\0';
if(regexp->next && matchfun[regexp->next->type][match_longest])
return matchfun[regexp->next->type][match_longest](regexp, regexp->next->next, text);
if(*text != '\0' && MATCH_ONE(regexp, text))
return matchhere(regexp->next, text + 1);
return 0;
}
/*
* return value:
* -1 error
* 0 not match
* 1 matched
*/
int regexp_match(char *reg, char *text)
{
int ret;
RE *regexp = compile(reg);
if(regexp == NULL)
return -1;
if(regexp->type == BEGIN)
{
ret = matchhere(regexp->next, text);
goto out;
}
do{
if(ret = matchhere(regexp, text))
{
goto out;
}
}while(*text++ != '\0');
out:
regexp_free(regexp);
return ret;
}
void TEST_reg_func(char *reg, char * str, int ret)
{
if (ret != regexp_match(reg, str)) {
if (reg)
printk("reg = %s,", reg);
else
printk("reg = null");
if (str)
printk("str = %s ", str);
else
printk("str= null");
printk("error, unit test.... failed, ret = %d\n",ret);
}
else {
if (reg && str)
printk("[unit test] %s %s......ok,ret = %d\n", reg, str, ret);
}
}
void TEST_regexp(void)
{
TEST_reg_func(".*baidu.com$", "www.baidu.com", 1);
TEST_reg_func("^sina.com", "www.sina.com.cn", 0);
TEST_reg_func("^sina.com", "sina.com.cn", 1);
TEST_reg_func(".*baidu.com$", "www.baidu.com223", 0);
}

View File

@ -2,10 +2,12 @@
START=96
start() {
lsmod | grep -q oaf 2>/dev/null || modprobe oaf
gen_class.sh /etc/appfilter/feature.cfg
appfilter.sh
}
stop() {
echo "stop appfilter"
echo "stop appfilter"
rmmod oaf >/dev/null 2>&1
}

View File

@ -11,6 +11,7 @@ UNPACK_CMD=unzip -q -p $(DL_DIR)/$(PKG_SOURCE) $(PKG_SOURCE_UNZIP) | gzip -dc |
PKG_NAME:=cypress-firmware
PKG_VERSION:=v5.4.18-2020_0402
PKG_RELEASE:=2
PKG_SOURCE_UNZIP:=cypress-firmware-$(PKG_VERSION).tar.gz
PKG_SOURCE:=cypress-fmac-$(PKG_VERSION).zip
@ -68,6 +69,7 @@ $(eval $(call BuildPackage,cypress-firmware-43340-sdio))
define Package/cypress-firmware-43362-sdio
$(Package/cypress-firmware-default)
TITLE:=CYW43362 FullMac SDIO firmware
PROVIDES:=brcmfmac-firmware-43362-sdio
endef
define Package/cypress-firmware-43362-sdio/install
@ -98,6 +100,7 @@ $(eval $(call BuildPackage,cypress-firmware-4339-sdio))
define Package/cypress-firmware-43430-sdio
$(Package/cypress-firmware-default)
TITLE:=CYW43430 FullMac SDIO firmware
PROVIDES:=brcmfmac-firmware-43430-sdio
endef
define Package/cypress-firmware-43430-sdio/install
@ -116,6 +119,7 @@ $(eval $(call BuildPackage,cypress-firmware-43430-sdio))
define Package/cypress-firmware-43455-sdio
$(Package/cypress-firmware-default)
TITLE:=CYW43455 FullMac SDIO firmware
PROVIDES:=brcmfmac-firmware-43455-sdio
endef
define Package/cypress-firmware-43455-sdio/install

View File

@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=linux-firmware
PKG_VERSION:=20191215
PKG_VERSION:=20200122
PKG_RELEASE:=1
PKG_SOURCE_URL:=@KERNEL/linux/kernel/firmware
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_HASH:=c2068ff4a797c0f2c3edbb9488f82a48bca8a995855ea21310a8346195c0ae56
PKG_HASH:=a30e811b3736a72b874ac27e10662f5e5409b1cadf8aab7ba88e8f8bc8083986
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>

View File

@ -2,8 +2,8 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=bcm27xx-gpu-fw
PKG_VERSION:=2020-03-26
PKG_RELEASE:=5574077183389cd4c65077ba18b59144ed6ccd6d
PKG_VERSION:=2020-05-27
PKG_RELEASE:=62fc8c01165a80021054a430182b504f7b877c2d
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)/rpi-firmware-$(PKG_RELEASE)
@ -26,7 +26,7 @@ define Download/bootcode_bin
FILE:=$(RPI_FIRMWARE_FILE)-bootcode.bin
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=bootcode.bin
HASH:=1e3582640b97f6a1ba77b66181fe698767d205f5d4c4315f56d03b398a7e55d1
HASH:=12c6b5fdd893ff60cddbad0fa8aea0ebd5328ed2a9cd39a2a09d7ac99621d5bf
endef
$(eval $(call Download,bootcode_bin))
@ -34,7 +34,7 @@ define Download/fixup_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup.dat
HASH:=1b90af0c87d5f705b5b6d921b2b47d37f73af81c5c9fb1d683201e619a00d2df
HASH:=25d39e703af377ca6412c0ac68e6739d2ffb56634b9a7262140d26d8150fdf23
endef
$(eval $(call Download,fixup_dat))
@ -42,7 +42,7 @@ define Download/fixup_cd_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup_cd.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup_cd.dat
HASH:=134c5f3db2de3e5fd285bd4073016f074cf4151cdd1bfe3443b9a14700d48a55
HASH:=9639f81ad007561048bb3956e88da425a84cef37f307a16734cdcfcdcbd40b4c
endef
$(eval $(call Download,fixup_cd_dat))
@ -50,7 +50,7 @@ define Download/fixup_x_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup_x.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup_x.dat
HASH:=32fd8182a9a603f41acb7d542cbb15aa4e84c2768816ae48e36b68d0d4e1754c
HASH:=538c4d514b55c09670bbc7bdc092e44ff1f572c4f124a47c5b514f120dff6263
endef
$(eval $(call Download,fixup_x_dat))
@ -58,7 +58,7 @@ define Download/fixup4_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup4.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup4.dat
HASH:=605b28219ba13b73dbf57a45e995e7ea090421ad96a971c950afb34e0d3f7841
HASH:=75312421da0e036f9d451facb848bd439247e4322ee2d36bbfe2f7acc9a6d681
endef
$(eval $(call Download,fixup4_dat))
@ -66,7 +66,7 @@ define Download/fixup4cd_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup4cd.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup4cd.dat
HASH:=a3a4c600472032cd6597e774f0b7be2cebbfa918ccfd7fa1cfecdf853c5f61a9
HASH:=9639f81ad007561048bb3956e88da425a84cef37f307a16734cdcfcdcbd40b4c
endef
$(eval $(call Download,fixup4cd_dat))
@ -74,7 +74,7 @@ define Download/fixup4x_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup4x.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup4x.dat
HASH:=c196692b2cac949fdeb354364eb15da83d192d77ab698cf3fe43142401c5281c
HASH:=d3d1a044412a22a7c366d57e79433532e137e9b184ea9ea68b0eb7577e70e4f3
endef
$(eval $(call Download,fixup4x_dat))
@ -82,7 +82,7 @@ define Download/start_elf
FILE:=$(RPI_FIRMWARE_FILE)-start.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start.elf
HASH:=2364737aade5c6459a0dfd7b5d5070ab6a6139803779d3f94b579744b40731a5
HASH:=5980340e652491926f263ac89b7bc2ab513246bd3eb27103bba4780d6e8568f8
endef
$(eval $(call Download,start_elf))
@ -90,7 +90,7 @@ define Download/start_cd_elf
FILE:=$(RPI_FIRMWARE_FILE)-start_cd.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start_cd.elf
HASH:=12b98b6c5336b4f1ee1a61753bd6471ce7ce8ee2644550dc79c8e41d3ee4e719
HASH:=389a44e371802207ed56fe82a3beaf675eb51176112bde7d77546039d7085572
endef
$(eval $(call Download,start_cd_elf))
@ -98,7 +98,7 @@ define Download/start_x_elf
FILE:=$(RPI_FIRMWARE_FILE)-start_x.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start_x.elf
HASH:=d21ece84f1ac70148787578ec7549a01d5fa7453b46119ab230470f8e403c0f9
HASH:=32016c544353b285394f0006d57a785239fee0262ed1b0ff80b8028c918f0ad9
endef
$(eval $(call Download,start_x_elf))
@ -106,7 +106,7 @@ define Download/start4_elf
FILE:=$(RPI_FIRMWARE_FILE)-start4.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start4.elf
HASH:=98c4cba6bd4ee03a53b02816c645f783becd9f9899787f7b1bcb8a784eeca4c0
HASH:=ec26d746ddf76527b1702fbf7e76c7b036545cc43da81361a2887c92e4965dcc
endef
$(eval $(call Download,start4_elf))
@ -114,7 +114,7 @@ define Download/start4cd_elf
FILE:=$(RPI_FIRMWARE_FILE)-start4cd.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start4cd.elf
HASH:=b9ee5a895563b891a74ac4be3e9e11be553aa69d600a196556328db164735f8a
HASH:=ee507a448911a9d82edf632decb160d5712ab43d8d32b1225f1c406d4eb87820
endef
$(eval $(call Download,start4cd_elf))
@ -122,7 +122,7 @@ define Download/start4x_elf
FILE:=$(RPI_FIRMWARE_FILE)-start4x.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start4x.elf
HASH:=bd2741aca11ecface061fd93d6b412d4f2a777165d780f5a2924569c9417ed92
HASH:=9a32a06aadeb84649ee03a15f067fa9285791488ffe61b82f9788303a1355614
endef
$(eval $(call Download,start4x_elf))

View File

@ -10,7 +10,7 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=broadcom-wl
PKG_VERSION:=5.10.56.27.3
PKG_RELEASE:=8
PKG_RELEASE:=9
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)_$(ARCH).tar.bz2
PKG_SOURCE_URL:=http://downloads.openwrt.org/sources

View File

@ -443,7 +443,10 @@ EOF
txpower=${txpower:-$vif_txpower}
[ -z "$txpower" ] || iwconfig $device txpower ${txpower}dBm
eval "$nas_cmd"
# fd 1000 is an inherited lock file descriptor for preventing concurrent
# init script executions. Close it here to prevent the nas daemon from
# inheriting it further to avoid holding the lock indefinitely.
eval "$nas_cmd 1000>&-"
}

View File

@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-clash
PKG_VERSION:=1.6.9b
PKG_VERSION:=1.6.9c
PKG_MAINTAINER:=frainzy1477
@ -101,8 +101,6 @@ define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/lib/lua/luci
$(INSTALL_DIR) $(1)/usr/share/
$(INSTALL_DIR) $(1)/usr/share/clash
$(INSTALL_DIR) $(1)/usr/rpcd
$(INSTALL_DIR) $(1)/usr/rpcd/acl.d
$(INSTALL_DIR) $(1)/usr/share/clash/rules
$(INSTALL_DIR) $(1)/usr/share/clash/rules/g_rules
$(INSTALL_DIR) $(1)/usr/share/clash/dashboard
@ -139,8 +137,6 @@ define Package/$(PKG_NAME)/install
$(INSTALL_BIN) ./root/usr/share/clash/logstatus_check $(1)/usr/share/clash/
$(INSTALL_BIN) ./root/usr/share/clash/clash.txt $(1)/usr/share/clash/
$(INSTALL_BIN) ./root/usr/rpcd/acl.d/luci-app-clash.json $(1)/usr/rpcd/acl.d/
$(INSTALL_BIN) ./root/usr/share/clash/dashboard/index.html $(1)/usr/share/clash/dashboard/
$(INSTALL_BIN) ./root/usr/share/clash/dashboard/main.1560b07adc97ac0ac265.css $(1)/usr/share/clash/dashboard/
$(INSTALL_BIN) ./root/usr/share/clash/dashboard/img/ffac0fa1d89f15922b4594863b8b32e9.png $(1)/usr/share/clash/dashboard/img/

View File

@ -12,8 +12,6 @@ function index()
end
entry({"admin", "services", "clash"},alias("admin", "services", "clash", "overview"), _("Clash"), 5)
page.dependent = true
page.acl_depends = { "luci-app-openclash" }
entry({"admin", "services", "clash", "overview"},cbi("clash/overview"),_("Overview"), 10).leaf = true
entry({"admin", "services", "clash", "client"},cbi("clash/client"),_("Client"), 20).leaf = true

View File

@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=bcm27xx-userland
PKG_VERSION:=6fb59736b1ae80fc62cddfe3309c800f72e1c07e
PKG_VERSION:=f4bccc38f9d0a740aeb7818d33ca1fd551e325de
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/raspberrypi/userland/tar.gz/$(PKG_VERSION)?
PKG_HASH:=f81fe28c636178645fb406cc87f543efa828ca896df856536f7b1b4ab54dfe0e
PKG_HASH:=3a4ea8788809bf889da9fe61759e4f8daafab3444264c011db9c6b25237fd044
PKG_FLAGS:=nonshared
@ -51,10 +51,12 @@ define Package/bcm27xx-userland/install
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/dtmerge $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/dtparam $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/dtoverlay $(1)/usr/bin
ifneq ($(ARCH),aarch64)
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/raspistill $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/raspivid $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/raspividyuv $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/raspiyuv $(1)/usr/bin
endif
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/tvservice $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/vcgencmd $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/vcmailbox $(1)/usr/bin

View File

@ -0,0 +1,75 @@
From 39c946b5dfcc38d3b2cd16d9c96f47a8341387cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
Date: Thu, 28 May 2020 15:19:57 +0200
Subject: [PATCH] Revert "Add MMAL and MMAL_APPS to 64bit builds"
This reverts commit 7d3c6b9f4c3ddeecefdeb2b882bada74a235249b.
---
CMakeLists.txt | 18 ++++++++++--------
host_applications/linux/CMakeLists.txt | 4 ++--
interface/mmal/CMakeLists.txt | 6 ++----
3 files changed, 14 insertions(+), 14 deletions(-)
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,9 +8,13 @@ SET(PROJECT_VER_PATCH 0)
SET(PROJECT_VER "${PROJECT_VER_MAJOR}.${PROJECT_VER_MINOR}.${PROJECT_VER_PATCH}")
SET(PROJECT_APIVER "${PROJECT_VER}")
-set(BUILD_MMAL TRUE)
-set(BUILD_MMAL_APPS TRUE)
-
+if(ARM64)
+ set(BUILD_MMAL FALSE)
+ set(BUILD_MMAL_APPS FALSE)
+else()
+ set(BUILD_MMAL TRUE)
+ set(BUILD_MMAL_APPS TRUE)
+endif()
set(vmcs_root ${PROJECT_SOURCE_DIR})
get_filename_component(VIDEOCORE_ROOT . ABSOLUTE)
@@ -74,11 +78,9 @@ if(BUILD_MMAL)
endif()
# VidTex supports Android and Linux
-if(NOT ARM64)
- if(BUILD_MMAL_APPS)
- add_subdirectory(host_applications/android/apps/vidtex)
- endif(BUILD_MMAL_APPS)
-endif()
+if(BUILD_MMAL_APPS)
+add_subdirectory(host_applications/android/apps/vidtex)
+endif(BUILD_MMAL_APPS)
if(NOT ARM64)
add_subdirectory(middleware/openmaxil)
--- a/host_applications/linux/CMakeLists.txt
+++ b/host_applications/linux/CMakeLists.txt
@@ -4,9 +4,9 @@ add_subdirectory(libs/bcm_host)
add_subdirectory(apps/gencmd)
add_subdirectory(apps/tvservice)
add_subdirectory(apps/vcmailbox)
-add_subdirectory(apps/raspicam)
-add_subdirectory(libs/sm)
if(NOT ARM64)
+ add_subdirectory(apps/raspicam)
+ add_subdirectory(libs/sm)
add_subdirectory(apps/smem)
endif()
add_subdirectory(libs/debug_sym)
--- a/interface/mmal/CMakeLists.txt
+++ b/interface/mmal/CMakeLists.txt
@@ -11,10 +11,8 @@ add_subdirectory(core)
add_subdirectory(util)
add_subdirectory(vc)
add_subdirectory(components)
-if(NOT ARM64)
- add_subdirectory(openmaxil)
- add_subdirectory(client)
-endif()
+add_subdirectory(openmaxil)
+add_subdirectory(client)
target_link_libraries(mmal mmal_core mmal_util mmal_vc_client vcos mmal_components)

View File

@ -11,4 +11,4 @@ fbtest: $(OBJS)
$(CC) -o $@ $(OBJS)
clean:
rm -f rbcfg *.o
rm -f fbtest *.o

View File

@ -8,11 +8,11 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/target.mk
PKG_NAME:=ccache
PKG_VERSION:=3.7.7
PKG_VERSION:=3.7.9
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://github.com/ccache/ccache/releases/download/v$(PKG_VERSION)
PKG_HASH:=b7c1d6d6fe42f18e424de92746af863e0bc85794da3d69e44300840c478c98cd
PKG_HASH:=f893da7543bfb9172bd55e603fcbdfcd83e6def176a28689c13235695b4cf44b
include $(INCLUDE_DIR)/host-build.mk

View File

@ -1,6 +1,6 @@
--- a/src/ccache.c
+++ b/src/ccache.c
@@ -2220,6 +2220,7 @@ calculate_object_hash(struct args *args,
@@ -2227,6 +2227,7 @@ calculate_object_hash(struct args *args,
"CPLUS_INCLUDE_PATH",
"OBJC_INCLUDE_PATH",
"OBJCPLUS_INCLUDE_PATH", // clang