1/*
2	ASUS features:
3		- traffic limiter for wan interface
4
5	Copyright (C) ASUSTek. Computer Inc.
6*/
7
8#include <rc.h>
9#include <math.h>
10
11#ifdef RTCONFIG_TRAFFIC_LIMITER
12
13#define IFPATH_MAX 64
14
15static int traffic_limiter_is_first = 1;
16
17void traffic_limiter_sendSMS(const char *type, int unit)
18{
19	char phone[32], message[IFPATH_MAX];
20	char *at_cmd[] = {"modem_status.sh", "send_sms", phone, message, NULL};
21	char buf[32];
22
23	snprintf(buf, sizeof(buf), "tl%d_%s_max", unit, type);
24	snprintf(phone, sizeof(phone), "%s", nvram_safe_get("modem_sms_phone"));
25
26	if (strcmp(type, "alert") == 0)
27		snprintf(message, sizeof(message), "%s %s bytes.", nvram_safe_get("modem_sms_message1"), nvram_safe_get(buf));
28	else if (strcmp(type, "limit") == 0)
29		snprintf(message, sizeof(message), "%s %s bytes.", nvram_safe_get("modem_sms_message2"), nvram_safe_get(buf));
30
31#ifdef RTCONFIG_INTERNAL_GOBI
32	stop_lteled();
33#endif
34	_eval(at_cmd, ">/tmp/modem_action.ret", 0, NULL);
35#ifdef RTCONFIG_INTERNAL_GOBI
36	start_lteled();
37#endif
38}
39
40static double traffic_limiter_get_max(const char *type, int unit)
41{
42	char path[IFPATH_MAX];
43	char buf[32];
44
45	snprintf(path, sizeof(path), "/tmp/tl%d_%s_max", unit, type);
46	if (f_read_string(path, buf, sizeof(buf)) > 0)
47		return atof(buf);
48
49	return 0;
50}
51
52static void traffic_limiter_set_max(const char *type, int unit, double value)
53{
54	char path[IFPATH_MAX];
55	char buf[32];
56
57	snprintf(path, sizeof(path), "/tmp/tl%d_%s_max", unit, type);
58	snprintf(buf, sizeof(buf), "%.9g", value);
59
60	f_write_string(path, buf, 0, 0);
61}
62
63static void _traffic_limiter_recover_connect(char *wan_if, int unit)
64{
65	/* recover wan connection function */
66	int debug = nvram_get_int("tl_debug");
67
68	if (debug) dbg("[TRAFFIC LIMITER] %s recover connect\n", wan_if);
69
70	update_wan_state(wan_if, WAN_STATE_CONNECTED, 0);
71	//start_wan_if(unit);
72	traffic_limiter_clear_bit("limit", unit);
73}
74
75void reset_traffic_limiter_counter(int force)
76{
77	// force = 0 : check limit line
78	// force = 1 : not to check limit line
79
80	/* recover connection when changing limit line or disable limit line */
81	char tmp1[32], tmp2[32], tmp3[32];
82	char prefix[sizeof("tlXXXXXXXX_")], wan_if[sizeof("wanXXXXXXXX_")];
83	int unit;
84	double val;
85
86	/* check daul wan mode */
87	if (traffic_limiter_dualwan_check(nvram_safe_get("wans_mode")) == 0)
88		return;
89
90	for (unit = TL_UNIT_S; unit < TL_UNIT_E; ++unit) {
91		snprintf(prefix, sizeof(prefix), "tl%d_", unit);
92		snprintf(wan_if, sizeof(wan_if), "wan%d_", unit);
93		strcat_r(prefix, "limit_max", tmp1);
94		strcat_r(prefix, "alert_max", tmp2);
95		strcat_r(prefix, "limit_enable", tmp3);
96
97		if (force == 1) {
98			/* if cycle detect, not to check limit line */
99			if (!is_wan_connect(unit))
100				_traffic_limiter_recover_connect(wan_if, unit);
101		} else if (force == 0) {
102			/* if traffic limit disable limit line and wan disconnect */
103			if (nvram_get_int(tmp3) == 0 && !is_wan_connect(unit))
104				_traffic_limiter_recover_connect(wan_if, unit);
105		}
106
107		// when limit line changes
108		val = nvram_get_double(tmp1);
109		if (fabs(val - traffic_limiter_get_max("limit", unit)) > 1.0/1024) {
110			traffic_limiter_set_max("limit", unit, val);
111			_traffic_limiter_recover_connect(wan_if, unit);
112		}
113
114		// reset counter when alert line changes
115		val = nvram_get_double(tmp2);
116		if (fabs(val - traffic_limiter_get_max("alert", unit)) > 1.0/1024) {
117			traffic_limiter_set_max("alert", unit, val);
118			// clear bit
119			traffic_limiter_clear_bit("alert", unit);
120			traffic_limiter_clear_bit("count", unit);
121		}
122	}
123}
124
125static void traffic_limiter_cycle_detect(void)
126{
127	struct tm t1, t2;
128	time_t date_start = nvram_get_int("tl_date_start");
129	time_t now, new_date;
130	char buf[32];
131
132	int debug = nvram_get_int("tl_debug");
133
134	/* current timestamp */
135	time(&now);
136
137	/* transfer format into tm */
138	localtime_r(&now, &t1);
139	localtime_r(&date_start, &t2);
140
141	if (debug) dbg("t1: %d-%d-%d, %d:%d:%d\n", t1.tm_year+1900, t1.tm_mon+1, t1.tm_mday, t1.tm_hour, t1.tm_min, t1.tm_sec);
142	if (debug) dbg("t2: %d-%d-%d, %d:%d:%d\n", t2.tm_year+1900, t2.tm_mon+1, t2.tm_mday, t2.tm_hour, t2.tm_min, t2.tm_sec);
143
144	if ((t1.tm_mon == (t2.tm_mon+1)) && (t1.tm_mday == t2.tm_mday)) {
145		// step1. save database
146		hm_traffic_limiter_save();
147
148		// setp2. update tl_date_start
149		t1.tm_hour = 0;
150		t1.tm_min = 0;
151		t1.tm_sec = 0;
152		new_date = mktime(&t1);
153
154		snprintf(buf, sizeof(buf), "%ld", new_date);
155		nvram_set("tl_date_start", buf);
156		if (debug) dbg("buf=%s, %d-%d-%d, %d:%d:%d\n", buf, t1.tm_year+1900, t1.tm_mon+1, t1.tm_mday, t1.tm_hour, t1.tm_min, t1.tm_sec);
157
158		// step3. recover connection
159		reset_traffic_limiter_counter(1);
160	}
161}
162
163void traffic_limiter_limitdata_check(void)
164{
165	if (nvram_get_int("tl_enable") == 0)
166		return;
167
168	/* wanduck to upadte traffic limiter data into /jffs/tld/xxx/tmp */
169	if (traffic_limiter_is_first) {
170		/* after hardware or software reboot, save final data last time */
171		eval("traffic_limiter", "-c");
172		traffic_limiter_is_first = 0;
173	} else {
174		/* normal query and upate data */
175		eval("traffic_limiter", "-q");
176	}
177
178	/* when tl_cycle is reached, upadte timestamp and start_wan_if() */
179	traffic_limiter_cycle_detect();
180}
181
182int traffic_limiter_wanduck_check(int unit)
183{
184	/* wanduck to check which interface's function and limit are enabled */
185	int ret = 0, save = 0;
186	unsigned int val;
187
188	val = traffic_limiter_read_bit("limit");
189
190	/* primary wan */
191	if (unit == 0 && nvram_get_int("tl0_limit_enable") && (val & 0x1)) {
192		ret = 1;
193		save = 1;
194	}
195
196	/* secondary wan */
197	if (unit == 1 && nvram_get_int("tl1_limit_enable") && (val & 0x2)) {
198		ret = 1;
199		save = 1;
200	}
201
202	/* save database */
203	if (save)
204		eval("traffic_limiter", "-w");
205
206	return ret;
207}
208
209void init_traffic_limiter(void)
210{
211	traffic_limiter_is_first = 1;
212	traffic_limiter_set_max("limit", 0, nvram_get_double("tl0_limit_max"));
213	traffic_limiter_set_max("alert", 0, nvram_get_double("tl0_alert_max"));
214	traffic_limiter_set_max("limit", 1, nvram_get_double("tl1_limit_max"));
215	traffic_limiter_set_max("alert", 1, nvram_get_double("tl1_alert_max"));
216}
217#endif
218