1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2024 Huawei Device Co., Ltd.
4 *
5 * Operations on the lowpower protocol
6 * Authors: yangyanjun
7 */
8 #ifdef CONFIG_LOWPOWER_PROTOCOL
9 #include <linux/types.h>
10 #include <linux/kernel.h>
11 #include <linux/proc_fs.h>
12 #include <linux/printk.h>
13 #include <linux/net_namespace.h>
14 #include <net/sock.h>
15 #include <net/ip.h>
16 #include <net/tcp.h>
17 #include <net/lowpower_protocol.h>
18
19 static atomic_t g_foreground_uid = ATOMIC_INIT(FOREGROUND_UID_INIT);
20
foreground_uid_atomic_set(uid_t val)21 static void foreground_uid_atomic_set(uid_t val)
22 {
23 atomic_set(&g_foreground_uid, val);
24 }
25
foreground_uid_atomic_read(void)26 static uid_t foreground_uid_atomic_read(void)
27 {
28 return (uid_t)atomic_read(&g_foreground_uid);
29 }
30
foreground_uid_show(struct seq_file * seq,void * v)31 static int foreground_uid_show(struct seq_file *seq, void *v)
32 {
33 uid_t uid = foreground_uid_atomic_read();
34
35 seq_printf(seq, "%u\n", uid);
36 return 0;
37 }
38
39 // echo xx > /proc/net/foreground_uid
foreground_uid_write(struct file * file,char * buf,size_t size)40 static int foreground_uid_write(struct file *file, char *buf, size_t size)
41 {
42 char *p = buf;
43 uid_t uid = simple_strtoul(p, &p, 10);
44
45 if (!p)
46 return -EINVAL;
47
48 foreground_uid_atomic_set(uid);
49 return 0;
50 }
51
52 // call this fun in net/ipv4/af_inet.c inet_init_net()
lowpower_protocol_net_init(struct net * net)53 void __net_init lowpower_protocol_net_init(struct net *net)
54 {
55 if (!proc_create_net_single_write("foreground_uid", 0644,
56 net->proc_net,
57 foreground_uid_show,
58 foreground_uid_write,
59 NULL))
60 pr_err("fail to register /proc/net/foreground_uid");
61 }
62
foreground_uid_match(struct net * net,struct sock * sk)63 static bool foreground_uid_match(struct net *net, struct sock *sk)
64 {
65 uid_t kuid;
66 uid_t foreground_uid;
67 struct sock *fullsk;
68
69 if (!net || !sk)
70 return false;
71
72 fullsk = sk_to_full_sk(sk);
73 if (!fullsk || !sk_fullsock(fullsk))
74 return false;
75
76 kuid = sock_net_uid(net, fullsk).val;
77 foreground_uid = foreground_uid_atomic_read();
78 if (kuid != foreground_uid)
79 return false;
80
81 return true;
82 }
83
84 /*
85 * ack optimization is only enable for large data receiving tasks and
86 * there is no packet loss scenario
87 */
tcp_ack_num(struct sock * sk)88 int tcp_ack_num(struct sock *sk)
89 {
90 if (!sk)
91 return 1;
92
93 if (foreground_uid_match(sock_net(sk), sk) == false)
94 return 1;
95
96 if (tcp_sk(sk)->bytes_received >= BIG_DATA_BYTES &&
97 tcp_sk(sk)->dup_ack_counter < TCP_FASTRETRANS_THRESH)
98 return TCP_ACK_NUM;
99 return 1;
100 }
101
netfilter_bypass_enable(struct net * net,struct sk_buff * skb,int (* fun)(struct net *,struct sock *,struct sk_buff *),int * ret)102 bool netfilter_bypass_enable(struct net *net, struct sk_buff *skb,
103 int (*fun)(struct net *, struct sock *, struct sk_buff *),
104 int *ret)
105 {
106 if (!net || !skb || !ip_hdr(skb) || ip_hdr(skb)->protocol != IPPROTO_TCP)
107 return false;
108
109 if (foreground_uid_match(net, skb->sk)) {
110 *ret = fun(net, NULL, skb);
111 return true;
112 }
113 return false;
114 }
115 #endif /* CONFIG_LOWPOWER_PROTOCOL */
116