1 /* $Id: upnpdescgen.c,v 1.50 2009/02/12 23:12:38 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2008 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
14 #include "getifaddr.h"
15 #include "upnpredirect.h"
17 #include "upnpdescgen.h"
18 #include "miniupnpdpath.h"
19 #include "upnpglobalvars.h"
20 #include "upnpdescstrings.h"
22 static const char * const upnptypes
[] =
30 static const char * const upnpdefaultvalues
[] =
36 static const char * const upnpallowedvalues
[] =
52 "Unconfigured", /* 14 */
56 "Unconfigured", /* 18 */
63 "ERROR_NONE", /* 25 */
69 static const char xmlver
[] =
70 "<?xml version=\"1.0\"?>\r\n";
71 static const char root_service
[] =
72 "scpd xmlns=\"urn:schemas-upnp-org:service-1-0\"";
73 static const char root_device
[] =
74 "root xmlns=\"urn:schemas-upnp-org:device-1-0\"";
76 /* root Description of the UPnP Device
77 * fixed to match UPnP_IGD_InternetGatewayDevice 1.0.pdf
78 * presentationURL is only "recommended" but the router doesn't appears
79 * in "Network connections" in Windows XP if it is not present. */
80 static const struct XMLElt rootDesc
[] =
83 {root_device
, INITHELPER(1,2)},
84 {"specVersion", INITHELPER(3,2)},
85 #if defined(ENABLE_L3F_SERVICE) || defined(HAS_DUMMY_SERVICE)
86 {"device", INITHELPER(5,13)},
88 {"device", INITHELPER(5,12)},
93 {"/deviceType", "urn:schemas-upnp-org:device:InternetGatewayDevice:1"},
94 {"/friendlyName", ROOTDEV_FRIENDLYNAME
}, /* required */
95 {"/manufacturer", ROOTDEV_MANUFACTURER
}, /* required */
97 {"/manufacturerURL", ROOTDEV_MANUFACTURERURL
}, /* optional */
98 {"/modelDescription", ROOTDEV_MODELDESCRIPTION
}, /* recommended */
99 {"/modelName", ROOTDEV_MODELNAME
}, /* required */
100 {"/modelNumber", modelnumber
},
101 {"/modelURL", ROOTDEV_MODELURL
},
102 {"/serialNumber", serialnumber
},
103 {"/UDN", uuidvalue
}, /* required */
104 #if defined(ENABLE_L3F_SERVICE) || defined(HAS_DUMMY_SERVICE)
105 {"serviceList", INITHELPER(57,1)},
106 {"deviceList", INITHELPER(18,1)},
107 {"/presentationURL", presentationurl
}, /* recommended */
109 {"deviceList", INITHELPER(18,1)},
110 {"/presentationURL", presentationurl
}, /* recommended */
114 {"device", INITHELPER(19,13)},
116 {"/deviceType", "urn:schemas-upnp-org:device:WANDevice:1"}, /* required */
117 {"/friendlyName", WANDEV_FRIENDLYNAME
},
118 {"/manufacturer", WANDEV_MANUFACTURER
},
119 {"/manufacturerURL", WANDEV_MANUFACTURERURL
},
120 {"/modelDescription" , WANDEV_MODELDESCRIPTION
},
121 {"/modelName", WANDEV_MODELNAME
},
122 {"/modelNumber", WANDEV_MODELNUMBER
},
123 {"/modelURL", WANDEV_MODELURL
},
124 {"/serialNumber", serialnumber
},
126 {"/UPC", WANDEV_UPC
},
128 {"serviceList", INITHELPER(32,1)},
129 {"deviceList", INITHELPER(38,1)},
131 {"service", INITHELPER(33,5)},
134 "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"},
135 /*{"/serviceId", "urn:upnp-org:serviceId:WANCommonInterfaceConfig"}, */
136 {"/serviceId", "urn:upnp-org:serviceId:WANCommonIFC1"}, /* required */
137 {"/controlURL", WANCFG_CONTROLURL
},
138 {"/eventSubURL", WANCFG_EVENTURL
},
139 {"/SCPDURL", WANCFG_PATH
},
141 {"device", INITHELPER(39,12)},
143 {"/deviceType", "urn:schemas-upnp-org:device:WANConnectionDevice:1"},
144 {"/friendlyName", WANCDEV_FRIENDLYNAME
},
145 {"/manufacturer", WANCDEV_MANUFACTURER
},
146 {"/manufacturerURL", WANCDEV_MANUFACTURERURL
},
147 {"/modelDescription", WANCDEV_MODELDESCRIPTION
},
148 {"/modelName", WANCDEV_MODELNAME
},
149 {"/modelNumber", WANCDEV_MODELNUMBER
},
150 {"/modelURL", WANCDEV_MODELURL
},
151 {"/serialNumber", serialnumber
},
153 {"/UPC", WANCDEV_UPC
},
154 {"serviceList", INITHELPER(51,1)},
156 {"service", INITHELPER(52,5)},
158 {"/serviceType", "urn:schemas-upnp-org:service:WANIPConnection:1"},
159 /* {"/serviceId", "urn:upnp-org:serviceId:WANIPConnection"}, */
160 {"/serviceId", "urn:upnp-org:serviceId:WANIPConn1"},
161 {"/controlURL", WANIPC_CONTROLURL
},
162 {"/eventSubURL", WANIPC_EVENTURL
},
163 {"/SCPDURL", WANIPC_PATH
},
165 #ifdef HAS_DUMMY_SERVICE
166 {"service", INITHELPER(58,5)},
168 {"/serviceType", "urn:schemas-dummy-com:service:Dummy:1"},
169 {"/serviceId", "urn:dummy-com:serviceId:dummy1"},
170 {"/controlURL", "/dummy"},
171 {"/eventSubURL", "/dummy"},
172 {"/SCPDURL", DUMMY_PATH
},
174 #ifdef ENABLE_L3F_SERVICE
175 {"service", INITHELPER(58,5)},
177 {"/serviceType", "urn:schemas-upnp-org:service:Layer3Forwarding:1"},
178 {"/serviceId", "urn:upnp-org:serviceId:Layer3Forwarding1"},
179 {"/controlURL", L3F_CONTROLURL
}, /* The Layer3Forwarding service is only */
180 {"/eventSubURL", L3F_EVENTURL
}, /* recommended, not mandatory */
181 {"/SCPDURL", L3F_PATH
},
187 /* see UPnP_IGD_WANIPConnection 1.0.pdf
188 static struct XMLElt scpdWANIPCn[] =
190 {root_service, {INITHELPER(1,2)}},
194 static const struct argument AddPortMappingArgs
[] =
207 static const struct argument GetExternalIPAddressArgs
[] =
213 static const struct argument DeletePortMappingArgs
[] =
221 static const struct argument SetConnectionTypeArgs
[] =
227 static const struct argument GetConnectionTypeInfoArgs
[] =
234 static const struct argument GetStatusInfoArgs
[] =
242 static const struct argument GetNATRSIPStatusArgs
[] =
249 static const struct argument GetGenericPortMappingEntryArgs
[] =
263 static const struct argument GetSpecificPortMappingEntryArgs
[] =
276 static const struct action WANIPCnActions
[] =
278 {"AddPortMapping", AddPortMappingArgs
}, /* R */
279 {"GetExternalIPAddress", GetExternalIPAddressArgs
}, /* R */
280 {"DeletePortMapping", DeletePortMappingArgs
}, /* R */
281 {"SetConnectionType", SetConnectionTypeArgs
}, /* R */
282 {"GetConnectionTypeInfo", GetConnectionTypeInfoArgs
}, /* R */
283 {"RequestConnection", 0}, /* R */
284 {"ForceTermination", 0}, /* R */
285 {"GetStatusInfo", GetStatusInfoArgs
}, /* R */
286 {"GetNATRSIPStatus", GetNATRSIPStatusArgs
}, /* R */
287 {"GetGenericPortMappingEntry", GetGenericPortMappingEntryArgs
}, /* R */
288 {"GetSpecificPortMappingEntry", GetSpecificPortMappingEntryArgs
}, /* R */
291 /* R=Required, O=Optional */
293 static const struct stateVar WANIPCnVars
[] =
296 {"ConnectionType", 0, 0/*1*/}, /* required */
297 {"PossibleConnectionTypes", 0|0x80, 0, 14, 15},
299 * Allowed values : Unconfigured / IP_Routed / IP_Bridged */
300 {"ConnectionStatus", 0|0x80, 0/*1*/, 18, 20}, /* required */
301 /* Allowed Values : Unconfigured / Connecting(opt) / Connected
302 * PendingDisconnect(opt) / Disconnecting (opt)
304 {"Uptime", 3, 0}, /* Required */
305 {"LastConnectionError", 0, 0, 25}, /* required : */
306 /* Allowed Values : ERROR_NONE(req) / ERROR_COMMAND_ABORTED(opt)
307 * ERROR_NOT_ENABLED_FOR_INTERNET(opt)
308 * ERROR_USER_DISCONNECT(opt)
309 * ERROR_ISP_DISCONNECT(opt)
310 * ERROR_IDLE_DISCONNECT(opt)
311 * ERROR_FORCED_DISCONNECT(opt)
312 * ERROR_NO_CARRIER(opt)
313 * ERROR_IP_CONFIGURATION(opt)
314 * ERROR_UNKNOWN(opt) */
315 {"RSIPAvailable", 1, 0}, /* required */
316 {"NATEnabled", 1, 0}, /* required */
317 {"ExternalIPAddress", 0|0x80, 0, 0, 254}, /* required. Default : empty string */
318 {"PortMappingNumberOfEntries", 2|0x80, 0, 0, 253}, /* required >= 0 */
319 {"PortMappingEnabled", 1, 0}, /* Required */
320 {"PortMappingLeaseDuration", 3, 0}, /* required */
321 {"RemoteHost", 0, 0}, /* required. Default : empty string */
322 {"ExternalPort", 2, 0}, /* required */
323 {"InternalPort", 2, 0}, /* required */
324 {"PortMappingProtocol", 0, 0, 11}, /* required allowedValues: TCP/UDP */
325 {"InternalClient", 0, 0}, /* required */
326 {"PortMappingDescription", 0, 0}, /* required default: empty string */
330 static const struct serviceDesc scpdWANIPCn
=
331 { WANIPCnActions
, WANIPCnVars
};
334 /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
336 static const struct argument GetCommonLinkPropertiesArgs
[] =
345 static const struct argument GetTotalBytesSentArgs
[] =
351 static const struct argument GetTotalBytesReceivedArgs
[] =
357 static const struct argument GetTotalPacketsSentArgs
[] =
363 static const struct argument GetTotalPacketsReceivedArgs
[] =
369 static const struct action WANCfgActions
[] =
371 {"GetCommonLinkProperties", GetCommonLinkPropertiesArgs
}, /* Required */
372 {"GetTotalBytesSent", GetTotalBytesSentArgs
}, /* optional */
373 {"GetTotalBytesReceived", GetTotalBytesReceivedArgs
}, /* optional */
374 {"GetTotalPacketsSent", GetTotalPacketsSentArgs
}, /* optional */
375 {"GetTotalPacketsReceived", GetTotalPacketsReceivedArgs
}, /* optional */
379 /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
380 static const struct stateVar WANCfgVars
[] =
382 {"WANAccessType", 0, 0, 1},
383 /* Allowed Values : DSL / POTS / Cable / Ethernet
384 * Default value : empty string */
385 {"Layer1UpstreamMaxBitRate", 3, 0},
386 {"Layer1DownstreamMaxBitRate", 3, 0},
387 {"PhysicalLinkStatus", 0|0x80, 0, 6, 6},
389 * Up / Down / Initializing (optional) / Unavailable (optionnal)
392 {"TotalBytesSent", 3, 0}, /* Optional */
393 {"TotalBytesReceived", 3, 0}, /* Optional */
394 {"TotalPacketsSent", 3, 0}, /* Optional */
395 {"TotalPacketsReceived", 3, 0},/* Optional */
396 /*{"MaximumActiveConnections", 2, 0}, // allowed Range value // OPTIONAL */
400 static const struct serviceDesc scpdWANCfg
=
401 { WANCfgActions
, WANCfgVars
};
403 #ifdef ENABLE_L3F_SERVICE
404 /* Read UPnP_IGD_Layer3Forwarding_1.0.pdf */
405 static const struct argument SetDefaultConnectionServiceArgs
[] =
411 static const struct argument GetDefaultConnectionServiceArgs
[] =
417 static const struct action L3FActions
[] =
419 {"SetDefaultConnectionService", SetDefaultConnectionServiceArgs
}, /* Req */
420 {"GetDefaultConnectionService", GetDefaultConnectionServiceArgs
}, /* Req */
424 static const struct stateVar L3FVars
[] =
426 {"DefaultConnectionService", 0|0x80, 0, 0, 255}, /* Required */
430 static const struct serviceDesc scpdL3F
=
431 { L3FActions
, L3FVars
};
435 * concatenate the string and use realloc to increase the
436 * memory buffer if needed. */
438 strcat_str(char * str
, int * len
, int * tmplen
, const char * s2
)
441 s2len
= (int)strlen(s2
);
442 if(*tmplen
<= (*len
+ s2len
))
447 *tmplen
+= s2len
+ 1;
448 str
= (char *)realloc(str
, *tmplen
);
450 /*strcpy(str + *len, s2); */
451 memcpy(str
+ *len
, s2
, s2len
+ 1);
457 * concatenate a character and use realloc to increase the
458 * size of the memory buffer if needed */
460 strcat_char(char * str
, int * len
, int * tmplen
, char c
)
462 if(*tmplen
<= (*len
+ 1))
465 str
= (char *)realloc(str
, *tmplen
);
472 /* iterative subroutine using a small stack
473 * This way, the progam stack usage is kept low */
475 genXML(char * str
, int * len
, int * tmplen
,
476 const struct XMLElt
* p
)
478 unsigned short i
, j
, k
;
480 const char * eltname
, *s
;
485 const char * eltname
;
486 } pile
[16]; /* stack */
488 i
= 0; /* current node */
489 j
= 1; /* i + number of nodes*/
492 eltname
= p
[i
].eltname
;
495 if(eltname
[0] == '/')
497 if(p
[i
].data
&& p
[i
].data
[0])
499 /*printf("<%s>%s<%s>\n", eltname+1, p[i].data, eltname); */
500 str
= strcat_char(str
, len
, tmplen
, '<');
501 str
= strcat_str(str
, len
, tmplen
, eltname
+1);
502 str
= strcat_char(str
, len
, tmplen
, '>');
503 str
= strcat_str(str
, len
, tmplen
, p
[i
].data
);
504 str
= strcat_char(str
, len
, tmplen
, '<');
505 str
= strcat_str(str
, len
, tmplen
, eltname
);
506 str
= strcat_char(str
, len
, tmplen
, '>');
514 /*printf(" pile[%d]\t%d %d\n", top, i, j); */
517 /*printf("</%s>\n", pile[top].eltname); */
518 str
= strcat_char(str
, len
, tmplen
, '<');
519 str
= strcat_char(str
, len
, tmplen
, '/');
520 s
= pile
[top
].eltname
;
521 for(c
= *s
; c
> ' '; c
= *(++s
))
522 str
= strcat_char(str
, len
, tmplen
, c
);
523 str
= strcat_char(str
, len
, tmplen
, '>');
532 /*printf("<%s>\n", eltname); */
533 str
= strcat_char(str
, len
, tmplen
, '<');
534 str
= strcat_str(str
, len
, tmplen
, eltname
);
535 str
= strcat_char(str
, len
, tmplen
, '>');
538 /*j = i + p[k].nchild; */
539 i
= (unsigned)p
[k
].data
& 0xffff;
540 j
= i
+ ((unsigned)p
[k
].data
>> 16);
542 /*printf(" +pile[%d]\t%d %d\n", top, i, j); */
545 pile
[top
].eltname
= eltname
;
551 * - Generate the root description of the UPnP device.
552 * - the len argument is used to return the length of
553 * the returned string.
554 * - tmp_uuid argument is used to build the uuid string */
556 genRootDesc(int * len
)
561 str
= (char *)malloc(tmplen
);
564 * len
= strlen(xmlver
);
565 /*strcpy(str, xmlver); */
566 memcpy(str
, xmlver
, *len
+ 1);
567 str
= genXML(str
, len
, &tmplen
, rootDesc
);
572 /* genServiceDesc() :
573 * Generate service description with allowed methods and
574 * related variables. */
576 genServiceDesc(int * len
, const struct serviceDesc
* s
)
579 const struct action
* acts
;
580 const struct stateVar
* vars
;
581 const struct argument
* args
;
586 str
= (char *)malloc(tmplen
);
589 /*strcpy(str, xmlver); */
590 *len
= strlen(xmlver
);
591 memcpy(str
, xmlver
, *len
+ 1);
593 acts
= s
->actionList
;
594 vars
= s
->serviceStateTable
;
596 str
= strcat_char(str
, len
, &tmplen
, '<');
597 str
= strcat_str(str
, len
, &tmplen
, root_service
);
598 str
= strcat_char(str
, len
, &tmplen
, '>');
600 str
= strcat_str(str
, len
, &tmplen
,
601 "<specVersion><major>1</major><minor>0</minor></specVersion>");
604 str
= strcat_str(str
, len
, &tmplen
, "<actionList>");
607 str
= strcat_str(str
, len
, &tmplen
, "<action><name>");
608 str
= strcat_str(str
, len
, &tmplen
, acts
[i
].name
);
609 str
= strcat_str(str
, len
, &tmplen
, "</name>");
614 str
= strcat_str(str
, len
, &tmplen
, "<argumentList>");
618 str
= strcat_str(str
, len
, &tmplen
, "<argument><name>New");
619 p
= vars
[args
[j
].relatedVar
].name
;
620 if(0 == memcmp(p
, "PortMapping", 11)
621 && 0 != memcmp(p
+ 11, "Description", 11)) {
622 if(0 == memcmp(p
+ 11, "NumberOfEntries", 15))
623 str
= strcat_str(str
, len
, &tmplen
, "PortMappingIndex");
625 str
= strcat_str(str
, len
, &tmplen
, p
+ 11);
627 str
= strcat_str(str
, len
, &tmplen
, p
);
629 str
= strcat_str(str
, len
, &tmplen
, "</name><direction>");
630 str
= strcat_str(str
, len
, &tmplen
, args
[j
].dir
==1?"in":"out");
631 str
= strcat_str(str
, len
, &tmplen
,
632 "</direction><relatedStateVariable>");
633 str
= strcat_str(str
, len
, &tmplen
, p
);
634 str
= strcat_str(str
, len
, &tmplen
,
635 "</relatedStateVariable></argument>");
638 str
= strcat_str(str
, len
, &tmplen
,"</argumentList>");
640 str
= strcat_str(str
, len
, &tmplen
, "</action>");
641 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
644 str
= strcat_str(str
, len
, &tmplen
, "</actionList><serviceStateTable>");
648 str
= strcat_str(str
, len
, &tmplen
,
649 "<stateVariable sendEvents=\"");
651 str
= strcat_str(str
, len
, &tmplen
, (vars
[i
].itype
& 0x80)?"yes":"no");
653 /* for the moment allways send no. Wait for SUBSCRIBE implementation
654 * before setting it to yes */
655 str
= strcat_str(str
, len
, &tmplen
, "no");
657 str
= strcat_str(str
, len
, &tmplen
, "\"><name>");
658 str
= strcat_str(str
, len
, &tmplen
, vars
[i
].name
);
659 str
= strcat_str(str
, len
, &tmplen
, "</name><dataType>");
660 str
= strcat_str(str
, len
, &tmplen
, upnptypes
[vars
[i
].itype
& 0x0f]);
661 str
= strcat_str(str
, len
, &tmplen
, "</dataType>");
662 if(vars
[i
].iallowedlist
)
664 str
= strcat_str(str
, len
, &tmplen
, "<allowedValueList>");
665 for(j
=vars
[i
].iallowedlist
; upnpallowedvalues
[j
]; j
++)
667 str
= strcat_str(str
, len
, &tmplen
, "<allowedValue>");
668 str
= strcat_str(str
, len
, &tmplen
, upnpallowedvalues
[j
]);
669 str
= strcat_str(str
, len
, &tmplen
, "</allowedValue>");
671 str
= strcat_str(str
, len
, &tmplen
, "</allowedValueList>");
673 /*if(vars[i].defaultValue) */
676 str
= strcat_str(str
, len
, &tmplen
, "<defaultValue>");
677 /*str = strcat_str(str, len, &tmplen, vars[i].defaultValue); */
678 str
= strcat_str(str
, len
, &tmplen
, upnpdefaultvalues
[vars
[i
].idefault
]);
679 str
= strcat_str(str
, len
, &tmplen
, "</defaultValue>");
681 str
= strcat_str(str
, len
, &tmplen
, "</stateVariable>");
682 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
685 str
= strcat_str(str
, len
, &tmplen
, "</serviceStateTable></scpd>");
691 * Generate the WANIPConnection xml description */
693 genWANIPCn(int * len
)
695 return genServiceDesc(len
, &scpdWANIPCn
);
699 * Generate the WANInterfaceConfig xml description. */
703 return genServiceDesc(len
, &scpdWANCfg
);
706 #ifdef ENABLE_L3F_SERVICE
710 return genServiceDesc(len
, &scpdL3F
);
716 genEventVars(int * len
, const struct serviceDesc
* s
, const char * servns
)
719 const struct stateVar
* v
;
723 str
= (char *)malloc(tmplen
);
727 v
= s
->serviceStateTable
;
728 str
= strcat_str(str
, len
, &tmplen
, "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\" xmlns:s=\"");
729 str
= strcat_str(str
, len
, &tmplen
, servns
);
730 str
= strcat_str(str
, len
, &tmplen
, "\">");
732 if(v
->itype
& 0x80) {
733 str
= strcat_str(str
, len
, &tmplen
, "<e:property><s:");
734 str
= strcat_str(str
, len
, &tmplen
, v
->name
);
735 str
= strcat_str(str
, len
, &tmplen
, ">");
736 //printf("<e:property><s:%s>", v->name);
737 switch(v
->ieventvalue
) {
740 case 253: /* Port mapping number of entries magical value */
741 snprintf(tmp
, sizeof(tmp
), "%d", upnp_get_portmapping_number_of_entries());
742 str
= strcat_str(str
, len
, &tmplen
, tmp
);
744 case 254: /* External ip address magical value */
746 str
= strcat_str(str
, len
, &tmplen
, use_ext_ip_addr
);
748 char ext_ip_addr
[INET_ADDRSTRLEN
];
749 if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
) < 0) {
750 str
= strcat_str(str
, len
, &tmplen
, "0.0.0.0");
752 str
= strcat_str(str
, len
, &tmplen
, ext_ip_addr
);
755 /*str = strcat_str(str, len, &tmplen, "0.0.0.0");*/
757 case 255: /* DefaultConnectionService magical value */
758 str
= strcat_str(str
, len
, &tmplen
, uuidvalue
);
759 str
= strcat_str(str
, len
, &tmplen
, ":WANConnectionDevice:1,urn:upnp-org:serviceId:WANIPConn1");
760 //printf("%s:WANConnectionDevice:1,urn:upnp-org:serviceId:WANIPConn1", uuidvalue);
763 str
= strcat_str(str
, len
, &tmplen
, upnpallowedvalues
[v
->ieventvalue
]);
764 //printf("%s", upnpallowedvalues[v->ieventvalue]);
766 str
= strcat_str(str
, len
, &tmplen
, "</s:");
767 str
= strcat_str(str
, len
, &tmplen
, v
->name
);
768 str
= strcat_str(str
, len
, &tmplen
, "></e:property>");
769 //printf("</s:%s></e:property>\n", v->name);
773 str
= strcat_str(str
, len
, &tmplen
, "</e:propertyset>");
774 //printf("</e:propertyset>\n");
776 //printf("%d\n", tmplen);
782 getVarsWANIPCn(int * l
)
784 return genEventVars(l
,
786 "urn:schemas-upnp-org:service:WANIPConnection:1");
790 getVarsWANCfg(int * l
)
792 return genEventVars(l
,
794 "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1");
797 #ifdef ENABLE_L3F_SERVICE
801 return genEventVars(l
,
803 "urn:schemas-upnp-org:service:Layer3Forwarding:1");