Index: lede/feeds/packages/net/miniupnpd/patches/303-change_file_for_wsc.patch
===================================================================
--- /dev/null
+++ lede/feeds/packages/net/miniupnpd/patches/303-change_file_for_wsc.patch
@@ -0,0 +1,1742 @@
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/minissdp.c
+===================================================================
+--- a/minissdp.c
++++ b/minissdp.c
+@@ -39,6 +39,9 @@
+ #include "asyncsendto.h"
+ #include "codelength.h"
+ #include "macros.h"
++#ifdef ENABLE_WSC_SERVICE
++#include "wsc/wsc_common.h"
++#endif /* ENABLE_WSC_SERVICE */ 
+ 
+ #ifndef MIN
+ #define MIN(x,y) (((x)<(y))?(x):(y))
+@@ -592,6 +595,16 @@ SendSSDPResponse(int s, const struct soc
+ 	}
+ }
+ 
++#ifdef ENABLE_WSC_SERVICE
++static const char * const wfa_known_service_types[] =
++{
++	"upnp:rootdevice",
++	"urn:schemas-wifialliance-org:device:WFADevice:",	
++	"urn:schemas-wifialliance-org:service:WFAWLANConfig:",	
++	0
++};
++#endif /* ENABLE_WSC_SERVICE */
++
+ static struct {
+ 	const char * s;
+ 	const int version;
+@@ -816,6 +829,76 @@ SendSSDPNotifies(int s, const char * hos
+ #endif /* ENABLE_IPV6 */
+ }
+ 
++#ifdef ENABLE_WSC_SERVICE
++static void
++WSC_SendSSDPNotifies(int s, const char * host, unsigned short port,
++                 unsigned int lifetime)
++{
++	struct sockaddr_in sockname;
++	int l, n, i=0;
++	char bufr[512];
++
++	memset(&sockname, 0, sizeof(struct sockaddr_in));
++	sockname.sin_family = AF_INET;
++	sockname.sin_port = htons(SSDP_PORT);
++	sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
++
++	if (GETFLAG(ENABLEWPSMASK))
++	{
++		while(wfa_known_service_types[i])
++		{
++			l = snprintf(bufr, sizeof(bufr), 
++					"NOTIFY * HTTP/1.1\r\n"
++					"HOST:%s:%d\r\n"
++					"Cache-Control:max-age=%u\r\n"
++					"Location:http://%s:%d" WFA_ROOTDESC_PATH"\r\n"
++					/*"Server:miniupnpd/1.0 UPnP/1.0\r\n"*/
++					"Server: " MINIUPNPD_SERVER_STRING "\r\n"
++					"NT:%s%s\r\n"
++					"USN:%s::%s%s\r\n"
++					"NTS:ssdp:alive\r\n"
++					"\r\n",
++					SSDP_MCAST_ADDR, SSDP_PORT,
++					lifetime,
++					host, port,
++					wfa_known_service_types[i], (i==0?"":"1"),
++					wps_uuidvalue, wfa_known_service_types[i], (i==0?"":"1") );
++			if(l>=sizeof(bufr))
++			{
++				syslog(LOG_WARNING, "WSC_SendSSDPNotifies(): truncated output");
++				l = sizeof(bufr);
++			}
++
++			n = sendto(s, bufr, l, 0,
++				(struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
++
++			if(n < 0)
++			{
++				syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s, host);
++			}
++			i++;
++		}
++	}
++	else
++	{
++		;
++	}
++}
++
++void
++WSC_SendSSDPNotifies2(int * sockets,
++                  unsigned short port,
++                  unsigned int lifetime)
++{
++	int i;
++	struct lan_addr_s * lan_addr;
++	for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
++	{
++		WSC_SendSSDPNotifies(sockets[i], lan_addr->str, port, lifetime);
++	}
++}
++#endif /* ENABLE_WSC_SERVICE */
++
+ /* SendSSDPNotifies2() sends SSDP NOTIFY packets on all interfaces
+  * for all destinations, all devices / services */
+ void
+@@ -1339,6 +1422,55 @@ ProcessSSDPData(int s, const char *bufr,
+ 					                 uuidvalue_wcd, delay);
+ 				}
+ 			}
++#ifdef ENABLE_WSC_SERVICE
++			if (GETFLAG(ENABLEWPSMASK))
++			{
++				for(i = 0; wfa_known_service_types[i]; i++)
++				{
++					l = (int)strlen(wfa_known_service_types[i]);
++					if(l<=st_len && (0 == memcmp(st, wfa_known_service_types[i], l)))
++					{
++						syslog(LOG_INFO, "WPS Single search found");					
++						SendSSDPResponse(s, sender,
++						                  st, st_len, "",
++						                  announced_host, WPS_PORT,
++#ifdef ENABLE_HTTPS
++										https_port,
++#endif
++										wfa_known_service_types[i], delay);
++						break;
++					}
++				}
++				/* Responds to request with ST: ssdp:all */
++				/* strlen("ssdp:all") == 8 */
++				if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
++				{
++					for(i=0; wfa_known_service_types[i]; i++)
++					{
++						l = (int)strlen(wfa_known_service_types[i]);
++						SendSSDPResponse(s, sender,
++						                  wfa_known_service_types[i], l, i==0?"":"1",
++						                  announced_host, WPS_PORT,
++#ifdef ENABLE_HTTPS
++										https_port,
++#endif
++										wfa_known_service_types[i], delay);
++					}
++				}
++				/* responds to request by UUID value */
++				l = (int)strlen(wps_uuidvalue);
++				if(l==st_len && (0 == memcmp(st, wps_uuidvalue, l)))
++				{
++					SendSSDPResponse(s, sender, st, st_len, "",
++					                  announced_host, WPS_PORT,
++#ifdef ENABLE_HTTPS
++									https_port,
++#endif
++									wfa_known_service_types[i], delay);
++				}
++
++			}
++#endif /* ENABLE_WSC_SERVICE */
+ 		}
+ 		else
+ 		{
+@@ -1481,6 +1613,49 @@ SendSSDPGoodbye(int * sockets, int n_soc
+ 	return ret;
+ }
+ 
++#ifdef ENABLE_WSC_SERVICE
++/* This will broadcast ssdp:byebye notifications to inform 
++ * the network that UPnP is going down. */
++int
++WSC_SendSSDPGoodbye(int * sockets, int n_sockets)
++{
++	struct sockaddr_in sockname;
++	int n, l;
++	int i, j;
++	char bufr[512];
++
++    memset(&sockname, 0, sizeof(struct sockaddr_in));
++    sockname.sin_family = AF_INET;
++    sockname.sin_port = htons(SSDP_PORT);
++    sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
++
++	for(j=0; j<n_sockets; j++)
++	{
++	    for(i=0; wfa_known_service_types[i]; i++)
++	    {
++	        l = snprintf(bufr, sizeof(bufr),
++	                 "NOTIFY * HTTP/1.1\r\n"
++	                 "HOST:%s:%d\r\n"
++	                 "NT:%s%s\r\n"
++	                 "USN:%s::%s%s\r\n"
++	                 "NTS:ssdp:byebye\r\n"
++	                 "\r\n",
++	                 SSDP_MCAST_ADDR, SSDP_PORT,
++					 wfa_known_service_types[i], (i==0?"":"1"),
++	                 wps_uuidvalue, wfa_known_service_types[i], (i==0?"":"1"));
++	        n = sendto(sockets[j], bufr, l, 0,
++	                   (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
++			if(n < 0)
++			{
++				syslog(LOG_ERR, "sendto(udp_shutdown=%d): %m", sockets[j]);
++				return -1;
++			}
++		}
++	}
++	return 0;
++}
++#endif
++
+ /* SubmitServicesToMiniSSDPD() :
+  * register services offered by MiniUPnPd to a running instance of
+  * MiniSSDPd */
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/minissdp.h
+===================================================================
+--- a/minissdp.h
++++ b/minissdp.h
+@@ -28,6 +28,15 @@ SendSSDPNotifies2(int * sockets,
+                   unsigned int lifetime);
+ #endif
+ 
++#ifdef ENABLE_WSC_SERVICE
++void
++WSC_SendSSDPNotifies2(int * sockets,
++                  unsigned short port,
++                  unsigned int lifetime);
++int
++WSC_SendSSDPGoodbye(int * sockets, int n);
++#endif /* ENABLE_WSC_SERVICE */
++
+ void
+ #ifdef ENABLE_HTTPS
+ ProcessSSDPRequest(int s,
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/miniupnpd.c
+===================================================================
+--- a/miniupnpd.c
++++ b/miniupnpd.c
+@@ -88,6 +88,88 @@
+ #endif
+ #include "commonrdr.h"
+ #include "upnputils.h"
++
++#ifdef ENABLE_WSC_SERVICE
++#include "wsc/wsc_common.h"
++//#include "wsc/wsc_netlink.h"
++#ifdef RT_DEBUG
++/* To be improved */
++int
++xml_print(const char * s, int len, FILE * f)
++{
++	int n = 0, i;
++	int elt_close = 0;
++	int c, indent = 0;
++
++	while(len > 0)
++	{
++		c = *(s++);	len--;
++		switch(c)
++		{
++		case '<':
++			if(len>0 && *s == '/')
++				elt_close++;
++			else if(len>0 && *s == '?')
++				elt_close = 1;
++			else
++				elt_close = 0;
++			if(elt_close!=1)
++			{
++				if(elt_close > 1)
++					indent--;
++				fputc('\n', f); n++;
++				for(i=indent; i>0; i--)
++					fputc(' ', f);
++				n += indent;
++			}
++			fputc(c, f); n++;
++			break;
++		case '>':
++			fputc(c, f); n++;
++			if(elt_close==1)
++			{
++				/*fputc('\n', f); n++; */
++				//elt_close = 0;
++				if(indent > 0)
++					indent--;
++			}
++			else if(elt_close == 0)
++				indent++;
++			break;
++		default:
++			fputc(c, f); n++;
++		}
++	}
++	return n;
++}
++
++int DescDump()
++{
++	char * Desc;
++	int DescLen;
++	char * s;
++	int l;
++
++	Desc = genWSCRootDesc((int *)&DescLen);
++	xml_print(Desc, DescLen, stdout);
++	free(Desc);
++	printf("\n-------------\n");
++
++	s = genWSC((int *)&l);
++	xml_print(s, l, stdout);
++	free(s);
++	printf("\n-------------\n");
++#ifdef ENABLE_EVENTS
++	s = getVarsWSC((int *)&l);
++	xml_print(s, l, stdout);
++	free(s);
++	printf("\n-------------\n");
++#endif /* ENABLE_EVENTS */
++	return 0;
++}
++#endif /* RT_DEBUG */
++#endif /* ENABLE_WSC_SERVICE */
++
+ #ifdef USE_IFACEWATCHER
+ #include "ifacewatcher.h"
+ #endif
+@@ -303,6 +385,10 @@ tomato_helper(void)
+ #endif  /* 1 (tomato) */
+ #endif	/* TOMATO */
+ 
++#ifdef ENABLE_WSC_SERVICE
++extern int wsc_debug_level;
++#endif /* ENABLE_WSC_SERVICE */
++
+ /* OpenAndConfHTTPSocket() :
+  * setup the socket used to handle incoming HTTP connections. */
+ static int
+@@ -1037,6 +1123,7 @@ parselanaddr(struct lan_addr_s * lan_add
+ 		}
+ 	}
+ #endif
++#ifndef ENABLE_WSC_SERVICE
+ 	if(lan_addr->ifname[0] != '\0')
+ 	{
+ 		lan_addr->index = if_nametoindex(lan_addr->ifname);
+@@ -1058,6 +1145,7 @@ parselanaddr(struct lan_addr_s * lan_add
+ 		syslog(LOG_NOTICE, "it is advised to use network interface name instead of %s", str);
+ 	}
+ #endif
++#endif /* ENABLE_WSC_SERVICE */
+ 	return 0;
+ parselan_error:
+ 	fprintf(stderr, "Error parsing address/mask (or interface name) : %s\n",
+@@ -1149,7 +1237,7 @@ static int
+ init(int argc, char * * argv, struct runtime_vars * v)
+ {
+ 	int i;
+-#ifndef NO_BACKGROUND_NO_PIDFILE
++#if defined(ENABLE_WSC_SERVICE) || !defined(NO_BACKGROUND_NO_PIDFILE)
+ 	int pid;
+ #endif
+ 	int debug_flag = 0;
+@@ -1186,7 +1274,12 @@ init(int argc, char * * argv, struct run
+ #endif /* DISABLE_CONFIG_FILE */
+ 
+ 	/* set initial values */
++#ifdef ENABLE_WSC_SERVICE
++	SETFLAG(ENABLEWPSMASK);
++#else
+ 	SETFLAG(ENABLEUPNPMASK);	/* UPnP is enabled by default */
++#endif /* ENABLE_WSC_SERVICE */
++
+ #ifdef ENABLE_IPV6
+ 	ipv6_bind_addr = in6addr_any;
+ #endif /* ENABLE_IPV6 */
+@@ -1530,6 +1623,18 @@ init(int argc, char * * argv, struct run
+ 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+ 			serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
+ 			break;
++#ifdef ENABLE_WSC_SERVICE
++		case 'M':
++			if(i+1 < argc)
++				strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);
++			else
++				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
++			modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
++			break;
++		case 'm':
++			i++;	/* discarding */
++			break;
++#else
+ 		case 'm':
+ 			if(i+1 < argc)
+ 				strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);
+@@ -1537,12 +1642,26 @@ init(int argc, char * * argv, struct run
+ 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+ 			modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
+ 			break;
++#endif /* ENABLE_WSC_SERVICE */
+ #ifdef ENABLE_NATPMP
+ 		case 'N':
+ 			/*enablenatpmp = 1;*/
+ 			SETFLAG(ENABLENATPMPMASK);
+ 			break;
+ #endif	/* ENABLE_NATPMP */
++#ifdef ENABLE_WSC_SERVICE
++		case 'G':
++			/*enable IGD service*/
++			SETFLAG(ENABLEUPNPMASK);
++			break;
++		case 'I':
++			i++; /* WPSInit will take care of it. */
++			break;
++		case 'n':
++			i++;
++			break;
++#endif /* ENABLE_WSC_SERVICE */
++
+ 		case 'U':
+ 			/*sysuptime = 1;*/
+ 			SETFLAG(SYSUPTIMEMASK);
+@@ -1566,6 +1685,7 @@ init(int argc, char * * argv, struct run
+ 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+ 			break;
+ #ifdef ENABLE_IPV6
++#ifndef ENABLE_WSC_SERVICE
+ 		case 'I':
+ 			if(i+1 < argc)
+ 				ext_if_name6 = argv[++i];
+@@ -1573,6 +1693,7 @@ init(int argc, char * * argv, struct run
+ 				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+ 			break;
+ #endif
++#endif
+ #ifdef USE_PF
+ 		case 'q':
+ 			if(i+1 < argc)
+@@ -1623,7 +1744,7 @@ init(int argc, char * * argv, struct run
+ 			}
+ 			break;
+ #endif	/* ENABLE_NFQUEUE */
+-#ifndef NO_BACKGROUND_NO_PIDFILE
++#if defined(ENABLE_WSC_SERVICE) || !defined(NO_BACKGROUND_NO_PIDFILE)
+ 		case 'P':
+ 			if(i+1 < argc)
+ 				pidfilename = argv[++i];
+@@ -1773,13 +1894,17 @@ init(int argc, char * * argv, struct run
+ 		}
+ 	}
+ 
+-#ifndef NO_BACKGROUND_NO_PIDFILE
++#if defined(ENABLE_WSC_SERVICE) || !defined(NO_BACKGROUND_NO_PIDFILE)
+ 	if(debug_flag)
+ 	{
+ 		pid = getpid();
+ 	}
+ 	else
+ 	{
++#ifdef ENABLE_WSC_SERVICE
++		wsc_debug_level = RT_DBG_OFF;
++#endif /* ENABLE_WSC_SERVICE */
++
+ #ifdef USE_DAEMON
+ 		if(daemon(0, 0)<0) {
+ 			perror("daemon()");
+@@ -1816,7 +1941,7 @@ init(int argc, char * * argv, struct run
+ 		}
+ 	}
+ 
+-#ifndef NO_BACKGROUND_NO_PIDFILE
++#if defined(ENABLE_WSC_SERVICE) || !defined(NO_BACKGROUND_NO_PIDFILE)
+ 	if(checkforrunning(pidfilename) < 0)
+ 	{
+ 		syslog(LOG_ERR, "MiniUPnPd is already running. EXITING");
+@@ -1899,7 +2024,7 @@ init(int argc, char * * argv, struct run
+ #endif
+ #endif
+ 
+-#ifndef NO_BACKGROUND_NO_PIDFILE
++#if defined(ENABLE_WSC_SERVICE) || !defined(NO_BACKGROUND_NO_PIDFILE)
+ 	if(writepidfile(pidfilename, pid) < 0)
+ 		pidfilename = NULL;
+ #endif
+@@ -1946,9 +2071,14 @@ print_usage:
+ #endif
+ 			"\n"
+ 			/*"[-l logfile] " not functionnal */
++#ifdef ENABLE_WSC_SERVICE
++			"\t\t[-u uuid] [-s serial] [-M model_number] \n"
++#else
++			"\t\t[-u uuid] [-s serial] [-m model_number] \n"
++#endif /* ENABLE_WSC_SERVICE */
+ 			"\t\t[-u uuid] [-s serial] [-m model_number] \n"
+ 			"\t\t[-t notify_interval] "
+-#ifndef NO_BACKGROUND_NO_PIDFILE
++#if defined(ENABLE_WSC_SERVICE) || !defined(NO_BACKGROUND_NO_PIDFILE)
+ 			"[-P pid_filename] "
+ #endif
+ #ifdef ENABLE_MANUFACTURER_INFO_CONFIGURATION
+@@ -1968,7 +2098,7 @@ print_usage:
+ 			"\n"
+ 	        "\nNotes:\n\tThere can be one or several listening_ips.\n"
+ 	        "\tNotify interval is in seconds. Default is 30 seconds.\n"
+-#ifndef NO_BACKGROUND_NO_PIDFILE
++#if defined(ENABLE_WSC_SERVICE) || !defined(NO_BACKGROUND_NO_PIDFILE)
+ 			"\tDefault pid file is '%s'.\n"
+ #endif
+ 			"\tDefault config file is '%s'.\n"
+@@ -1992,6 +2122,10 @@ print_usage:
+ 			"\t-q sets the ALTQ queue in pf.\n"
+ 			"\t-T sets the tag name in pf.\n"
+ #endif
++#ifdef ENABLE_WSC_SERVICE
++			"\t-G turns on IGD Device service.\n"
++#endif /* ENABLE_WSC_SERVICE */
++
+ #ifdef ENABLE_NFQUEUE
+ 			"\t-Q sets the queue number that is used by NFQUEUE.\n"
+ 			"\t-n sets the name of the interface(s) that packets will arrive on.\n"
+@@ -2008,7 +2142,7 @@ print_usage:
+ 			"\t-v enables LOG_INFO messages, -vv LOG_DEBUG as well (default with -d)\n"
+ 			"\t-h / --help prints this help and quits.\n"
+ 	        "", argv[0], argv[0], argv[0],
+-#ifndef NO_BACKGROUND_NO_PIDFILE
++#if defined(ENABLE_WSC_SERVICE) || !defined(NO_BACKGROUND_NO_PIDFILE)
+ 			pidfilename,
+ #endif
+ 			DEFAULT_CONFIG);
+@@ -2048,6 +2182,10 @@ main(int argc, char * * argv)
+ 	int sifacewatcher = -1;
+ #endif
+ 
++#ifdef ENABLE_WSC_SERVICE
++	int shttpwpsl = -1;
++#endif /* ENABLE_WSC_SERVICE */
++
+ 	int * snotify = NULL;
+ 	int addr_count;
+ 	LIST_HEAD(httplisthead, upnphttp) upnphttphead;
+@@ -2131,6 +2269,22 @@ main(int argc, char * * argv)
+ 	}
+ #endif
+ 
++#ifdef ENABLE_WSC_SERVICE
++	if (GETFLAG(ENABLEWPSMASK))
++	{
++		if (WPSInit(argc, argv))
++		{
++			DBGPRINTF(RT_DBG_OFF, "WPSInit() ok !\n");
++		}
++		else
++		{
++			DBGPRINTF(RT_DBG_OFF, "WPSInit() failed !\n");
++			CLEARFLAG(ENABLEWPSMASK);
++			return 1;
++		}
++	}
++#endif /* ENABLE_WSC_SERVICE */
++
+ 	LIST_INIT(&upnphttphead);
+ #ifdef USE_MINIUPNPDCTL
+ 	LIST_INIT(&ctllisthead);
+@@ -2138,8 +2292,14 @@ main(int argc, char * * argv)
+ 
+ 	if(
+ #ifdef ENABLE_NATPMP
++#ifdef ENABLE_WSC_SERVICE
++		!GETFLAG(ENABLEWPSMASK) &&
++#endif /* ENABLE_WSC_SERVICE */
+ 	   !GETFLAG(ENABLENATPMPMASK) && !GETFLAG(ENABLEUPNPMASK)
+ #else
++#ifdef ENABLE_WSC_SERVICE
++		!GETFLAG(ENABLEWPSMASK) &&
++#endif /* ENABLE_WSC_SERVICE */
+ 	   !GETFLAG(ENABLEUPNPMASK)
+ #endif
+ 	   ) {
+@@ -2186,6 +2346,33 @@ main(int argc, char * * argv)
+ 		}
+ 	}
+ 
++#ifdef ENABLE_WSC_SERVICE
++	if (GETFLAG(ENABLEWPSMASK))
++	{
++		/* open socket for HTTP connections. Listen on the 1st LAN address */
++#ifdef ENABLE_IPV6
++		shttpwpsl = OpenAndConfHTTPSocket(&WPS_PORT, !GETFLAG(IPV6DISABLEDMASK));
++#else /* ENABLE_IPV6 */
++		shttpwpsl = OpenAndConfHTTPSocket(&WPS_PORT);
++#endif /* ENABLE_IPV6 */
++		if(shttpwpsl < 0)
++		{
++			syslog(LOG_ERR, "Failed to open socket for WPS. EXITING");
++			return 1;
++		}
++		syslog(LOG_ERR, "WPS listening on port %d", WPS_PORT);
++	
++		{
++			int flags;
++	
++			flags = fcntl(netlink_sock, F_GETFL, 0); 
++			if (flags == -1) 
++				return 1; 
++			fcntl(netlink_sock, F_SETFL, flags | O_NONBLOCK);
++		}		
++	}
++#endif /* ENABLE_WSC_SERVICE */
++
+ 	if(GETFLAG(ENABLEUPNPMASK))
+ 	{
+ 		unsigned short listen_port;
+@@ -2328,6 +2515,13 @@ main(int argc, char * * argv)
+ 	sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl");
+ #endif
+ 
++#ifdef ENABLE_WSC_SERVICE
++	if (GETFLAG(ENABLEWPSMASK))
++	{
++		DescDump();
++	}
++#endif /* ENABLE_WSC_SERVICE */
++
+ #ifdef ENABLE_NFQUEUE
+ 	if ( nfqueue != -1 && n_nfqix > 0) {
+ 		nfqh = OpenAndConfNFqueue();
+@@ -2491,7 +2685,15 @@ main(int argc, char * * argv)
+ 		{
+ 			/* the comparaison is not very precise but who cares ? */
+ 			if(timeofday.tv_sec >= (lasttimeofday.tv_sec + v.notify_interval))
+-			{
++			{			
++#ifdef ENABLE_WSC_SERVICE
++				{
++					// how often to verify the timeouts, in seconds
++					// default value is equal to notify interval
++					WscMsgQVerifyTimeouts(v.notify_interval);
++				}
++#endif
++
+ 				if (GETFLAG(ENABLEUPNPMASK))
+ 					SendSSDPNotifies2(snotify,
+ 				                  (unsigned short)v.port,
+@@ -2499,6 +2701,16 @@ main(int argc, char * * argv)
+ 					              (unsigned short)v.https_port,
+ #endif
+ 				                  v.notify_interval << 1);
++
++#ifdef ENABLE_WSC_SERVICE
++				if (GETFLAG(ENABLEWPSMASK))
++				{
++					WSC_SendSSDPNotifies2(snotify,
++						(unsigned short)WPS_PORT,
++						v.notify_interval << 1);
++				}
++#endif /* ENABLE_WSC_SERVICE */
++
+ 				memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval));
+ 				timeout.tv_sec = v.notify_interval;
+ 				timeout.tv_usec = 0;
+@@ -2582,6 +2794,20 @@ main(int argc, char * * argv)
+ 			FD_SET(shttpl, &readset);
+ 			max_fd = MAX( max_fd, shttpl);
+ 		}
++
++#ifdef ENABLE_WSC_SERVICE
++		if(shttpwpsl >= 0)
++		{
++			FD_SET(shttpwpsl, &readset);
++			max_fd = MAX(max_fd, shttpwpsl);
++		}
++		if(netlink_sock >= 0)
++		{
++			FD_SET(netlink_sock, &readset);
++			max_fd = MAX(max_fd, netlink_sock);
++		}
++#endif /* ENABLE_WSC_SERVICE */
++
+ #if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
+ 		if (shttpl_v4 >= 0)
+ 		{
+@@ -2911,13 +3137,64 @@ main(int argc, char * * argv)
+ 		{
+ 			if(e->socket >= 0)
+ 			{
+-				if(FD_ISSET(e->socket, &readset) ||
++				if((FD_ISSET(e->socket, &readset) ||
+ 				   FD_ISSET(e->socket, &writeset))
++#ifdef ENABLE_WSC_SERVICE
++					&& (e->state != DO_NOTHING_IN_MAIN_LOOP)
++#endif
++				)
+ 				{
+ 					Process_upnphttp(e);
+ 				}
+ 			}
+ 		}
++
++#ifdef ENABLE_WSC_SERVICE
++		if (GETFLAG(ENABLEWPSMASK))
++		{
++			/* process incoming HTTP connections */
++			if(shttpwpsl >= 0 && FD_ISSET(shttpwpsl, &readset))
++			{
++				int shttpwps;
++				socklen_t clientnamelen;
++				struct sockaddr_in clientname;
++				clientnamelen = sizeof(struct sockaddr_in);
++				shttpwps = accept(shttpwpsl, (struct sockaddr *)&clientname, &clientnamelen);
++				if (shttpwps<0)
++				{
++					syslog(LOG_ERR, "accept(shttpwpsl): %m");
++				}
++				else
++				{
++					struct upnphttp * tmp = 0;
++					syslog(LOG_ERR, "HTTP connection from %s:%d",
++						inet_ntoa(clientname.sin_addr),
++						ntohs(clientname.sin_port) );
++					/* Create a new upnphttp object and add it to
++					 * the active upnphttp object list */
++					tmp = New_upnphttp(shttpwps);
++					if(tmp)
++					{
++						tmp->clientaddr = clientname.sin_addr;
++						LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
++					}
++					else
++					{
++						syslog(LOG_ERR, "New_upnphttp() failed");
++						close(shttpwps);
++						shttpwps = -1;
++					}
++				}
++			}
++
++			if(FD_ISSET(netlink_sock, &readset))
++			{
++				DBGPRINTF(RT_DBG_LOUD, "(%s):netlink socket data is available now.\n", __FUNCTION__);
++				wscNLSockRecv(netlink_sock);
++			}
++		}
++#endif /* ENABLE_WSC_SERVICE */
++
+ 		/* process incoming HTTP connections */
+ 		if(shttpl >= 0 && FD_ISSET(shttpl, &readset))
+ 		{
+@@ -3036,6 +3313,18 @@ shutdown:
+ 		}
+ 	}
+ #endif
++#ifdef ENABLE_WSC_SERVICE
++	if(shttpwpsl >= 0)
++	{
++		close(shttpwpsl);
++		shttpwpsl = -1;
++	}
++	if(netlink_sock >= 0)
++	{
++		close(netlink_sock);
++		netlink_sock = -1;
++	}
++#endif /* ENABLE_WSC_SERVICE */
+ #if defined(ENABLE_IPV6) && defined(ENABLE_PCP)
+ 	if(spcp_v6 >= 0)
+ 	{
+@@ -3055,6 +3344,22 @@ shutdown:
+ 	}
+ #endif
+ 
++#ifdef ENABLE_WSC_SERVICE
++	if (GETFLAG(ENABLEWPSMASK))
++	{
++		if(WSC_SendSSDPGoodbye(snotify, addr_count) < 0)
++		{
++			syslog(LOG_ERR, "Failed to broadcast good-bye notifications for WSC");
++		}
++	}
++	
++	if (!(GETFLAG(ENABLEUPNPMASK)))
++	{
++		for(i=0; i<addr_count; i++)
++			close(snotify[i]);
++	}
++#endif /* ENABLE_WSC_SERVICE */
++
+ 	if (GETFLAG(ENABLEUPNPMASK))
+ 	{
+ #ifndef ENABLE_IPV6
+@@ -3066,7 +3371,7 @@ shutdown:
+ 	}
+ 
+ 	/* remove pidfile */
+-#ifndef NO_BACKGROUND_NO_PIDFILE
++#if defined(ENABLE_WSC_SERVICE) || !defined(NO_BACKGROUND_NO_PIDFILE)
+ 	if(pidfilename && (unlink(pidfilename) < 0))
+ 	{
+ 		syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename);
+@@ -3096,6 +3401,17 @@ shutdown:
+ 	freeoptions();
+ #endif
+ 	closelog();
++#ifdef ENABLE_WSC_SERVICE
++	CLEARFLAG(ENABLEWPSMASK);
++	DBGPRINTF(RT_DBG_INFO, "wscSystemStop()...\n");
++	wscSystemStop();
++	
++#if 1 // def MULTIPLE_CARD_SUPPORT
++	unlink(pid_file_path);
++#else
++	unlink(DEFAULT_PID_FILE_PATH);
++#endif // MULTIPLE_CARD_SUPPORT //
++#endif /* ENABLE_WSC_SERVICE */
+ 	return 0;
+ }
+ 
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/miniupnpdpath.h
+===================================================================
+--- a/miniupnpdpath.h
++++ b/miniupnpdpath.h
+@@ -14,6 +14,13 @@
+ 
+ #define ROOTDESC_PATH 		"/rootDesc.xml"
+ 
++#ifdef ENABLE_WSC_SERVICE
++#define WFA_ROOTDESC_PATH 	"/WFADeviceDesc.xml"
++#define WSC_PATH			"/WFAWLANConfigSCPD.xml"
++#define WSC_CONTROLURL		"/control"
++#define WSC_EVENTURL		"/event"
++#endif /* ENABLE_WSC_SERVICE */
++
+ #ifdef HAS_DUMMY_SERVICE
+ #define DUMMY_PATH			"/dummy.xml"
+ #endif
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/upnpdescgen.c
+===================================================================
+--- a/upnpdescgen.c
++++ b/upnpdescgen.c
+@@ -23,7 +23,15 @@
+ #include "upnpurns.h"
+ #include "getconnstatus.h"
+ 
+-
++#ifdef ENABLE_WSC_SERVICE
++#include "upnphttp.h"		/* For wscLocalDevice */
++#include "wsc/wsc_upnp.h"
++#endif /* ENABLE_WSC_SERVICE */
++
++#ifdef ENABLE_WSC_SERVICE
++//Default WSC service magical value
++#define WSCSERVICE_MAGICALVALUE (247)
++#endif
+ /* Event magical values codes */
+ #define SETUPREADY_MAGICALVALUE (248)
+ #define CONNECTIONSTATUS_MAGICALVALUE (249)
+@@ -34,6 +42,10 @@
+ #define EXTERNALIPADDRESS_MAGICALVALUE (254)
+ #define DEFAULTCONNECTIONSERVICE_MAGICALVALUE (255)
+ 
++#ifdef ENABLE_WSC_SERVICE
++/* The data structure used the save the local Wsc UPnP Device. */
++//extern struct upnpDevice wscLocalDevice;
++#endif /* ENABLE_WSC_SERVICE */
+ 
+ static const char * const upnptypes[] =
+ {
+@@ -41,6 +53,9 @@ static const char * const upnptypes[] =
+ 	"boolean",
+ 	"ui2",
+ 	"ui4",
++#ifdef ENABLE_WSC_SERVICE //Mediatek :  be care that original code 4 => bin.base64, but portig code 4 => ui1
++	"ui1",
++#endif
+ 	"bin.base64"
+ };
+ 
+@@ -94,7 +109,11 @@ static const char * const upnpallowedval
+  * ERROR_IP_CONFIGURATION
+  * ERROR_UNKNOWN */
+ 	0,
+-	"",		/* 27 */
++	"",		/* 27 */	
++#ifdef ENABLE_WSC_SERVICE
++	0,
++	"0",	/* 29 */
++#endif /* ENABLE_WSC_SERVICE */
+ 	0
+ };
+ 
+@@ -132,6 +151,13 @@ static const char * magicargname[] = {
+ #endif /* ENABLE_DP_SERVICE */
+ };
+ 
++/* it seems fine to use xmlver instead of wps_xmlver */
++#ifdef ENABLE_WSC_SERVICE
++/* it seems fine to use xmlver instead of wps_xmlver in service description */
++static const char wps_xmlver[] = 
++	"<?xml version=\"1.0\" encoding=\"utf-8\"?>";
++#endif /* ENABLE_WSC_SERVICE */
++
+ static const char xmlver[] =
+ 	"<?xml version=\"1.0\"?>\r\n";
+ static const char root_service[] =
+@@ -317,6 +343,41 @@ static const struct XMLElt rootDesc[] =
+ 	{0, 0}
+ };
+ 
++#ifdef ENABLE_WSC_SERVICE
++static const struct XMLElt WFArootDesc[] =
++{
++/* 0 */
++	{root_device, INITHELPER(1,2)},
++	{"specVersion", INITHELPER(3,2)},
++	{"device", INITHELPER(5,11)},
++
++	{"/major", "1"},
++	{"/minor", "0"},
++/* 5 */
++	{"/deviceType", "urn:schemas-wifialliance-org:device:WFADevice:1"},
++	{"/friendlyName", WLANDEV_FRIENDLYNAME},
++	{"/manufacturer", WLANDEV_MANUFACTURER},
++	{"/manufacturerURL", WLANDEV_MANUFACTURERURL},
++	{"/modelDescription", WLANDEV_MODELDESCRIPTION},
++	{"/modelName", WLANDEV_MODELNAME},
++	{"/modelNumber", WLANDEV_MODELNUMBER},
++	{"/modelURL", WLANDEV_MODELURL},
++	{"/serialNumber", wps_serialnumber},
++	{"/UDN", wps_uuidvalue},
++/* 15 */	
++	{"serviceList", INITHELPER(16,1)},
++/* 16 */
++	{"service", INITHELPER(17,5)},
++/* 17 */	
++	{"/serviceType", "urn:schemas-wifialliance-org:service:WFAWLANConfig:1"},
++	{"/serviceId", "urn:wifialliance-org:serviceId:WFAWLANConfig1"},
++	{"/SCPDURL", "WFAWLANConfigSCPD.xml"},
++	{"/controlURL", "control"},
++	{"/eventSubURL", "event"},
++	{0, 0}
++};
++#endif
++
+ /* WANIPCn.xml */
+ /* see UPnP_IGD_WANIPConnection 1.0.pdf
+ static struct XMLElt scpdWANIPCn[] =
+@@ -789,7 +850,12 @@ static const struct stateVar DPVars[] =
+ 	{"A_ARG_TYPE_ACL", 0},
+ 	{"A_ARG_TYPE_IdentityList", 0},
+ 	{"A_ARG_TYPE_Identity", 0},
++	//Mediatek :	be care origianl ver 1.2 poritng , 4 => ui1, 5 => bin.base64
++#ifdef ENABLE_WSC_SERVICE
++	{"A_ARG_TYPE_Base64", 5},
++#else
+ 	{"A_ARG_TYPE_Base64", 4},
++#endif
+ 	{"A_ARG_TYPE_String", 0},
+ 	{0, 0}
+ };
+@@ -798,6 +864,139 @@ static const struct serviceDesc scpdDP =
+ { DPActions, DPVars };
+ #endif
+ 
++#ifdef ENABLE_WSC_SERVICE
++static const struct argument GetDeviceInfoArgs[] =
++{
++	{2, 3}, /* out */
++	{0, 0}
++};
++
++static const struct argument PutMessageArgs[] =
++{
++	{1, 1}, /* in */
++	{2, 2}, /* out */
++	{0, 0}
++};
++
++static const struct argument GetAPSettingsArgs[] =
++{
++	{1, 0}, /* in */
++	{2, 4}, /* out */
++	{0, 0}
++};
++
++
++static const struct argument SetAPSettingsArgs[] =
++{
++	{1, 4}, /* in */
++	{0, 0}
++};
++
++static const struct argument DelAPSettingsArgs[] =
++{
++	{1, 4}, /* in */
++	{0, 0}
++};
++
++static const struct argument GetSTASettingsArgs[] =
++{
++	{1, 0}, /* in */
++	{2, 6}, /* out */
++	{0, 0}
++};
++
++static const struct argument SetSTASettingsArgs[] =
++{
++	{2, 6}, /* in */
++	{0, 0}
++};
++
++static const struct argument DelSTASettingsArgs[] =
++{
++	{1, 6}, /* in */
++	{0, 0}
++};
++
++static const struct argument PutWLANResponseArgs[] =
++{
++	{1, 0}, /* in */
++	{1, 9}, /* in */
++	{1, 10}, /* in */
++	{0, 0}
++};
++
++static const struct argument RebootAPArgs[] =
++{
++	{1, 4}, /* in */
++	{0, 0}
++};
++
++static const struct argument ResetAPArgs[] =
++{
++	{1, 0}, /* in */
++	{0, 0}
++};
++
++static const struct argument RebootSTAArgs[] =
++{
++	{1, 6}, /* in */
++	{0, 0}
++};
++
++static const struct argument ResetSTAArgs[] =
++{
++	{1, 0}, /* in */
++	{0, 0}
++};
++
++static const struct argument SetSelectedRegistrarArgs[] =
++{
++	{1, 0}, /* in */
++	{0, 0}
++};
++
++static const struct action WSCActions[] =
++{
++	{"DelAPSettings", DelAPSettingsArgs},
++	{"DelSTASettings", DelSTASettingsArgs},
++	{"GetAPSettings", GetAPSettingsArgs},
++	{"GetDeviceInfo", GetDeviceInfoArgs},
++	{"GetSTASettings", GetSTASettingsArgs},
++	{"PutMessage", PutMessageArgs},
++	{"PutWLANResponse", PutWLANResponseArgs},
++	{"RebootAP", RebootAPArgs},
++	{"RebootSTA", RebootSTAArgs},
++	{"ResetAP", ResetAPArgs},
++	{"ResetSTA", ResetSTAArgs},
++	{"SetAPSettings", SetAPSettingsArgs},
++	{"SetSelectedRegistrar", SetSelectedRegistrarArgs},
++	{"SetSTASettings", SetSTASettingsArgs},
++	{0, 0}
++};
++
++/* See WFA WLANConfig 1.0.pdf */
++static const struct stateVar WSCVars[] =
++{
++	{"Message", 5, 0, 0, 0},	/* Required */
++	{"InMessage", 5, 0, 0, 0},	/* Required */
++	{"OutMessage", 5, 0, 0, 0},	/* Required */
++	{"DeviceInfo", 5, 0, 0, 0},	/* Required */
++	{"APSettings", 5, 0, 0, 0},	   /* Conditional */
++	{"WLANEvent", 5|0x80, 0, 0, WSCSERVICE_MAGICALVALUE},    /* Conditional */ /*Mediatek :  change magic value from 252 to WSCSERVICE_MAGICALVALUE*/
++	{"STASettings", 5, 0, 0, 0},    /* Conditional */
++	{"APStatus", 4|0x80, 0, 0, WSCSERVICE_MAGICALVALUE},  /* Conditional */
++	{"STAStatus", 4|0x80, 0, 0, WSCSERVICE_MAGICALVALUE},    /* Conditional */
++	{"WLANEventType", 4, 0, 0, 0},    /* Conditional */
++	{"WLANEventMAC", 0, 0, 0, 0},    /* Conditional */
++	{"WLANResponse", 5, 0, 0, 0},    /* Conditional */
++	{0, 0}
++};
++
++static const struct serviceDesc scpdWSC =
++{ WSCActions, WSCVars };
++#endif /* ENABLE_WSC_SERVICE */
++
++
+ /* strcat_str()
+  * concatenate the string and use realloc to increase the
+  * memory buffer if needed. */
+@@ -997,6 +1196,31 @@ genXML(char * str, int * len, int * tmpl
+ 	}
+ }
+ 
++#ifdef ENABLE_WSC_SERVICE
++/* genRootDesc() :
++ * - Generate the root description of the UPnP device.
++ * - the len argument is used to return the length of
++ *   the returned string. 
++ * - tmp_uuid argument is used to build the uuid string */
++char *
++genWSCRootDesc(int * len)
++{
++	char * str;
++	int tmplen;
++
++	tmplen = 2048;
++	str = (char *)malloc(tmplen);
++	if(str == NULL)
++		return NULL;
++	*len = strlen(wps_xmlver);
++	/*strcpy(str, xmlver); */
++	memcpy(str, wps_xmlver, *len + 1);
++	str = genXML(str, len, &tmplen, WFArootDesc);
++	str[*len] = '\0';
++	return str;
++}
++#endif /* ENABLE_WSC_SERVICE */
++
+ /* genRootDesc() :
+  * - Generate the root description of the UPnP device.
+  * - the len argument is used to return the length of
+@@ -1186,6 +1410,14 @@ genWANIPCn(int * len)
+ 	return genServiceDesc(len, &scpdWANIPCn);
+ }
+ 
++#ifdef ENABLE_WSC_SERVICE
++char *
++genWSC(int * len)
++{
++	return genServiceDesc(len, &scpdWSC);
++}
++#endif /* ENABLE_WSC_SERVICE */
++
+ /* genWANCfg() :
+  * Generate the WANInterfaceConfig xml description. */
+ char *
+@@ -1227,6 +1459,10 @@ genEventVars(int * len, const struct ser
+ 	char * str;
+ 	int tmplen;
+ 	tmplen = 512;
++#ifdef ENABLE_WSC_SERVICE
++	int var_index = 0;	
++#endif /* ENABLE_WSC_SERVICE */
++
+ 	str = (char *)malloc(tmplen);
+ 	if(str == NULL)
+ 		return NULL;
+@@ -1242,6 +1478,16 @@ genEventVars(int * len, const struct ser
+ 			switch(v->ieventvalue) {
+ 			case 0:
+ 				break;
++				
++#ifdef ENABLE_WSC_SERVICE
++			case WSCSERVICE_MAGICALVALUE:	/* Default WSC service magical value */
++				printf("update Event Vars :%s == %s\n", v->name, wscLocalDevice.services.StateVarVal[var_index]);
++				/* WSC_EVENT_WLANEVENT : 0; WSC_EVENT_APSTATUS : 1; WSC_EVENT_STASTATUS : 2 */
++				str = strcat_str(str, len, &tmplen, wscLocalDevice.services.StateVarVal[var_index]);
++				var_index += 1;
++				break;
++#endif /* ENABLE_WSC_SERVICE */
++
+ #ifdef ENABLE_DP_SERVICE
+ 			case SETUPREADY_MAGICALVALUE:
+ 				/* always ready for setup */
+@@ -1367,4 +1613,15 @@ getVarsDP(int * l)
+ }
+ #endif
+ 
++#ifdef ENABLE_WSC_SERVICE
++char *
++getVarsWSC(int * l)
++{
++
++	return genEventVars(l,
++	                    &scpdWSC
++	                    /*,WscServiceTypeStr*/);
++}
++#endif /* ENABLE_WSC_SERVICE */
++
+ #endif /* ENABLE_EVENTS */
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/upnpdescgen.h
+===================================================================
+--- a/upnpdescgen.h
++++ b/upnpdescgen.h
+@@ -55,6 +55,17 @@ struct stateVar {
+ char *
+ genRootDesc(int * len);
+ 
++#ifdef ENABLE_WSC_SERVICE
++/* The data structure used the save the local Wsc UPnP Device. */
++//extern struct upnpDevice wscLocalDevice;	
++
++char *
++genWSCRootDesc(int * len);
++
++char *
++genWSC(int * len);
++#endif /* ENABLE_WSC_SERVICE */
++
+ /* for the two following functions */
+ char *
+ genWANIPCn(int * len);
+@@ -96,6 +107,10 @@ getVars6FC(int * len);
+ char *
+ getVarsDP(int * len);
+ #endif
++#ifdef ENABLE_WSC_SERVICE
++char *
++getVarsWSC(int * len);
++#endif /* ENABLE_WSC_SERVICE */
+ #endif /* ENABLE_EVENTS */
+ 
+ #endif
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/upnpdescstrings.h
+===================================================================
+--- a/upnpdescstrings.h
++++ b/upnpdescstrings.h
+@@ -37,5 +37,17 @@
+ #define WANCDEV_UPC					"000000000000"
+ /* UPC is 12 digit (barcode) */
+ 
++#ifdef ENABLE_WSC_SERVICE
++#define WLANDEV_FRIENDLYNAME		"MediatekAPS"
++#define WLANDEV_MANUFACTURER		"Mediatek Technology, Corp."
++#define WLANDEV_MANUFACTURERURL		"http://www.mediatek.com"
++#define WLANDEV_MODELNAME			"Mediatek Wireless Access Point"
++#define WLANDEV_MODELDESCRIPTION	"Mediatek AP WPS device"
++//Mediatek :  need to modified
++#define WLANDEV_MODELNUMBER			"RT3062"
++#define WLANDEV_MODELURL			"http://www.mediatek.com"
++//#define WLANDEV_UPC					"MINIUPNPD"
++#endif /* ENABLE_WSC_SERVICE */
++
+ #endif
+ 
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/upnpevents.c
+===================================================================
+--- a/upnpevents.c
++++ b/upnpevents.c
+@@ -32,6 +32,11 @@
+ #include "upnpdescgen.h"
+ #include "upnputils.h"
+ 
++#ifdef ENABLE_WSC_SERVICE
++#include "wsc/wsc_common.h"
++#include "wsc/wsc_upnp.h"/* for wscLocalDevice */
++#endif /* ENABLE_WSC_SERVICE */
++
+ #ifdef ENABLE_EVENTS
+ /*enum subscriber_service_enum {
+  EWanCFG = 1,
+@@ -39,6 +44,7 @@
+  EL3F
+ };*/
+ 
++#if 0
+ /* stuctures definitions */
+ struct subscriber {
+ 	LIST_ENTRY(subscriber) entries;
+@@ -49,6 +55,7 @@ struct subscriber {
+ 	char uuid[42];
+ 	char callback[];
+ };
++#endif
+ 
+ struct upnp_event_notify {
+ 	LIST_ENTRY(upnp_event_notify) entries;
+@@ -75,7 +82,10 @@ struct upnp_event_notify {
+ };
+ 
+ /* prototypes */
+-static void
++#ifndef ENABLE_WSC_SERVICE
++static
++#endif
++void
+ upnp_event_create_notify(struct subscriber * sub);
+ 
+ /* Subscriber list */
+@@ -110,6 +120,10 @@ newSubscriber(const char * eventurl, con
+ 	else if(strcmp(eventurl, DP_EVENTURL)==0)
+ 		tmp->service = EDP;
+ #endif
++#ifdef ENABLE_WSC_SERVICE
++	else if(strcmp(eventurl, WSC_EVENTURL)==0)
++		tmp->service = EWSC;
++#endif /* ENABLE_WSC_SERVICE */
+ 	else {
+ 		free(tmp);
+ 		return NULL;
+@@ -148,7 +162,14 @@ newSubscriber(const char * eventurl, con
+ 			}
+ 		}
+ 		if(status != uuid_s_ok) {
+-			/* make a dummy uuid */
++			/* make a dummy uuid */	
++#ifdef ENABLE_WSC_SERVICE
++			if (tmp->service == EWSC)
++			{
++				strncpy(tmp->uuid, wps_uuidvalue, sizeof(tmp->uuid));
++			}
++			else
++#endif /* ENABLE_WSC_SERVICE */
+ 			strncpy(tmp->uuid, uuidvalue_igd, sizeof(tmp->uuid));
+ 			tmp->uuid[sizeof(tmp->uuid)-1] = '\0';
+ 			snprintf(tmp->uuid+sizeof(tmp->uuid)-5, 5, "%04lx", random() & 0xffff);
+@@ -156,6 +177,13 @@ newSubscriber(const char * eventurl, con
+ 	}
+ #else
+ 	/* make a dummy uuid */
++#ifdef ENABLE_WSC_SERVICE
++	if (tmp->service == EWSC)
++	{
++		strncpy(tmp->uuid, wps_uuidvalue, sizeof(tmp->uuid));
++	}
++	else
++#endif /* ENABLE_WSC_SERVICE */
+ 	strncpy(tmp->uuid, uuidvalue_igd, sizeof(tmp->uuid));
+ 	tmp->uuid[sizeof(tmp->uuid)-1] = '\0';
+ 	snprintf(tmp->uuid+sizeof(tmp->uuid)-5, 5, "%04lx", random() & 0xffff);
+@@ -233,6 +261,15 @@ void
+ upnp_event_var_change_notify(enum subscriber_service_enum service)
+ {
+ 	struct subscriber * sub;
++	
++#ifdef RT_DEBUG
++	sub = subscriberlist.lh_first;
++	if (sub == NULL)
++	{
++		DBGPRINTF(RT_DBG_INFO, "\n--------------subscriberlist is empty !!!--------------\n");
++	}
++#endif /* RT_DEBUG */
++
+ 	for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
+ 		if(sub->service == service && sub->notify == NULL)
+ 			upnp_event_create_notify(sub);
+@@ -240,7 +277,10 @@ upnp_event_var_change_notify(enum subscr
+ }
+ 
+ /* create and add the notify object to the list */
+-static void
++#ifndef ENABLE_WSC_SERVICE
++static 
++#endif
++void
+ upnp_event_create_notify(struct subscriber * sub)
+ {
+ 	struct upnp_event_notify * obj;
+@@ -418,6 +458,11 @@ static void upnp_event_prepare(struct up
+ 		return;
+ 	}
+ 	switch(obj->sub->service) {
++#ifdef ENABLE_WSC_SERVICE
++	case EWSC:
++		xml = getVarsWSC(&l);
++		break;
++#endif /* ENABLE_WSC_SERVICE */
+ 	case EWanCFG:
+ 		xml = getVarsWANCfg(&l);
+ 		break;
+@@ -443,7 +488,12 @@ static void upnp_event_prepare(struct up
+ 		xml = NULL;
+ 		l = 0;
+ 	}
++//Mediatek : Need to increase the buffer, or the payload may be cut!
++#ifdef ENABLE_WSC_SERVICE
++	obj->buffersize = 2000;// 1024 ==> 2000 (confirmed : 1024 is not enough)
++#else
+ 	obj->buffersize = 1024;
++#endif
+ 	for (;;) {
+ 		obj->buffer = malloc(obj->buffersize);
+ 		if(!obj->buffer) {
+@@ -686,5 +736,28 @@ void write_events_details(int s) {
+ }
+ #endif
+ 
++#ifdef ENABLE_WSC_SERVICE
++int 
++WscDevSubscriberSearch(
++	char *SubsId,
++	struct subscriber ** sub)
++{
++	int found = 0;
++
++	*sub = subscriberlist.lh_first;
++
++	while (*sub)
++	{
++		if (memcmp(SubsId, (*sub)->uuid, 41) == 0)
++		{
++			found = 1;
++			break;
++		}
++		*sub = (*sub)->entries.le_next;
++	}
++
++	return found;
++}
++#endif /* ENABLE_WSC_SERVICE */
+ #endif
+ 
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/upnpevents.h
+===================================================================
+--- a/upnpevents.h
++++ b/upnpevents.h
+@@ -25,6 +25,21 @@ enum subscriber_service_enum {
+ #ifdef ENABLE_DP_SERVICE
+  EDP,
+ #endif
++#ifdef ENABLE_WSC_SERVICE
++ EWSC,
++#endif
++};
++
++//Mediatek : move from to upnpevents.c
++/* stuctures definitions */
++struct subscriber {
++	LIST_ENTRY(subscriber) entries;
++	struct upnp_event_notify * notify;
++	time_t timeout;
++	uint32_t seq;
++	enum subscriber_service_enum service;
++	char uuid[42];
++	char callback[];
+ };
+ 
+ void
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/upnpglobalvars.c
+===================================================================
+--- a/upnpglobalvars.c
++++ b/upnpglobalvars.c
+@@ -64,6 +64,11 @@ char uuidvalue_wan[] = "uuid:00000000-00
+ char uuidvalue_wcd[] = "uuid:00000000-0000-0000-0000-000000000000";
+ char serialnumber[SERIALNUMBER_MAX_LEN] = "00000000";
+ 
++#ifdef ENABLE_WSC_SERVICE
++char wps_uuidvalue[] = "uuid:00000000-0000-0000-0000-000000000000";
++char wps_serialnumber[SERIALNUMBER_MAX_LEN] = "87654321";
++#endif /* ENABLE_WSC_SERVICE */
++
+ char modelnumber[MODELNUMBER_MAX_LEN] = "1";
+ 
+ /* presentation url :
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/upnpglobalvars.h
+===================================================================
+--- a/upnpglobalvars.h
++++ b/upnpglobalvars.h
+@@ -31,6 +31,9 @@ extern uint16_t ext_stun_port;
+ extern const char * lease_file;
+ #endif
+ 
++#define FILE_PATH_LEN	256
++extern char pid_file_path[FILE_PATH_LEN];
++
+ /* forced ip address to use for this interface
+  * when NULL, getifaddr() is used */
+ extern const char * use_ext_ip_addr;
+@@ -86,6 +89,13 @@ extern int runtime_flags;
+ 
+ #define EXTIPRESERVEDIGNOREMASK 0x2000
+ 
++#ifdef ENABLE_WSC_SERVICE
++#define ENABLEWPSMASK		0x8000
++
++extern char wps_uuidvalue[];
++extern char wps_serialnumber[];
++#endif /* ENABLE_WSC_SERVICE */
++
+ #define SETFLAG(mask)	runtime_flags |= mask
+ #define GETFLAG(mask)	(runtime_flags & mask)
+ #define CLEARFLAG(mask)	runtime_flags &= ~mask
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/upnphttp.c
+===================================================================
+--- a/upnphttp.c
++++ b/upnphttp.c
+@@ -749,6 +749,10 @@ ProcessHttpQuery_upnphttp(struct upnphtt
+ 		char * (* f)(int *);
+ 	} path_desc[] = {
+ 		{ ROOTDESC_PATH, genRootDesc},
++#ifdef ENABLE_WSC_SERVICE
++		{ WFA_ROOTDESC_PATH, genWSCRootDesc},
++		{ WSC_PATH, genWSC},
++#endif
+ 		{ WANIPC_PATH, genWANIPCn},
+ 		{ WANCFG_PATH, genWANCfg},
+ #ifdef HAS_DUMMY_SERVICE
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/upnphttp.h
+===================================================================
+--- a/upnphttp.h
++++ b/upnphttp.h
+@@ -18,11 +18,19 @@
+ #include <openssl/ssl.h>
+ #endif /* ENABLE_HTTPS */
+ 
++#ifdef ENABLE_WSC_SERVICE
++#include "wsc/wsc_upnp.h"
++#endif
++
+ #define UPNP_VERSION_STRING "UPnP/" UPNP_VERSION_MAJOR_STR "." UPNP_VERSION_MINOR_STR
+ 
+ /* server: HTTP header returned in all HTTP responses : */
+ #define MINIUPNPD_SERVER_STRING	OS_VERSION " " UPNP_VERSION_STRING " MiniUPnPd/" MINIUPNPD_VERSION
+ 
++#ifdef ENABLE_WSC_SERVICE
++struct upnpDevice wscLocalDevice;	// The data structure used the save the local Wsc UPnP Device.
++#endif
++
+ /*
+  states :
+   0 - waiting for data to read
+@@ -34,7 +42,10 @@ enum httpStates {
+ 	EWaitingForHttpRequest = 0,
+ 	EWaitingForHttpContent,
+ 	ESendingContinue,
+-	ESendingAndClosing,
++	ESendingAndClosing,	
++#ifdef ENABLE_WSC_SERVICE
++	DO_NOTHING_IN_MAIN_LOOP,
++#endif
+ 	EToDelete = 100
+ };
+ 
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/upnpsoap.c
+===================================================================
+--- a/upnpsoap.c
++++ b/upnpsoap.c
+@@ -45,7 +45,10 @@ static int is_numeric(const char * s)
+ 	return 1;
+ }
+ 
+-static void
++#ifndef ENABLE_WSC_SERVICE
++static
++#endif
++void
+ BuildSendAndCloseSoapResp(struct upnphttp * h,
+                           const char * body, int bodylen)
+ {
+@@ -2137,6 +2140,31 @@ GetPinholePackets(struct upnphttp * h, c
+ }
+ #endif
+ 
++#ifdef ENABLE_WSC_SERVICE
++static const struct 
++{
++	const char * methodName; 
++	int (*methodImpl)(IN struct upnphttp *, IN uint32, OUT IXML_Document *, OUT char **);
++}
++soapActions[] =
++{
++	{ "GetDeviceInfo", WscDevGetDeviceInfo},
++	{ "PutMessage", WscDevPutMessage},
++	{ "GetAPSettings", WscDevGetAPSettings},
++	{ "SetAPSettings", WscDevSetAPSettings},
++	{ "DelAPSettings", WscDevDelAPSettings},
++	{ "GetSTASettings", WscDevGetSTASettings},
++	{ "SetSTASettings", WscDevSetSTASettings},
++	{ "PutWLANResponse", WscDevPutWLANResponse},
++	{ "RebootAP", WscDevRebootAP},
++	{ "ResetAP", WscDevResetAP},
++	{ "RebootSTA", WscDevRebootSTA},
++	{ "ResetSTA", WscDevResetSTA},
++	{ "SetSelectedRegistrar", WscDevSetSelectedRegistrar},
++	{ 0, 0 }
++};
++#endif /* ENABLE_WSC_SERVICE */
++
+ #ifdef ENABLE_DP_SERVICE
+ static void
+ SendSetupMessage(struct upnphttp * h, const char * action, const char * ns)
+@@ -2310,9 +2338,33 @@ ExecuteSoapAction(struct upnphttp * h, c
+ 	int i, len, methodlen;
+ 	char namespace[256];
+ 
++#ifdef ENABLE_WSC_SERVICE
++	char *error_string = NULL;
++	int retCode = -1;
++	int pos=0;
++#endif /* ENABLE_WSC_SERVICE */
++
+ 	/* SoapAction example :
+ 	 * urn:schemas-upnp-org:service:WANIPConnection:1#GetStatusInfo */
+ 	p = strchr(action, '#');
++
++#ifdef RT_DEBUG
++	if (p == NULL)
++	{
++		printf("\n------h->req_soapActionLen = %d------\n", h->req_soapActionLen);
++	}
++#endif
++
++#ifdef ENABLE_WSC_SERVICE
++	/* fix a bug about extracting out the action handler name */
++	/* skip string terminator while extracting */
++	while (p == NULL)
++	{
++		++pos;
++		p = strchr(&action[pos], '#');
++	}
++#endif /* ENABLE_WSC_SERVICE */
++
+ 	if(p && (p - action) < n) {
+ 		for(i = 0; i < ((int)sizeof(namespace) - 1) && (action + i) < p; i++)
+ 			namespace[i] = action[i];
+@@ -2336,6 +2388,33 @@ ExecuteSoapAction(struct upnphttp * h, c
+ 				return;
+ 			}
+ 		}
++		
++#ifdef ENABLE_WSC_SERVICE
++		if (GETFLAG(ENABLEWPSMASK))
++		{
++			i=0;
++			while(soapActions[i].methodName)
++			{
++				len = strlen(soapActions[i].methodName);
++				if(strncmp(p, soapActions[i].methodName, len) == 0)
++				{
++
++					IXML_Document resp_node = NULL;
++
++					retCode = soapActions[i].methodImpl(h,
++						h->clientaddr.s_addr, &resp_node, &error_string);
++
++					if ((error_string) == NULL)
++					{
++						ASSERT(retCode == 0);
++					}
++
++					return;
++				}
++				i++;
++			}
++		}
++#endif /* ENABLE_WSC_SERVICE */
+ 		syslog(LOG_NOTICE, "SoapMethod: Unknown: %.*s %s", methodlen, p, namespace);
+ 	} else {
+ 		syslog(LOG_NOTICE, "cannot parse SoapAction");
+Index: lede/build_dir/target-aarch64_cortex-a53_musl/miniupnpd-2.2.1/upnpsoap.h
+===================================================================
+--- a/upnpsoap.h
++++ b/upnpsoap.h
+@@ -19,5 +19,89 @@ ExecuteSoapAction(struct upnphttp *, con
+ void
+ SoapError(struct upnphttp * h, int errCode, const char * errDesc);
+ 
++#ifdef ENABLE_WSC_SERVICE
++#include "wsc/wsc_common.h"
++#include "wsc/wsc_msg.h"
++
++extern int
++WscDevGetAPSettings(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++    OUT IXML_Document * out,
++    OUT char **errorString );
++extern int
++WscDevGetSTASettings(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++extern int
++WscDevSetAPSettings(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++extern int
++WscDevDelAPSettings(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++extern int
++WscDevSetSTASettings(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++extern int
++WscDevRebootAP(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++extern int 
++WscDevResetAP(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++extern int
++WscDevRebootSTA(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++extern int
++WscDevResetSTA(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++extern int 
++WscDevSetSelectedRegistrar(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++extern int
++WscDevPutWLANResponse(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++extern int 
++WscDevPutMessage(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++extern int
++WscDevGetDeviceInfo(
++	IN struct upnphttp * h,
++	IN uint32 ipAddr,
++	OUT IXML_Document * out,
++	OUT char **errorString);
++#endif /* ENABLE_WSC_SERVICE */
++
+ #endif
+ 
