1/*
2
3	ASUS features:
4		- traditional qos
5		- bandwidth limiter
6
7	Copyright (C) ASUSTek. Computer Inc.
8
9*/
10#include "rc.h"
11#include <arpa/inet.h>
12#include <sys/socket.h>
13
14static const char *qosfn = "/tmp/qos";
15static const char *mangle_fn = "/tmp/mangle_rules";
16#ifdef RTCONFIG_IPV6
17static const char *mangle_fn_ipv6 = "/tmp/mangle_rules_ipv6";
18#endif
19
20int etable_flag = 0;
21int manual_return = 0;
22
23// FindMask :
24// 1. sourceStr 	: replace "*'" to "0"
25// 2. matchStr 		: here is "*"
26// 3. replaceStr 	: here is "0"
27// 4. Mask 		: find rule's submask
28static int FindMask(char *sourceStr, char *matchStr, char *replaceStr, char *Mask){
29	char newStr[40];
30	int strLen;
31	int count = 0;
32
33	char *FindPos = strstr(sourceStr, matchStr);
34	if((!FindPos) || (!matchStr)) return -1;
35
36	while(FindPos != NULL){
37		count++;
38		//fprintf(stderr,"[FindMask] FindPos=%s, strLen=%d, count=%d, sourceStr=%s\n", FindPos, strLen, count, sourceStr); // tmp test
39		memset(newStr, 0, sizeof(newStr));
40		strLen = FindPos - sourceStr;
41		strncpy(newStr, sourceStr, strLen);
42		strcat(newStr, replaceStr);
43		strcat(newStr, FindPos + strlen(matchStr));
44		strcpy(sourceStr, newStr);
45
46		FindPos = strstr(sourceStr, matchStr);
47	}
48
49	switch(count){
50		case 1:
51			strcpy(Mask, "255.255.255.0");
52			break;
53		case 2:
54			strcpy(Mask, "255.255.0.0");
55			break;
56		case 3:
57			strcpy(Mask, "255.0.0.0");
58			break;
59		case 4:
60			strcpy(Mask, "0.0.0.0");
61			break;
62		default:
63			strcpy(Mask, "255.255.255.255");
64			break;
65	}
66
67	//fprintf(stderr,"[FindMask] count=%d, Mask=%s\n", count, Mask); // tmp test
68	return 0;
69}
70
71static unsigned calc(unsigned bw, unsigned pct)
72{
73	unsigned n = ((unsigned long)bw * pct) / 100;
74	return (n < 2) ? 2 : n;
75}
76
77#ifdef CONFIG_BCMWL5 // TODO: it is only for the case, eth0 as wan, vlanx as lan
78void del_EbtablesRules(void)
79{
80	/* Flush all rules in nat table of ebtable*/
81	eval("ebtables", "-t", "nat", "-F");
82	etable_flag = 0;
83}
84
85void add_EbtablesRules(void)
86{
87	if(etable_flag == 1) return;
88	char *nv, *p, *g;
89	nv = g = strdup(nvram_safe_get("wl_ifnames"));
90	if(nv){
91		while ((p = strsep(&g, " ")) != NULL){
92			//fprintf(stderr, "%s: g=%s, p=%s\n", __FUNCTION__, g, p); //tmp test
93			eval("ebtables", "-t", "nat", "-A", "PREROUTING", "-i", p, "-j", "mark", "--mark-or", "6", "--mark-target", "ACCEPT");
94			eval("ebtables", "-t", "nat", "-A", "POSTROUTING", "-o", p, "-j", "mark", "--mark-or", "6", "--mark-target", "ACCEPT");
95		}
96		free(nv);
97	}
98
99	// for MultiSSID
100	int UnitNum = 2; 	// wl0.x, wl1.x
101	int GuestNum = 3;	// wlx.0, wlx.1, wlx.2
102	char mssid_if[32];
103	char mssid_enable[32];
104	int i, j;
105	for( i = 0; i < UnitNum; i++){
106		for( j = 1; j <= GuestNum; j++ ){
107			snprintf(mssid_if, sizeof(mssid_if), "wl%d.%d", i, j);
108			snprintf(mssid_enable, sizeof(mssid_enable), "%s_bss_enabled", mssid_if);
109			//fprintf(stderr, "%s: mssid_enable=%s\n", __FUNCTION__, mssid_enable); //tmp test
110			if(!strcmp(nvram_safe_get(mssid_enable), "1")){
111				eval("ebtables", "-t", "nat", "-A", "PREROUTING", "-i", mssid_if, "-j", "mark", "--mark-or", "6", "--mark-target", "ACCEPT");
112				eval("ebtables", "-t", "nat", "-A", "POSTROUTING", "-o", mssid_if, "-j", "mark", "--mark-or", "6", "--mark-target", "ACCEPT");
113			}
114		}
115	}
116
117	etable_flag = 1;
118}
119#endif
120
121void del_iQosRules(void)
122{
123#ifdef CLS_ACT
124	eval("ip", "link", "set", "imq0", "down");
125#endif
126
127#ifdef CONFIG_BCMWL5 // TODO: it is only for the case, eth0 as wan, vlanx as lan
128	del_EbtablesRules(); // flush ebtables nat table
129#endif
130
131	/* Flush all rules in mangle table */
132	eval("iptables", "-t", "mangle", "-F");
133#ifdef RTCONFIG_IPV6
134	eval("ip6tables", "-t", "mangle", "-F");
135#endif
136}
137
138static int add_qos_rules(char *pcWANIF)
139{
140	FILE *fn;
141#ifdef RTCONFIG_IPV6
142	FILE *fn_ipv6 = NULL;
143#endif
144	char *buf;
145	char *g;
146	char *p;
147	char *desc, *addr, *port, *prio, *transferred, *proto;
148	int class_num;
149	int down_class_num=6; 	// for download class_num = 0x6 / 0x106
150	int i, inuse;
151	char q_inuse[32]; 	// for inuse
152	char dport[192], saddr_1[192], saddr_2[192], proto_1[8], proto_2[8],conn[256], end[256], end2[256];
153	int method;
154	int gum;
155	int sticky_enable;
156	const char *chain;
157	int v4v6_ok;
158
159	if((fn = fopen(mangle_fn, "w")) == NULL) return -2;
160#ifdef RTCONFIG_IPV6
161	if(ipv6_enabled() && (fn_ipv6 = fopen(mangle_fn_ipv6, "w")) == NULL){
162		fclose(fn);
163		return -3;
164	}
165#endif
166
167	inuse = sticky_enable = 0;
168
169	if(get_model()==MODEL_RTAC56U || get_model()==MODEL_RTAC56S || get_model()==MODEL_RTAC68U ||
170		get_model()==MODEL_DSLAC68U || get_model()==MODEL_RTAC87U || get_model()==MODEL_RTAC3200 ||
171		get_model()==MODEL_RTAC88U || get_model()==MODEL_RTAC3100 || get_model()==MODEL_RTAC5300 || get_model()==MODEL_RTAC5300R ||
172		get_model()==MODEL_RTAC1200G || get_model()==MODEL_RTAC1200GP)
173		manual_return = 1;
174
175	if(nvram_match("qos_sticky", "0"))
176		sticky_enable = 1;
177
178	del_iQosRules(); // flush all rules in mangle table
179
180#ifdef CLS_ACT
181	eval("ip", "link", "set", "imq0", "up");
182#endif
183	fprintf(stderr, "[qos] iptables START\n");
184
185	fprintf(fn,
186		"*mangle\n"
187		":PREROUTING ACCEPT [0:0]\n"
188		":OUTPUT ACCEPT [0:0]\n"
189		":QOSO - [0:0]\n"
190		"-A QOSO -j CONNMARK --restore-mark --mask 0x7\n"
191		"-A QOSO -m connmark ! --mark 0/0xff00 -j RETURN\n"
192		);
193#ifdef RTCONFIG_IPV6
194	if (fn_ipv6 && ipv6_enabled())
195	fprintf(fn_ipv6,
196		"*mangle\n"
197		":PREROUTING ACCEPT [0:0]\n"
198		":OUTPUT ACCEPT [0:0]\n"
199		":QOSO - [0:0]\n"
200		"-A QOSO -j CONNMARK --restore-mark --mask 0x7\n"
201		"-A QOSO -m connmark ! --mark 0/0xff00 -j RETURN\n"
202		);
203#endif
204	g = buf = strdup(nvram_safe_get("qos_rulelist"));
205	while (g) {
206
207		/* ASUSWRT
208		qos_rulelist :
209			desc>addr>port>proto>transferred>prio
210
211			addr  : (source) IP or MAC or IP-range
212			port  : dest port
213			proto : tcp, udp, tcp/udp, any , (icmp, igmp)
214			transferred : min:max
215			prio  : 0-4, 0 is the highest
216  		*/
217
218		if ((p = strsep(&g, "<")) == NULL) break;
219		if((vstrsep(p, ">", &desc, &addr, &port, &proto, &transferred, &prio)) != 6) continue;
220		class_num = atoi(prio);
221		if ((class_num < 0) || (class_num > 4)) continue;
222
223		i = 1 << class_num;
224		++class_num;
225
226		//if (method == 1) class_num |= 0x200;
227		if ((inuse & i) == 0) {
228			inuse |= i;
229			fprintf(stderr, "[qos] iptable creates, inuse=%d\n", inuse);
230		}
231
232		v4v6_ok = IPT_V4;
233#ifdef RTCONFIG_IPV6
234		if (fn_ipv6 && ipv6_enabled())
235			v4v6_ok |= IPT_V6;
236#endif
237
238		/* Beginning of the Rule */
239		/*
240 			if transferred != NULL, class_num must bt 0x1~0x6, not 0x101~0x106
241			0x1~0x6		: keep tracing this connection.
242			0x101~0x106 	: connection will be considered as marked connection, won't detect again.
243		*/
244#if 0
245		if(strcmp(transferred, "") != 0 )
246			method = 1;
247		else
248			method = nvram_get_int("qos_method");	// strict rule ordering
249		gum = (method == 0) ? 0x100 : 0;
250#else
251		method = 1;
252		gum = 0;
253#endif
254		class_num |= gum;
255		down_class_num |= gum;	// for download
256
257		chain = "QOSO";		// chain name
258		sprintf(end , " -j CONNMARK --set-return 0x%x/0x7\n", class_num);	// CONNMARK string
259		sprintf(end2, " -j RETURN\n");
260
261		/*************************************************/
262		/*                        addr                   */
263		/*           src mac or src ip or IP range       */
264		/*************************************************/
265		char tmp[20], addr_t[40];
266		char *tmp_addr, *q_ip, *q_mac;
267
268		memset(saddr_1, 0, sizeof(saddr_1));
269		memset(saddr_2, 0, sizeof(saddr_2));
270
271		memset(tmp, 0, sizeof(tmp));
272		sprintf(tmp, "%s", addr);
273		tmp_addr = tmp;
274		q_ip  = strsep(&tmp_addr, ":");
275		q_mac = tmp_addr;
276
277		memset(addr_t, 0, sizeof(addr_t));
278		sprintf(addr_t, "%s", addr);
279
280		// step1: check contain '-' or not, if yes, IP-range, ex. 192.168.1.10-192.168.1.100
281		// step2: check addr is NULL
282		// step3: check IP or MAC
283		// step4: check IP contain '*' or not, if yes, IP-range
284		// step5: check DUT's LAN IP shouldn't inside IP-range
285
286		// step1: check contain '-' or not, if yes, IP-range
287		if(strchr(addr_t, '-') == NULL){
288			// step2: check addr is NULL
289			if(!strcmp(addr_t, "")){
290				sprintf(saddr_1, "%s", addr_t);	// NULL
291			}
292			else{ // step2
293				// step3: check IP or MAC
294				if (q_mac == NULL){
295					// step4: check IP contain '*' or not, if yes, IP-range
296					if(strchr(q_ip, '*') != NULL){
297						char *rule;
298						char Mask[40];
299						struct in_addr range_A, range_B, range_C;
300
301						memset(Mask, 0, sizeof(Mask));
302						rule =  strdup(addr_t);
303						FindMask(rule, "*", "0", Mask); 				// find submask and replace "*" to "0"
304						memset(addr_t, 0, sizeof(addr_t));
305						sprintf(addr_t, "%s", rule);					// copy rule to addr_t for v4v6_ok
306
307						unsigned int ip = inet_addr(rule); 				// covert rule's IP into binary form
308						unsigned int nm = inet_addr(Mask);				// covert submask into binary form
309						unsigned int gw = inet_addr(nvram_safe_get("lan_ipaddr")); 	// covert DUT's LAN IP into binary form
310						unsigned int gw_t = htonl(gw);
311
312						range_A.s_addr = ntohl(gw_t - 1);
313						range_B.s_addr = ntohl(gw_t + 1);
314						range_C.s_addr = ip | ~nm;
315
316			//fprintf(stderr, "[addr] addr_t=%s, rule/Mask=%s/%s, ip/nm/gw=%x/%x/%x\n", addr_t, rule, Mask, ip, nm, gw); // tmp test
317
318						// step5: check DUT's LAN IP shouldn't inside IP-range
319						// DUT's LAN IP inside IP-range
320						if( (ip & nm) == (gw & nm)){
321			//fprintf(stderr, "[addr] %x/%x/%x/%x/%s matched\n", ip_t, nm_t, gw_t, range_B.s_addr, inet_ntoa(range_B)); // tmp test
322							char range_B_addr[40];
323							sprintf(range_B_addr, "%s", inet_ntoa(range_B));
324
325							sprintf(saddr_1, "-m iprange --src-range %s-%s", rule, inet_ntoa(range_A)); 		// IP-range
326							sprintf(saddr_2, "-m iprange --src-range %s-%s", range_B_addr, inet_ntoa(range_C)); 	// IP-range
327						}
328						else{
329							sprintf(saddr_1, "-m iprange --src-range %s-%s", rule, inet_ntoa(range_C)); 		// IP-range
330						}
331
332						free(rule);
333					}
334					else{ // step4
335						sprintf(saddr_1, "-s %s", addr_t);	// IP
336					}
337
338					v4v6_ok &= ipt_addr_compact(addr_t, v4v6_ok, (v4v6_ok==IPT_V4));
339					if (!v4v6_ok) continue;
340				}
341				else{ // step3
342					sprintf(saddr_1, "-m mac --mac-source %s", addr_t);	// MAC
343				}
344			}
345		}
346		else{ // step1
347			sprintf(saddr_1, "-m iprange --src-range %s", addr_t);	// IP-range
348		}
349		//fprintf(stderr, "[qos] tmp=%s, ip=%s, mac=%s, addr=%s, addr_t=%s, saddr_1=%s, saddr_2=%s\n", tmp, q_ip, q_mac, addr, addr_t, saddr_1, saddr_2); // tmp test
350
351		/*************************************************/
352		/*                      port                     */
353		/*            single port or multi-ports         */
354		/*************************************************/
355		char *tmp_port, *q_port, *q_leave;
356
357		sprintf(tmp, "%s", port);
358		tmp_port = tmp;
359		q_port = strsep(&tmp_port, ",");
360		q_leave = tmp_port;
361
362		if(strcmp(port, "") == 0 ){
363			sprintf(dport, "%s", "");
364		}
365		else{
366			if(q_leave != NULL)
367				sprintf(dport, "-m multiport --dport %s", port); // multi port
368			else
369				sprintf(dport, "--dport %s", port); // single port
370		}
371		//fprintf(stderr, "[qos] tmp=%s, q_port=%s, q_leave=%s, port=%s\n", tmp, q_port, q_leave, port ); // tmp test
372
373		/*************************************************/
374		/*                   transferred                 */
375		/*   --connbytes min:max                         */
376 		/*   --connbytes-dir (original/reply/both)       */
377 		/*   --connbytes-mode (packets/bytes/avgpkt)     */
378		/*************************************************/
379		char *tmp_trans, *q_min, *q_max;
380		long min, max ;
381
382		sprintf(tmp, "%s", transferred);
383		tmp_trans = tmp;
384		q_min = strsep(&tmp_trans, "~");
385		q_max = tmp_trans;
386
387		if (strcmp(transferred,"") == 0){
388			sprintf(conn, "%s", "");
389		}
390		else{
391			sprintf(tmp, "%s", q_min);
392			min = atol(tmp);
393
394			if(strcmp(q_max,"") == 0) // q_max == NULL
395				sprintf(conn, "-m connbytes --connbytes %ld:%s --connbytes-dir both --connbytes-mode bytes", min*1024, q_max);
396			else{// q_max != NULL
397				sprintf(tmp, "%s", q_max);
398				max = atol(tmp);
399				sprintf(conn, "-m connbytes --connbytes %ld:%ld --connbytes-dir both --connbytes-mode bytes", min*1024, max*1024-1);
400			}
401		}
402		//fprintf(stderr, "[qos] tmp=%s, transferred=%s, min=%ld, max=%ld, q_max=%s, conn=%s\n", tmp, transferred, min*1024, max*1024-1, q_max, conn); // tmp test
403
404		/*************************************************/
405		/*                      proto                    */
406		/*        tcp, udp, tcp/udp, any, (icmp, igmp)   */
407		/*************************************************/
408		memset(proto_1, 0, sizeof(proto_1));
409		memset(proto_2, 0, sizeof(proto_2));
410		if(!strcmp(proto, "tcp"))
411		{
412			sprintf(proto_1, "-p tcp");
413			sprintf(proto_2, "NO");
414		}
415		else if(!strcmp(proto, "udp"))
416		{
417			sprintf(proto_1, "-p udp");
418			sprintf(proto_2, "NO");
419		}
420		else if(!strcmp(proto, "any"))
421		{
422			sprintf(proto_1, "%s", "");
423			sprintf(proto_2, "NO");
424		}
425		else if(!strcmp(proto, "tcp/udp"))
426		{
427			sprintf(proto_1, "-p tcp");
428			sprintf(proto_2, "-p udp");
429		}
430		else{
431			sprintf(proto_1, "NO");
432			sprintf(proto_2, "NO");
433		}
434		//fprintf(stderr, "[qos] proto_1=%s, proto_2=%s, proto=%s\n", proto_1, proto_2, proto); // tmp test
435
436		/*******************************************************************/
437		/*                                                                 */
438		/*  build final rule for check proto_1, proto_2, saddr_1, saddr_2  */
439		/*                                                                 */
440		/*******************************************************************/
441		// step1. check proto != "NO"
442		// step2. if proto = any, no proto / dport
443		// step3. check saddr for ip-range; saddr_1 could be empty, dport only
444
445		if (v4v6_ok & IPT_V4){
446			// step1. check proto != "NO"
447			if(strcmp(proto_1, "NO")){
448				// step2. if proto = any, no proto / dport
449				if(strcmp(proto_1, "")){
450					// step3. check saddr for ip-range;saddr_1 could be empty, dport only
451						fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_1, conn, end);
452						if(manual_return)
453						fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_1, conn, end2);
454
455					if(strcmp(saddr_2, "")){
456						fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_2, conn, end);
457						if(manual_return)
458						fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_2, conn, end2);
459					}
460				}
461				else{
462						fprintf(fn, "-A %s %s %s %s", chain, saddr_1, conn, end);
463						if(manual_return)
464						fprintf(fn, "-A %s %s %s %s", chain, saddr_1, conn, end2);
465
466					if(strcmp(saddr_2, "")){
467						fprintf(fn, "-A %s %s %s %s", chain, saddr_2, conn, end);
468						if(manual_return)
469						fprintf(fn, "-A %s %s %s %s", chain, saddr_2, conn, end2);
470					}
471				}
472			}
473
474			// step1. check proto != "NO"
475			if(strcmp(proto_2, "NO")){
476				// step2. if proto = any, no proto / dport
477				if(strcmp(proto_2, "")){
478					// step3. check saddr for ip-range;saddr_1 could be empty, dport only
479						fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_1, conn, end);
480						if(manual_return)
481						fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_1, conn, end2);
482
483					if(strcmp(saddr_2, "")){
484						fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_2, conn, end);
485						if(manual_return)
486						fprintf(fn, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_2, conn, end2);
487					}
488				}
489				else{
490						fprintf(fn, "-A %s %s %s %s", chain, saddr_1, conn, end);
491						if(manual_return)
492						fprintf(fn, "-A %s %s %s %s", chain, saddr_1, conn, end2);
493
494					if(strcmp(saddr_2, "")){
495						fprintf(fn, "-A %s %s %s %s", chain, saddr_2, conn, end);
496						if(manual_return)
497						fprintf(fn, "-A %s %s %s %s", chain, saddr_2, conn, end2);
498					}
499				}
500			}
501		}
502
503#ifdef RTCONFIG_IPV6
504		if (fn_ipv6 && ipv6_enabled() && (v4v6_ok & IPT_V6)){
505			// step1. check proto != "NO"
506			if(strcmp(proto_1, "NO")){
507				// step2. if proto = any, no proto / dport
508				if(strcmp(proto_1, "")){
509					// step3. check saddr for ip-range;saddr_1 could be empty, dport only
510						fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_1, conn, end);
511						if(manual_return)
512						fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_1, conn, end2);
513
514					if(strcmp(saddr_2, "")){
515						fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_2, conn, end);
516						if(manual_return)
517						fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_1, dport, saddr_2, conn, end2);
518					}
519				}
520				else{
521						fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_1, conn, end);
522						if(manual_return)
523						fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_1, conn, end2);
524
525					if(strcmp(saddr_2, "")){
526						fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_2, conn, end);
527						if(manual_return)
528						fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_2, conn, end2);
529					}
530				}
531			}
532
533			// step1. check proto != "NO"
534			if(strcmp(proto_2, "NO")){
535				// step2. if proto = any, no proto / dport
536				if(strcmp(proto_2, "")){
537					// step3. check saddr for ip-range;saddr_1 could be empty, dport only
538						fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_1, conn, end);
539						if(manual_return)
540						fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_1, conn, end2);
541
542					if(strcmp(saddr_2, "")){
543						fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_2, conn, end);
544						if(manual_return)
545						fprintf(fn_ipv6, "-A %s %s %s %s %s %s", chain, proto_2, dport, saddr_2, conn, end2);
546					}
547				}
548				else{
549						fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_1, conn, end);
550						if(manual_return)
551						fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_1, conn, end2);
552					if(strcmp(saddr_2, "")){
553						fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_2, conn, end);
554						if(manual_return)
555						fprintf(fn_ipv6, "-A %s %s %s %s", chain, saddr_2, conn, end2);
556					}
557				}
558			}
559		}
560#endif
561	}
562	free(buf);
563
564	/* lan_addr for iptables use (LAN download) */
565	char *a, *b, *c, *d;
566	char lan_addr[20];
567	g = buf = strdup(nvram_safe_get("lan_ipaddr"));
568	if((vstrsep(g, ".", &a, &b, &c, &d)) != 4){
569		fprintf(stderr,"[qos] lan_ipaddr doesn't exist!!\n");
570	}
571	else{
572		sprintf(lan_addr, "%s.%s.%s.0/24", a, b, c);
573		fprintf(stderr,"[qos] lan_addr=%s\n", lan_addr);
574	}
575	free(buf);
576
577	//fprintf(stderr, "[qos] down_class_num=%x\n", down_class_num);
578
579	/* The default class */
580	i = nvram_get_int("qos_default");
581	if ((i < 0) || (i > 4)) i = 3;  // "lowest"
582	class_num = i + 1;
583
584#ifdef CONFIG_BCMWL5 // TODO: it is only for the case, eth0 as wan, vlanx as lan
585	if(strncmp(pcWANIF, "ppp", 3)==0){
586		// ppp related interface doesn't need physdev
587		// do nothing
588	}
589	else{
590		/* for WLAN to LAN bridge packet */
591		// ebtables : identify bridge packet
592		add_EbtablesRules();
593
594		// for multicast
595		fprintf(fn, "-A QOSO -d 224.0.0.0/4 -j CONNMARK --set-return 0x%x/0x7\n",  down_class_num);
596		if(manual_return)
597			fprintf(fn , "-A QOSO -d 224.0.0.0/4 -j RETURN\n");
598		// for download (LAN or wireless)
599		fprintf(fn, "-A QOSO -d %s -j CONNMARK --set-return 0x%x/0x7\n", lan_addr, down_class_num);
600		if(manual_return)
601			fprintf(fn , "-A QOSO -d %s -j RETURN\n", lan_addr);
602/* Requires bridge netfilter, but slows down and breaks EMF/IGS IGMP IPTV Snooping
603		// for WLAN to LAN bridge issue
604		fprintf(fn, "-A POSTROUTING -d %s -m physdev --physdev-is-in -j CONNMARK --set-return 0x6/0x7\n", lan_addr);
605*/
606		// for download, interface br0
607		fprintf(fn, "-A POSTROUTING -o br0 -j QOSO\n");
608	}
609#endif
610		fprintf(fn,
611			"-A QOSO -j CONNMARK --set-return 0x%x/0x7\n"
612			"-A FORWARD -o %s -j QOSO\n"
613			"-A OUTPUT -o %s -j QOSO\n",
614				class_num, pcWANIF, pcWANIF);
615		if(manual_return)
616			fprintf(fn , "-A QOSO -j RETURN\n");
617
618#ifdef RTCONFIG_IPV6
619	if (fn_ipv6 && ipv6_enabled() && *wan6face) {
620#ifdef CONFIG_BCMWL5 // TODO: it is only for the case, eth0 as wan, vlanx as lan
621		if(strncmp(wan6face, "ppp", 3)==0){
622			// ppp related interface doesn't need physdev
623			// do nothing
624		}
625		else{
626			/* for WLAN to LAN bridge packet */
627			// ebtables : identify bridge packet
628			add_EbtablesRules();
629
630			// for multicast
631			fprintf(fn_ipv6, "-A QOSO -d 224.0.0.0/4 -j CONNMARK --set-return 0x%x/0x7\n",  down_class_num);
632			if(manual_return)
633				fprintf(fn_ipv6, "-A QOSO -d 224.0.0.0/4 -j RETURN\n");
634			// for download (LAN or wireless)
635			fprintf(fn_ipv6, "-A QOSO -d %s -j CONNMARK --set-return 0x%x/0x7\n", lan_addr, down_class_num);
636			if(manual_return)
637				fprintf(fn_ipv6, "-A QOSO -d %s -j RETURN\n", lan_addr);
638/* Requires bridge netfilter, but slows down and breaks EMF/IGS IGMP IPTV Snooping
639			// for WLAN to LAN bridge issue
640			fprintf(fn_ipv6, "-A POSTROUTING -d %s -m physdev --physdev-is-in -j CONNMARK --set-return 0x6/0x7\n", lan_addr);
641*/
642			// for download, interface br0
643			fprintf(fn_ipv6, "-A POSTROUTING -o br0 -j QOSO\n");
644		}
645#endif
646		fprintf(fn_ipv6,
647			"-A QOSO -j CONNMARK --set-return 0x%x/0x7\n"
648			"-A FORWARD -o %s -j QOSO\n"
649			"-A OUTPUT -o %s -j QOSO\n",
650				class_num, wan6face, wan6face);
651		if(manual_return)
652			fprintf(fn_ipv6, "-A QOSO -j RETURN\n");
653	}
654#endif
655
656	inuse |= (1 << i) | 1;  // default and highest are always built
657	sprintf(q_inuse, "%d", inuse);
658	nvram_set("qos_inuse", q_inuse);
659	fprintf(stderr, "[qos] qos_inuse=%d\n", inuse);
660
661	/* Ingress rules */
662	g = buf = strdup(nvram_safe_get("qos_irates"));
663	for (i = 0; i < 10; ++i) {
664		if ((!g) || ((p = strsep(&g, ",")) == NULL)) continue;
665		if ((inuse & (1 << i)) == 0) continue;
666		if (atoi(p) > 0) {
667			fprintf(fn, "-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0x7\n", pcWANIF);
668#ifdef CLS_ACT
669			fprintf(fn, "-A PREROUTING -i %s -j IMQ --todev 0\n", pcWANIF);
670#endif
671#ifdef RTCONFIG_IPV6
672			if (fn_ipv6 && ipv6_enabled() && *wan6face) {
673				fprintf(fn_ipv6, "-A PREROUTING -i %s -j CONNMARK --restore-mark --mask 0x7\n", wan6face);
674#ifdef CLS_ACT
675				fprintf(fn_ipv6, "-A PREROUTING -i %s -j IMQ --todev 0\n", wan6face);
676#endif
677			}
678#endif
679			break;
680		}
681	}
682	free(buf);
683
684	fprintf(fn, "COMMIT\n");
685	fclose(fn);
686	chmod(mangle_fn, 0700);
687	eval("iptables-restore", (char*)mangle_fn);
688#ifdef RTCONFIG_IPV6
689	if (fn_ipv6 && ipv6_enabled())
690	{
691		fprintf(fn_ipv6, "COMMIT\n");
692		fclose(fn_ipv6);
693		chmod(mangle_fn_ipv6, 0700);
694//		eval("ip6tables-restore", (char*)mangle_fn_ipv6);
695	}
696#endif
697	fprintf(stderr, "[qos] iptables DONE!\n");
698
699	return 0;
700}
701
702
703/*******************************************************************/
704// The definations of all partations
705// eth0 : WAN
706// 1:1  : upload
707// 1:2  : download   (1000000Kbits)
708// 1:10 : highest
709// 1:20 : high
710// 1:30 : middle
711// 1:40 : low        (default)
712// 1:50 : lowest
713// 1:60 : ALL Download (WAN to LAN and LAN to LAN) (1000000kbits)
714/*******************************************************************/
715
716/* Tc */
717static int start_tqos(void)
718{
719	int i;
720	char *buf, *g, *p;
721	unsigned int rate;
722	unsigned int ceil;
723	unsigned int ibw, obw, bw;
724	unsigned int mtu;
725	FILE *f;
726	int x;
727	int inuse;
728	char s[256];
729	int first;
730	char burst_root[32];
731	char burst_leaf[32];
732#ifdef CONFIG_BCMWL5
733	char *protocol="802.1q";
734#endif
735
736	// judge interface by get_wan_ifname
737	// add Qos iptable rules in mangle table,
738	// move it to firewall - mangle_setting
739	// add_iQosRules(get_wan_ifname(wan_primary_ifunit())); // iptables start
740
741	ibw = strtoul(nvram_safe_get("qos_ibw"), NULL, 10);
742	obw = strtoul(nvram_safe_get("qos_obw"), NULL, 10);
743	if(ibw==0||obw==0) return -1;
744
745	if((f = fopen(qosfn, "w")) == NULL) return -2;
746
747	fprintf(stderr, "[qos] tc START!\n");
748
749	/* qos_burst */
750	i = nvram_get_int("qos_burst0");
751	if(i > 0) sprintf(burst_root, "burst %dk", i);
752		else burst_root[0] = 0;
753	i = nvram_get_int("qos_burst1");
754
755	if(i > 0) sprintf(burst_leaf, "burst %dk", i);
756		else burst_leaf[0] = 0;
757
758	/* Egress OBW  -- set the HTB shaper (Classful Qdisc)
759	* the BW is set here for each class
760	*/
761
762	mtu = strtoul(nvram_safe_get("wan_mtu"), NULL, 10);
763	bw = obw;
764
765	/* WAN */
766	fprintf(f,
767		"#!/bin/sh\n"
768		"#LAN/WAN\n"
769		"I=%s\n"
770		"SFQ=\"sfq perturb 10\"\n"
771		"TQA=\"tc qdisc add dev $I\"\n"
772		"TCA=\"tc class add dev $I\"\n"
773		"TFA=\"tc filter add dev $I\"\n"
774#ifdef CLS_ACT
775		"DLIF=imq0\n"
776		"TQADL=\"tc qdisc add dev $DLIF\"\n"
777		"TCADL=\"tc class add dev $DLIF\"\n"
778		"TFADL=\"tc filter add dev $DLIF\"\n"
779#endif
780		"case \"$1\" in\n"
781		"start)\n"
782		"#LAN/WAN\n"
783		"\ttc qdisc del dev $I root 2>/dev/null\n"
784		"\t$TQA root handle 1: htb default %u\n"
785#ifdef CLS_ACT
786		"\ttc qdisc del dev $DLIF root 2>/dev/null\n"
787		"\t$TQADL root handle 2: htb default %u\n"
788#endif
789		"# upload 1:1\n"
790		"\t$TCA parent 1: classid 1:1 htb rate %ukbit ceil %ukbit %s\n" ,
791			get_wan_ifname(wan_primary_ifunit()), // judge WAN interface
792			(nvram_get_int("qos_default") + 1) * 10,
793#ifdef CLS_ACT
794			(nvram_get_int("qos_default") + 1) * 10,
795#endif
796			bw, bw, burst_root);
797
798	/* LAN protocol: 802.1q */
799#ifdef CONFIG_BCMWL5 // TODO: it is only for the case, eth0 as wan, vlanx as lan
800	protocol = "802.1q";
801	fprintf(f,
802		"# download 1:2\n"
803		"\t$TCA parent 1: classid 1:2 htb rate 1000000kbit ceil 1000000kbit burst 10000 cburst 10000\n"
804		"# 1:60 ALL Download for BCM\n"
805		"\t$TCA parent 1:2 classid 1:60 htb rate 1000000kbit ceil 1000000kbit burst 10000 cburst 10000 prio 6\n"
806		"\t$TQA parent 1:60 handle 60: pfifo\n"
807		"\t$TFA parent 1: prio 6 protocol %s handle 6 fw flowid 1:60\n", protocol
808		);
809#endif
810
811	inuse = nvram_get_int("qos_inuse");
812
813	g = buf = strdup(nvram_safe_get("qos_orates"));
814	for (i = 0; i < 5; ++i) { // 0~4 , 0:highest, 4:lowest
815
816		if ((!g) || ((p = strsep(&g, ",")) == NULL)) break;
817
818		if ((inuse & (1 << i)) == 0){
819			fprintf(stderr, "[qos] egress %d doesn't create, inuse=%d\n", i, inuse );
820			continue;
821		}
822		else
823			fprintf(stderr, "[qos] egress %d creates\n", i);
824
825		if ((sscanf(p, "%u-%u", &rate, &ceil) != 2) || (rate < 1)) continue;
826
827		if (ceil > 0) sprintf(s, "ceil %ukbit ", calc(bw, ceil));
828			else s[0] = 0;
829		x = (i + 1) * 10;
830
831		fprintf(f,
832			"# egress %d: %u-%u%%\n"
833			"\t$TCA parent 1:1 classid 1:%d htb rate %ukbit %s %s prio %d quantum %u\n"
834			"\t$TQA parent 1:%d handle %d: $SFQ\n"
835			"\t$TFA parent 1: prio %d protocol ip handle %d fw flowid 1:%d\n",
836				i, rate, ceil,
837				x, calc(bw, rate), s, burst_leaf, (i >= 6) ? 7 : (i + 1), mtu,
838				x, x,
839				x, i + 1, x);
840	}
841	free(buf);
842
843	/*
844		10000 = ACK
845		00100 = RST
846		00010 = SYN
847		00001 = FIN
848	*/
849
850	if (nvram_match("qos_ack", "on")) {
851		fprintf(f,
852			"\n"
853			"\t$TFA parent 1: prio 14 protocol ip u32 "
854			"match ip protocol 6 0xff "			// TCP
855			"match u8 0x05 0x0f at 0 "			// IP header length
856			"match u16 0x0000 0xffc0 at 2 "			// total length (0-63)
857			"match u8 0x10 0xff at 33 "			// ACK only
858			"flowid 1:10\n");
859	}
860	if (nvram_match("qos_syn", "on")) {
861		fprintf(f,
862			"\n"
863			"\t$TFA parent 1: prio 15 protocol ip u32 "
864			"match ip protocol 6 0xff "			// TCP
865			"match u8 0x05 0x0f at 0 "			// IP header length
866			"match u16 0x0000 0xffc0 at 2 "			// total length (0-63)
867			"match u8 0x02 0x02 at 33 "			// SYN,*
868			"flowid 1:10\n");
869	}
870	if (nvram_match("qos_fin", "on")) {
871		fprintf(f,
872			"\n"
873			"\t$TFA parent 1: prio 17 protocol ip u32 "
874			"match ip protocol 6 0xff "			// TCP
875			"match u8 0x05 0x0f at 0 "			// IP header length
876			"match u16 0x0000 0xffc0 at 2 "			// total length (0-63)
877			"match u8 0x01 0x01 at 33 "			// FIN,*
878			"flowid 1:10\n");
879	}
880	if (nvram_match("qos_rst", "on")) {
881		fprintf(f,
882			"\n"
883			"\t$TFA parent 1: prio 19 protocol ip u32 "
884			"match ip protocol 6 0xff "			// TCP
885			"match u8 0x05 0x0f at 0 "			// IP header length
886			"match u16 0x0000 0xffc0 at 2 "			// total length (0-63)
887			"match u8 0x04 0x04 at 33 "			// RST,*
888			"flowid 1:10\n");
889	}
890	if (nvram_match("qos_icmp", "on")) {
891		fputs("\n\t$TFA parent 1: prio 13 protocol ip u32 match ip protocol 1 0xff flowid 1:10\n", f);
892	}
893
894	// ingress
895	first = 1;
896	bw = ibw;
897
898	if (bw > 0) {
899		g = buf = strdup(nvram_safe_get("qos_irates"));
900		for (i = 0; i < 5; ++i) { // 0~4 , 0:highest, 4:lowest
901			if ((!g) || ((p = strsep(&g, ",")) == NULL)) break;
902			if ((inuse & (1 << i)) == 0) continue;
903			if ((rate = atoi(p)) < 1) continue;	// 0 = off
904
905			if (first) {
906				first = 0;
907				fprintf(f,
908					"\n"
909#if !defined(CLS_ACT)
910					"\ttc qdisc del dev $I ingress 2>/dev/null\n"
911					"\t$TQA handle ffff: ingress\n"
912#endif
913					);
914			}
915
916			// rate in kb/s
917			unsigned int u = calc(bw, rate);
918
919			// burst rate
920			unsigned int v = u / 2;
921			if (v < 50) v = 50;
922
923#ifdef CLS_ACT
924			x = (i + 1) * 10;
925			fprintf(f,
926				"# ingress %d: %u%%\n"
927				"\t$TCADL parent 2:1 classid 2:%d htb rate %ukbit %s prio %d quantum %u\n"
928				"\t$TQADL parent 2:%d handle %d: $SFQ\n"
929				"\t$TFADL parent 2: prio %d protocol ip handle %d fw flowid 2:%d\n",
930					i, rate,
931					x, calc(bw, rate), burst_leaf, (i >= 6) ? 7 : (i + 1), mtu,
932					x, x,
933					x, i + 1, x);
934#else
935			x = i + 1;
936			fprintf(f,
937				"# ingress %d: %u%%\n"
938				"\t$TFA parent ffff: prio %d protocol ip handle %d"
939					" fw police rate %ukbit burst %ukbit drop flowid ffff:%d\n",
940					i, rate, x, x, u, v, x);
941#endif
942		}
943		free(buf);
944	}
945
946	fputs(
947		"\t;;\n"
948		"stop)\n"
949		"\ttc qdisc del dev $I root 2>/dev/null\n"
950#ifdef CLS_ACT
951		"\ttc qdisc del dev $DLIF root 2>/dev/null\n"
952#else
953		"\ttc qdisc del dev $I ingress 2>/dev/null\n"
954#endif
955		"\t;;\n"
956		"*)\n"
957		"\t#---------- Upload ----------\n"
958		"\ttc -s -d class ls dev $I\n"
959		"\ttc -s -d qdisc ls dev $I\n"
960		"\techo\n"
961#ifdef CLS_ACT
962		"\t#--------- Download ---------\n"
963		"\ttc -s -d class ls dev $DLIF\n"
964		"\ttc -s -d qdisc ls dev $DLIF\n"
965		"\techo\n"
966#endif
967		"esac\n",
968		f);
969
970	fclose(f);
971	chmod(qosfn, 0700);
972	eval((char *)qosfn, "start");
973	fprintf(stderr,"[qos] tc done!\n");
974
975	return 0;
976}
977
978
979void stop_iQos(void)
980{
981	eval((char *)qosfn, "stop");
982}
983
984#define TYPE_IP 0
985#define TYPE_MAC 1
986#define TYPE_IPRANGE 2
987#define TYPE_GUEST 3
988
989static void address_checker(int *addr_type, char *addr_old, char *addr_new, int len)
990{
991	char *second, *last_dot;
992	int len_to_minus, len_to_dot;
993
994	// guestnetwork interface
995	if (strstr(addr_old, "wl")){
996		*addr_type = TYPE_GUEST;
997		strncpy(addr_new, addr_old, len);
998		return;
999	}
1000
1001	second = strchr(addr_old, '-');
1002	if (second != NULL)
1003	{
1004		*addr_type = TYPE_IPRANGE;
1005		if (strchr(second+1, '.') != NULL){
1006			// long notation
1007			strncpy(addr_new, addr_old, len);
1008		}
1009		else{
1010			// short notation
1011			last_dot = strrchr(addr_old, '.');
1012			len_to_minus = second - addr_old;
1013			len_to_dot = last_dot - addr_old;
1014			strncpy(addr_new, addr_old, len_to_minus+1);
1015			strncpy(addr_new + len_to_minus + 1, addr_new, len_to_dot+1);
1016			strcpy(addr_new + len_to_minus + len_to_dot + 2, second+1);
1017		}
1018	}
1019	else
1020	{
1021		if (strlen(addr_old) == 17)
1022			*addr_type = TYPE_MAC;
1023		else
1024			*addr_type = TYPE_IP;
1025		strncpy(addr_new, addr_old, len);
1026	}
1027}
1028
1029static int add_bandwidth_limiter_rules(char *pcWANIF)
1030{
1031	FILE *fn = NULL;
1032	char *buf, *g, *p;
1033	char *enable, *addr, *dlc, *upc, *prio;
1034	char lan_addr[32];
1035	char addr_new[32];
1036	int addr_type;
1037	char *action = NULL;
1038
1039	if ((fn = fopen(mangle_fn, "w")) == NULL) return -2;
1040	del_iQosRules(); // flush all rules in mangle table
1041
1042	switch (get_model()){
1043		case MODEL_DSLN55U:
1044		case MODEL_RTN13U:
1045		case MODEL_RTN56U:
1046			action = "CONNMARK --set-return";
1047			manual_return = 0;
1048			break;
1049		default:
1050			action = "MARK --set-mark";
1051			manual_return = 1;
1052			break;
1053	}
1054
1055	/* ASUSWRT
1056	qos_bw_rulelist :
1057		enable>addr>DL-Ceil>UL-Ceil>prio
1058		enable : enable or disable this rule
1059		addr : (source) IP or MAC or IP-range or wireless interface(wl0.1, wl0.2, etc.)
1060		DL-Ceil : the max download bandwidth
1061		UL-Ceil : the max upload bandwidth
1062		prio : priority for client
1063	*/
1064
1065	memset(lan_addr, 0, sizeof(lan_addr));
1066	sprintf(lan_addr, "%s/%s", nvram_safe_get("lan_ipaddr"), nvram_safe_get("lan_netmask"));
1067
1068	fprintf(fn,
1069		"*mangle\n"
1070		":PREROUTING ACCEPT [0:0]\n"
1071		":OUTPUT ACCEPT [0:0]\n"
1072		);
1073
1074	// access router : mark 9
1075	fprintf(fn,
1076		"-A POSTROUTING -s %s -d %s -j %s 9\n"
1077		"-A PREROUTING -s %s -d %s -j %s 9\n"
1078		, nvram_safe_get("lan_ipaddr"), lan_addr, action
1079		, lan_addr, nvram_safe_get("lan_ipaddr"), action
1080		);
1081
1082	if(manual_return){
1083	fprintf(fn,
1084		"-A POSTROUTING -s %s -d %s -j RETURN\n"
1085		"-A PREROUTING -s %s -d %s -j RETURN\n"
1086		, nvram_safe_get("lan_ipaddr"), lan_addr
1087		, lan_addr, nvram_safe_get("lan_ipaddr")
1088		);
1089	}
1090
1091	g = buf = strdup(nvram_safe_get("qos_bw_rulelist"));
1092	while (g) {
1093		if ((p = strsep(&g, "<")) == NULL) break;
1094		if ((vstrsep(p, ">", &enable, &addr, &dlc, &upc, &prio)) != 5) continue;
1095		if (!strcmp(enable, "0")) continue;
1096		memset(addr_new, 0, sizeof(addr_new));
1097		address_checker(&addr_type, addr, addr_new, sizeof(addr_new));
1098		_dprintf("[BWLIT] %s: addr_type=%d, addr=%s, add_new=%s, lan_addr=%s\n", __FUNCTION__, addr_type, addr, addr_new, lan_addr);
1099
1100		if (addr_type == TYPE_IP){
1101			fprintf(fn,
1102				"-A POSTROUTING ! -s %s -d %s -j %s %d\n"
1103				"-A PREROUTING -s %s ! -d %s -j %s %d\n"
1104				, lan_addr, addr_new, action, atoi(prio)+10
1105				, addr_new, lan_addr, action, atoi(prio)+10
1106				);
1107			if(manual_return){
1108			fprintf(fn,
1109				"-A POSTROUTING ! -s %s -d %s -j RETURN\n"
1110				"-A PREROUTING -s %s ! -d %s -j RETURN\n"
1111				, lan_addr, addr_new, addr_new, lan_addr
1112				);
1113			}
1114		}
1115		else if (addr_type == TYPE_MAC){
1116			fprintf(fn,
1117				"-A PREROUTING -m mac --mac-source %s ! -d %s  -j %s %d\n"
1118				, addr_new, lan_addr, action, atoi(prio)+10
1119				);
1120			if(manual_return){
1121			fprintf(fn,
1122				"-A PREROUTING -m mac --mac-source %s ! -d %s  -j RETURN\n"
1123				, addr_new, lan_addr
1124				);
1125			}
1126		}
1127		else if (addr_type == TYPE_IPRANGE){
1128			fprintf(fn,
1129				"-A POSTROUTING ! -s %s -m iprange --dst-range %s -j %s %d\n"
1130				"-A PREROUTING -m iprange --src-range %s ! -d %s -j %s %d\n"
1131				, lan_addr, addr_new, action, atoi(prio)+10
1132				, addr_new, lan_addr, action, atoi(prio)+10
1133				);
1134			if(manual_return){
1135			fprintf(fn,
1136				"-A POSTROUTING ! -s %s -m iprange --dst-range %s -j RETURN\n"
1137				"-A PREROUTING -m iprange --src-range %s ! -d %s -j RETURN\n"
1138				, lan_addr, addr_new, addr_new, lan_addr
1139				);
1140			}
1141		}
1142		else if (addr_type == TYPE_GUEST) continue;
1143	}
1144	free(buf);
1145
1146	fprintf(fn, "COMMIT\n");
1147	fclose(fn);
1148	chmod(mangle_fn, 0700);
1149	eval("iptables-restore", (char*)mangle_fn);
1150	_dprintf("[BWLIT] %s: create rules\n", __FUNCTION__);
1151
1152	return 0;
1153}
1154
1155static int guest; // qdisc root only 3: ~ 12: (9 guestnetwork)
1156
1157static int start_bandwidth_limiter(void)
1158{
1159	FILE *f = NULL;
1160	char *buf, *g, *p;
1161	char *enable, *addr, *dlc, *upc, *prio;
1162	int class = 0;
1163	int s[6]; // strip mac address
1164	int addr_type;
1165	char addr_new[30];
1166
1167	// init guest 3: ~ 12: (9 guestnetwork), start number = 3
1168	guest = 3;
1169
1170	if ((f = fopen(qosfn, "w")) == NULL) return -2;
1171	fprintf(f,
1172		"#!/bin/sh\n"
1173		"WAN=%s\n"
1174		"\n"
1175		"case \"$1\" in\n"
1176		"start)\n"
1177		, get_wan_ifname(wan_primary_ifunit())
1178	);
1179
1180	/* ASUSWRT
1181	qos_bw_rulelist :
1182		enable>addr>DL-Ceil>UL-Ceil>prio
1183		enable : enable or disable this rule
1184		addr : (source) IP or MAC or IP-range or wireless interface(wl0.1, wl0.2, etc.)
1185		DL-Ceil : the max download bandwidth
1186		UL-Ceil : the max upload bandwidth
1187		prio : priority for client
1188	*/
1189
1190	g = buf = strdup(nvram_safe_get("qos_bw_rulelist"));
1191
1192	// if no qos_bw_rulelist, shouldn't set tc rule
1193	if (strcmp(g, "")) {
1194		fprintf(f,
1195		"tc qdisc del dev $WAN root 2>/dev/null\n"
1196		"tc qdisc del dev $WAN ingress 2>/dev/null\n"
1197		"tc qdisc del dev br0 root 2>/dev/null\n"
1198		"tc qdisc del dev br0 ingress 2>/dev/null\n"
1199		"\n"
1200		"TQAU=\"tc qdisc add dev $WAN\"\n"
1201		"TCAU=\"tc class add dev $WAN\"\n"
1202		"TFAU=\"tc filter add dev $WAN\"\n"
1203		"SFQ=\"sfq perturb 10\"\n"
1204		"TQA=\"tc qdisc add dev br0\"\n"
1205		"TCA=\"tc class add dev br0\"\n"
1206		"TFA=\"tc filter add dev br0\"\n"
1207		"\n"
1208		"$TQA root handle 1: htb\n"
1209		"$TCA parent 1: classid 1:1 htb rate 10240000kbit\n"
1210		"\n"
1211		"$TQAU root handle 2: htb\n"
1212		"$TCAU parent 2: classid 2:1 htb rate 10240000kbit\n"
1213		);
1214
1215		// access router : mark 9
1216		// default : 10Gbps
1217		fprintf(f,
1218		"\n"
1219		"$TCA parent 1:1 classid 1:9 htb rate 10240000kbit ceil 10240000kbit prio 1\n"
1220		"$TQA parent 1:9 handle 9: $SFQ\n"
1221		"$TFA parent 1: prio 1 protocol ip handle 9 fw flowid 1:9\n"
1222		"\n"
1223		"$TCAU parent 2:1 classid 2:9 htb rate 10240000kbit ceil 10240000kbit prio 1\n"
1224		"$TQAU parent 2:9 handle 9: $SFQ\n"
1225		"$TFAU parent 2: prio 1 protocol ip handle 9 fw flowid 2:9\n"
1226		);
1227	}
1228
1229	while (g) {
1230		if ((p = strsep(&g, "<")) == NULL) break;
1231		if ((vstrsep(p, ">", &enable, &addr, &dlc, &upc, &prio)) != 5) continue;
1232		if (!strcmp(enable, "0")) continue;
1233
1234		address_checker(&addr_type, addr, addr_new, sizeof(addr_new));
1235		class = atoi(prio) + 10;
1236		if (addr_type == TYPE_MAC)
1237		{
1238			sscanf(addr_new, "%02X:%02X:%02X:%02X:%02X:%02X",&s[0],&s[1],&s[2],&s[3],&s[4],&s[5]);
1239			fprintf(f,
1240				"\n"
1241				"$TCA parent 1:1 classid 1:%d htb rate %skbit ceil %skbit prio %d\n"
1242				"$TQA parent 1:%d handle %d: $SFQ\n"
1243				"$TFA parent 1: protocol ip prio %d u32 match u16 0x0800 0xFFFF at -2 match u32 0x%02X%02X%02X%02X 0xFFFFFFFF at -12 match u16 0x%02X%02X 0xFFFF at -14 flowid 1:%d"
1244				"\n"
1245				"$TCAU parent 2:1 classid 2:%d htb rate %skbit ceil %skbit prio %d\n"
1246				"$TQAU parent 2:%d handle %d: $SFQ\n"
1247				"$TFAU parent 2: prio %d protocol ip handle %d fw flowid 2:%d\n"
1248				, class, dlc, dlc, class
1249				, class, class
1250				, class, s[2], s[3], s[4], s[5], s[0], s[1], class
1251				, class, upc, upc, class
1252				, class, class
1253				, class, class, class
1254			);
1255		}
1256		else if (addr_type == TYPE_IP || addr_type == TYPE_IPRANGE)
1257		{
1258			fprintf(f,
1259				"\n"
1260				"$TCA parent 1:1 classid 1:%d htb rate %skbit ceil %skbit prio %d\n"
1261				"$TQA parent 1:%d handle %d: $SFQ\n"
1262				"$TFA parent 1: prio %d protocol ip handle %d fw flowid 1:%d\n"
1263				"\n"
1264				"$TCAU parent 2:1 classid 2:%d htb rate %skbit ceil %skbit prio %d\n"
1265				"$TQAU parent 2:%d handle %d: $SFQ\n"
1266				"$TFAU parent 2: prio %d protocol ip handle %d fw flowid 2:%d\n"
1267				, class, dlc, dlc, class
1268				, class, class
1269				, class, class, class
1270				, class, upc, upc, class
1271				, class, class
1272				, class, class, class
1273			);
1274		}
1275		else if (addr_type == TYPE_GUEST)
1276		{
1277			// setup guest network's bandwidth limiter
1278			char mssid_mark[4];
1279			char *wl_if = NULL;
1280			int i, j;
1281
1282			if(sscanf(addr_new, "wl%d.%d", &i, &j) != 2){
1283				_dprintf("[BWLIT] %s: fail to strip i, j from wlx.x\n", __FUNCTION__);
1284			}
1285
1286			snprintf(mssid_mark, sizeof(mssid_mark), "%d", class);
1287
1288			if(get_model()==MODEL_RTAC87U && (i == 1)){
1289				if(j == 1) wl_if = "vlan4000";
1290				if(j == 2) wl_if = "vlan4001";
1291				if(j == 3) wl_if = "vlan4002";
1292			}
1293			else{
1294				wl_if = addr_new;
1295			}
1296
1297			eval("ebtables", "-t", "nat", "-A", "PREROUTING", "-i", wl_if, "-j", "mark", "--set-mark", mssid_mark, "--mark-target", "ACCEPT");
1298			eval("ebtables", "-t", "nat", "-A", "POSTROUTING", "-o", wl_if, "-j", "mark", "--set-mark", mssid_mark, "--mark-target", "ACCEPT");
1299
1300			fprintf(f,
1301				"\n"
1302				"tc qdisc del dev %s root 2>/dev/null\n"
1303				"GUEST%d%d=%s\n"
1304				"TQA%d%d=\"tc qdisc add dev $GUEST%d%d\"\n"
1305				"TCA%d%d=\"tc class add dev $GUEST%d%d\"\n"
1306				"TFA%d%d=\"tc filter add dev $GUEST%d%d\"\n" // 5
1307				"\n"
1308				"$TQA%d%d root handle %d: htb\n"
1309				"$TCA%d%d parent %d: classid %d:1 htb rate %skbit\n" // 7
1310				"\n"
1311				"$TCA%d%d parent %d:1 classid %d:%d htb rate 1kbit ceil %skbit prio %d\n"
1312				"$TQA%d%d parent %d:%d handle %d: $SFQ\n"
1313				"$TFA%d%d parent %d: prio %d protocol ip handle %d fw flowid %d:%d\n" // 10
1314				"\n"
1315				"$TCAU parent 2:1 classid 2:%d htb rate 1kbit ceil %skbit prio %d\n"
1316				"$TQAU parent 2:%d handle %d: $SFQ\n"
1317				"$TFAU parent 2: prio %d protocol ip handle %d fw flowid 2:%d\n" // 13
1318				, wl_if
1319				, i, j, wl_if
1320				, i, j, i, j
1321				, i, j, i, j
1322				, i, j, i, j // 5
1323				, i, j, guest
1324				, i, j, guest, guest, dlc //7
1325				, i, j, guest, guest, class, dlc, class
1326				, i, j, guest, class, class
1327				, i, j, guest, class, class, guest, class // 10
1328				, class, upc, class
1329				, class, class
1330				, class, class, class //13
1331			);
1332			_dprintf("[BWLIT] %s: create %s bandwidth limiter, qdisc=%d, class=%d\n", __FUNCTION__, wl_if, guest, class);
1333			guest++; // add guest 3: ~ 12: (9 guestnetwork)
1334		}
1335	}
1336	free(buf);
1337
1338	fprintf(f,
1339		";;\n"
1340		"stop)\n"
1341		"tc qdisc del dev $WAN root 2>/dev/null\n"
1342		"tc qdisc del dev $WAN ingress 2>/dev/null\n"
1343		"tc qdisc del dev br0 root 2>/dev/null\n"
1344		"tc qdisc del dev br0 ingress 2>/dev/null\n"
1345		";;\n"
1346		"*)\n"
1347		"tc -s -d class ls dev $WAN\n"
1348		"tc -s -d class ls dev br0\n"
1349		"esac"
1350	);
1351
1352	fclose(f);
1353	chmod(qosfn, 0700);
1354	eval((char *)qosfn, "start");
1355	_dprintf("[BWLIT] %s: create bandwidth limiter\n", __FUNCTION__);
1356
1357	return 0;
1358}
1359
1360int add_iQosRules(char *pcWANIF)
1361{
1362	int status = 0;
1363	if (pcWANIF == NULL || nvram_get_int("qos_enable") != 1 || nvram_get_int("qos_type") == 1) return -1;
1364
1365	if (nvram_get_int("qos_enable") == 1 && nvram_get_int("qos_type") == 0)
1366		status = add_qos_rules(pcWANIF);
1367	else if (nvram_get_int("qos_enable") == 1 && nvram_get_int("qos_type") == 2)
1368		status = add_bandwidth_limiter_rules(pcWANIF);
1369
1370	if (status < 0) _dprintf("[%s] status = %d\n", __FUNCTION__, status);
1371
1372	return status;
1373}
1374
1375int start_iQos(void)
1376{
1377	int status = 0;
1378	if (nvram_get_int("qos_enable") != 1 || nvram_get_int("qos_type") == 1) return -1;
1379
1380	if (nvram_get_int("qos_enable") == 1 && nvram_get_int("qos_type") == 0)
1381		status = start_tqos();
1382	else if (nvram_get_int("qos_enable") == 1 && nvram_get_int("qos_type") == 2)
1383		status = start_bandwidth_limiter();
1384
1385	if (status < 0) _dprintf("[%s] status = %d\n", __FUNCTION__, status);
1386
1387	return status;
1388}
1389