1 /* $Id: upnpdescgen.c,v 1.78 2014/10/21 14:08:35 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2014 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 #include "getconnstatus.h"
25 /* Event magical values codes */
26 #define CONNECTIONSTATUS_MAGICALVALUE (249)
27 #define FIREWALLENABLED_MAGICALVALUE (250)
28 #define INBOUNDPINHOLEALLOWED_MAGICALVALUE (251)
29 #define SYSTEMUPDATEID_MAGICALVALUE (252)
30 #define PORTMAPPINGNUMBEROFENTRIES_MAGICALVALUE (253)
31 #define EXTERNALIPADDRESS_MAGICALVALUE (254)
32 #define DEFAULTCONNECTIONSERVICE_MAGICALVALUE (255)
35 static const char * const upnptypes
[] =
44 static const char * const upnpdefaultvalues
[] =
47 "IP_Routed"/*"Unconfigured"*/, /* 1 default value for ConnectionType */
48 "3600", /* 2 default value for PortMappingLeaseDuration */
51 static const char * const upnpallowedvalues
[] =
67 "Unconfigured", /* 14 */
71 "Unconfigured", /* 18 */
78 "ERROR_NONE", /* 25 */
80 * ERROR_COMMAND_ABORTED
81 * ERROR_NOT_ENABLED_FOR_INTERNET
82 * ERROR_USER_DISCONNECT
83 * ERROR_ISP_DISCONNECT
84 * ERROR_IDLE_DISCONNECT
85 * ERROR_FORCED_DISCONNECT
87 * ERROR_IP_CONFIGURATION
94 static const int upnpallowedranges
[] = {
96 /* 1 PortMappingLeaseDuration */
105 /* 7 OutboundPinholeTimeout */
110 static const char * magicargname
[] = {
121 static const char xmlver
[] =
122 "<?xml version=\"1.0\"?>\r\n";
123 static const char root_service
[] =
124 "scpd xmlns=\"urn:schemas-upnp-org:service-1-0\"";
125 static const char root_device
[] =
126 "root xmlns=\"urn:schemas-upnp-org:device-1-0\"";
128 /* root Description of the UPnP Device
129 * fixed to match UPnP_IGD_InternetGatewayDevice 1.0.pdf
130 * Needs to be checked with UPnP-gw-InternetGatewayDevice-v2-Device.pdf
131 * presentationURL is only "recommended" but the router doesn't appears
132 * in "Network connections" in Windows XP if it is not present. */
133 static const struct XMLElt rootDesc
[] =
136 {root_device
, INITHELPER(1,2)},
137 {"specVersion", INITHELPER(3,2)},
138 #if defined(ENABLE_L3F_SERVICE) || defined(HAS_DUMMY_SERVICE) || defined(ENABLE_DP_SERVICE)
139 {"device", INITHELPER(5,13)},
141 {"device", INITHELPER(5,12)},
146 {"/deviceType", DEVICE_TYPE_IGD
},
147 /* urn:schemas-upnp-org:device:InternetGatewayDevice:1 or 2 */
148 #ifdef ENABLE_MANUFACTURER_INFO_CONFIGURATION
149 {"/friendlyName", friendly_name
/*ROOTDEV_FRIENDLYNAME*/}, /* required */
150 {"/manufacturer", manufacturer_name
/*ROOTDEV_MANUFACTURER*/}, /* required */
152 {"/manufacturerURL", manufacturer_url
/*ROOTDEV_MANUFACTURERURL*/}, /* optional */
153 {"/modelDescription", model_description
/*ROOTDEV_MODELDESCRIPTION*/}, /* recommended */
154 {"/modelName", model_name
/*ROOTDEV_MODELNAME*/}, /* required */
155 {"/modelNumber", modelnumber
},
156 {"/modelURL", model_url
/*ROOTDEV_MODELURL*/},
158 {"/friendlyName", ROOTDEV_FRIENDLYNAME
}, /* required */
159 {"/manufacturer", ROOTDEV_MANUFACTURER
}, /* required */
161 {"/manufacturerURL", ROOTDEV_MANUFACTURERURL
}, /* optional */
162 {"/modelDescription", ROOTDEV_MODELDESCRIPTION
}, /* recommended */
163 {"/modelName", ROOTDEV_MODELNAME
}, /* required */
164 {"/modelNumber", modelnumber
},
165 {"/modelURL", ROOTDEV_MODELURL
},
167 {"/serialNumber", serialnumber
},
168 {"/UDN", uuidvalue_igd
}, /* required */
169 /* see if /UPC is needed. */
170 #ifdef ENABLE_6FC_SERVICE
171 #define SERVICES_OFFSET 63
173 #define SERVICES_OFFSET 58
175 #if defined(ENABLE_L3F_SERVICE) || defined(HAS_DUMMY_SERVICE) || defined(ENABLE_DP_SERVICE)
176 /* here we dening Services for the root device :
177 * L3F and DUMMY and DeviceProtection */
178 #ifdef ENABLE_L3F_SERVICE
183 #ifdef HAS_DUMMY_SERVICE
188 #ifdef ENABLE_DP_SERVICE
193 #define NSERVICES (NSERVICES1+NSERVICES2+NSERVICES3)
194 {"serviceList", INITHELPER(SERVICES_OFFSET
,NSERVICES
)},
195 {"deviceList", INITHELPER(18,1)},
196 {"/presentationURL", presentationurl
}, /* recommended */
198 {"deviceList", INITHELPER(18,1)},
199 {"/presentationURL", presentationurl
}, /* recommended */
203 {"device", INITHELPER(19,13)},
205 {"/deviceType", DEVICE_TYPE_WAN
}, /* required */
206 /* urn:schemas-upnp-org:device:WANDevice:1 or 2 */
207 {"/friendlyName", WANDEV_FRIENDLYNAME
},
208 {"/manufacturer", WANDEV_MANUFACTURER
},
209 {"/manufacturerURL", WANDEV_MANUFACTURERURL
},
210 {"/modelDescription" , WANDEV_MODELDESCRIPTION
},
211 {"/modelName", WANDEV_MODELNAME
},
212 {"/modelNumber", WANDEV_MODELNUMBER
},
213 {"/modelURL", WANDEV_MODELURL
},
214 {"/serialNumber", serialnumber
},
215 {"/UDN", uuidvalue_wan
},
216 {"/UPC", WANDEV_UPC
}, /* UPC (=12 digit barcode) is optional */
218 {"serviceList", INITHELPER(32,1)},
219 {"deviceList", INITHELPER(38,1)},
221 {"service", INITHELPER(33,5)},
224 "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"},
225 /*{"/serviceId", "urn:upnp-org:serviceId:WANCommonInterfaceConfig"}, */
226 {"/serviceId", "urn:upnp-org:serviceId:WANCommonIFC1"}, /* required */
227 {"/controlURL", WANCFG_CONTROLURL
},
228 {"/eventSubURL", WANCFG_EVENTURL
},
229 {"/SCPDURL", WANCFG_PATH
},
231 {"device", INITHELPER(39,12)},
233 {"/deviceType", DEVICE_TYPE_WANC
},
234 /* urn:schemas-upnp-org:device:WANConnectionDevice:1 or 2 */
235 {"/friendlyName", WANCDEV_FRIENDLYNAME
},
236 {"/manufacturer", WANCDEV_MANUFACTURER
},
237 {"/manufacturerURL", WANCDEV_MANUFACTURERURL
},
238 {"/modelDescription", WANCDEV_MODELDESCRIPTION
},
239 {"/modelName", WANCDEV_MODELNAME
},
240 {"/modelNumber", WANCDEV_MODELNUMBER
},
241 {"/modelURL", WANCDEV_MODELURL
},
242 {"/serialNumber", serialnumber
},
243 {"/UDN", uuidvalue_wcd
},
244 {"/UPC", WANCDEV_UPC
}, /* UPC (=12 digit Barcode) is optional */
245 #ifdef ENABLE_6FC_SERVICE
246 {"serviceList", INITHELPER(51,2)},
248 {"serviceList", INITHELPER(51,1)},
251 {"service", INITHELPER(53,5)},
252 {"service", INITHELPER(58,5)},
254 {"/serviceType", SERVICE_TYPE_WANIPC
},
255 /* urn:schemas-upnp-org:service:WANIPConnection:2 for v2 */
256 {"/serviceId", SERVICE_ID_WANIPC
},
257 /* urn:upnp-org:serviceId:WANIPConn1 or 2 */
258 {"/controlURL", WANIPC_CONTROLURL
},
259 {"/eventSubURL", WANIPC_EVENTURL
},
260 {"/SCPDURL", WANIPC_PATH
},
261 #ifdef ENABLE_6FC_SERVICE
263 {"/serviceType", "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"},
264 {"/serviceId", "urn:upnp-org:serviceId:WANIPv6FC1"},
265 {"/controlURL", WANIP6FC_CONTROLURL
},
266 {"/eventSubURL", WANIP6FC_EVENTURL
},
267 {"/SCPDURL", WANIP6FC_PATH
},
269 /* 58 / 63 = SERVICES_OFFSET*/
270 #if defined(HAS_DUMMY_SERVICE) || defined(ENABLE_L3F_SERVICE) || defined(ENABLE_DP_SERVICE)
271 {"service", INITHELPER(SERVICES_OFFSET
+2,5)},
272 {"service", INITHELPER(SERVICES_OFFSET
+7,5)},
274 #ifdef HAS_DUMMY_SERVICE
275 /* 60 / 65 = SERVICES_OFFSET+2 */
276 {"/serviceType", "urn:schemas-dummy-com:service:Dummy:1"},
277 {"/serviceId", "urn:dummy-com:serviceId:dummy1"},
278 {"/controlURL", "/dummy"},
279 {"/eventSubURL", "/dummy"},
280 {"/SCPDURL", DUMMY_PATH
},
282 #ifdef ENABLE_L3F_SERVICE
283 /* 60 / 65 = SERVICES_OFFSET+2 */
284 {"/serviceType", "urn:schemas-upnp-org:service:Layer3Forwarding:1"},
285 {"/serviceId", "urn:upnp-org:serviceId:Layer3Forwarding1"},
286 {"/controlURL", L3F_CONTROLURL
}, /* The Layer3Forwarding service is only */
287 {"/eventSubURL", L3F_EVENTURL
}, /* recommended, not mandatory */
288 {"/SCPDURL", L3F_PATH
},
290 #ifdef ENABLE_DP_SERVICE
291 /* InternetGatewayDevice v2 :
292 * it is RECOMMEDED that DeviceProtection service is implemented and applied.
293 * If DeviceProtection is not implemented and applied, it is RECOMMENDED
294 * that control points are able to access only actions and parameters defined
296 /* 65 / 70 = SERVICES_OFFSET+7 */
297 {"/serviceType", "urn:schemas-upnp-org:service:DeviceProtection:1"},
298 {"/serviceId", "urn:upnp-org:serviceId:DeviceProtection1"},
299 {"/controlURL", DP_CONTROLURL
},
300 {"/eventSubURL", DP_EVENTURL
},
301 {"/SCPDURL", DP_PATH
},
307 /* see UPnP_IGD_WANIPConnection 1.0.pdf
308 static struct XMLElt scpdWANIPCn[] =
310 {root_service, {INITHELPER(1,2)}},
314 static const struct argument AddPortMappingArgs
[] =
316 {1, 11}, /* RemoteHost */
317 {1, 12}, /* ExternalPort */
318 {1, 14}, /* PortMappingProtocol */
319 {1, 13}, /* InternalPort */
320 {1, 15}, /* InternalClient */
321 {1, 9}, /* PortMappingEnabled */
322 {1, 16}, /* PortMappingDescription */
323 {1, 10}, /* PortMappingLeaseDuration */
328 static const struct argument AddAnyPortMappingArgs
[] =
330 {1, 11}, /* RemoteHost */
331 {1, 12}, /* ExternalPort */
332 {1, 14}, /* PortMappingProtocol */
333 {1, 13}, /* InternalPort */
334 {1, 15}, /* InternalClient */
335 {1, 9}, /* PortMappingEnabled */
336 {1, 16}, /* PortMappingDescription */
337 {1, 10}, /* PortMappingLeaseDuration */
338 {2, 12}, /* NewReservedPort / ExternalPort */
342 static const struct argument DeletePortMappingRangeArgs
[] =
344 {1|(1<<2), 12}, /* NewStartPort / ExternalPort */
345 {1|(2<<2), 12}, /* NewEndPort / ExternalPort */
346 {1, 14}, /* NewProtocol / PortMappingProtocol */
347 {1, 18}, /* NewManage / A_ARG_TYPE_Manage */
351 static const struct argument GetListOfPortMappingsArgs
[] =
353 {1|(1<<2), 12}, /* NewStartPort / ExternalPort */
354 {1|(2<<2), 12}, /* NewEndPort / ExternalPort */
355 {1, 14}, /* NewProtocol / PortMappingProtocol */
356 {1, 18}, /* NewManage / A_ARG_TYPE_Manage */
357 {1, 8}, /* NewNumberOfPorts / PortMappingNumberOfEntries */
358 {2, 19}, /* NewPortListing / A_ARG_TYPE_PortListing */
363 static const struct argument GetExternalIPAddressArgs
[] =
369 static const struct argument DeletePortMappingArgs
[] =
371 {1, 11}, /* RemoteHost */
372 {1, 12}, /* ExternalPort */
373 {1, 14}, /* PortMappingProtocol */
377 static const struct argument SetConnectionTypeArgs
[] =
383 static const struct argument GetConnectionTypeInfoArgs
[] =
390 static const struct argument GetStatusInfoArgs
[] =
398 static const struct argument GetNATRSIPStatusArgs
[] =
405 static const struct argument GetGenericPortMappingEntryArgs
[] =
419 static const struct argument GetSpecificPortMappingEntryArgs
[] =
432 static const struct action WANIPCnActions
[] =
434 {"SetConnectionType", SetConnectionTypeArgs
}, /* R */
435 {"GetConnectionTypeInfo", GetConnectionTypeInfoArgs
}, /* R */
436 {"RequestConnection", 0}, /* R */
437 /*{"RequestTermination", 0},*/ /* O */
438 {"ForceTermination", 0}, /* R */
439 /*{"SetAutoDisconnectTime", 0},*/ /* O */
440 /*{"SetIdleDisconnectTime", 0},*/ /* O */
441 /*{"SetWarnDisconnectDelay", 0}, */ /* O */
442 {"GetStatusInfo", GetStatusInfoArgs
}, /* R */
443 /*GetAutoDisconnectTime*/ /* O */
444 /*GetIdleDisconnectTime*/ /* O */
445 /*GetWarnDisconnectDelay*/ /* O */
446 {"GetNATRSIPStatus", GetNATRSIPStatusArgs
}, /* R */
447 {"GetGenericPortMappingEntry", GetGenericPortMappingEntryArgs
}, /* R */
448 {"GetSpecificPortMappingEntry", GetSpecificPortMappingEntryArgs
}, /* R */
449 {"AddPortMapping", AddPortMappingArgs
}, /* R */
450 {"DeletePortMapping", DeletePortMappingArgs
}, /* R */
451 {"GetExternalIPAddress", GetExternalIPAddressArgs
}, /* R */
453 {"DeletePortMappingRange", DeletePortMappingRangeArgs
}, /* R, IGD v2 */
454 {"GetListOfPortMappings", GetListOfPortMappingsArgs
}, /* R, IGD v2 */
455 {"AddAnyPortMapping", AddAnyPortMappingArgs
}, /* R, IGD v2 */
458 {"AddPortMapping", AddPortMappingArgs
}, /* R */
459 {"GetExternalIPAddress", GetExternalIPAddressArgs
}, /* R */
460 {"DeletePortMapping", DeletePortMappingArgs
}, /* R */
461 {"SetConnectionType", SetConnectionTypeArgs
}, /* R */
462 {"GetConnectionTypeInfo", GetConnectionTypeInfoArgs
}, /* R */
463 {"RequestConnection", 0}, /* R */
464 {"ForceTermination", 0}, /* R */
465 {"GetStatusInfo", GetStatusInfoArgs
}, /* R */
466 {"GetNATRSIPStatus", GetNATRSIPStatusArgs
}, /* R */
467 {"GetGenericPortMappingEntry", GetGenericPortMappingEntryArgs
}, /* R */
468 {"GetSpecificPortMappingEntry", GetSpecificPortMappingEntryArgs
}, /* R */
469 /* added in v2 UPnP-gw-WANIPConnection-v2-Service.pdf */
471 {"AddAnyPortMapping", AddAnyPortMappingArgs
},
472 {"DeletePortMappingRange", DeletePortMappingRangeArgs
},
473 {"GetListOfPortMappings", GetListOfPortMappingsArgs
},
478 /* R=Required, O=Optional */
480 /* ignore "warning: missing initializer" */
481 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
483 static const struct stateVar WANIPCnVars
[] =
487 {"ConnectionType", 0, 0/*1*/}, /* required */
488 {"PossibleConnectionTypes", 0|0x80, 0, 14, 15},
490 {"ConnectionType", 0, 1, 14, 15}, /* required */
491 {"PossibleConnectionTypes", 0|0x80, 0, 0, 15},
493 * Allowed values : Unconfigured / IP_Routed / IP_Bridged */
494 {"ConnectionStatus", 0|0x80, 0/*1*/, 18,
495 CONNECTIONSTATUS_MAGICALVALUE
}, /* required */
496 /* Allowed Values : Unconfigured / Connecting(opt) / Connected
497 * PendingDisconnect(opt) / Disconnecting (opt)
499 {"Uptime", 3, 0}, /* Required */
500 {"LastConnectionError", 0, 0, 25}, /* required : */
501 /* Allowed Values : ERROR_NONE(req) / ERROR_COMMAND_ABORTED(opt)
502 * ERROR_NOT_ENABLED_FOR_INTERNET(opt)
503 * ERROR_USER_DISCONNECT(opt)
504 * ERROR_ISP_DISCONNECT(opt)
505 * ERROR_IDLE_DISCONNECT(opt)
506 * ERROR_FORCED_DISCONNECT(opt)
507 * ERROR_NO_CARRIER(opt)
508 * ERROR_IP_CONFIGURATION(opt)
509 * ERROR_UNKNOWN(opt) */
510 {"RSIPAvailable", 1, 0}, /* required */
511 {"NATEnabled", 1, 0}, /* required */
512 {"ExternalIPAddress", 0|0x80, 0, 0,
513 EXTERNALIPADDRESS_MAGICALVALUE
}, /* required. Default : empty string */
514 {"PortMappingNumberOfEntries", 2|0x80, 0, 0,
515 PORTMAPPINGNUMBEROFENTRIES_MAGICALVALUE
}, /* required >= 0 */
516 {"PortMappingEnabled", 1, 0}, /* Required */
518 {"PortMappingLeaseDuration", 3, 2, 1}, /* required */
519 /* TODO : for IGD v2 :
520 * <stateVariable sendEvents="no">
521 * <name>PortMappingLeaseDuration</name>
522 * <dataType>ui4</dataType>
523 * <defaultValue>Vendor-defined</defaultValue>
524 * <allowedValueRange>
525 * <minimum>0</minimum>
526 * <maximum>604800</maximum>
527 * </allowedValueRange>
528 * </stateVariable> */
529 {"RemoteHost", 0, 0}, /* required. Default : empty string */
530 {"ExternalPort", 2, 0}, /* required */
531 {"InternalPort", 2, 0, 3}, /* required */
532 {"PortMappingProtocol", 0, 0, 11}, /* required allowedValues: TCP/UDP */
533 {"InternalClient", 0, 0}, /* required */
534 {"PortMappingDescription", 0, 0}, /* required default: empty string */
535 /* added in v2 UPnP-gw-WANIPConnection-v2-Service.pdf */
537 {"SystemUpdateID", 3|0x80, 0, 0, SYSTEMUPDATEID_MAGICALVALUE
},
538 {"A_ARG_TYPE_Manage", 1, 0},
539 {"A_ARG_TYPE_PortListing", 0, 0},
544 static const struct serviceDesc scpdWANIPCn
=
545 { WANIPCnActions
, WANIPCnVars
};
548 /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
550 static const struct argument GetCommonLinkPropertiesArgs
[] =
559 static const struct argument GetTotalBytesSentArgs
[] =
565 static const struct argument GetTotalBytesReceivedArgs
[] =
571 static const struct argument GetTotalPacketsSentArgs
[] =
577 static const struct argument GetTotalPacketsReceivedArgs
[] =
583 static const struct action WANCfgActions
[] =
585 {"GetCommonLinkProperties", GetCommonLinkPropertiesArgs
}, /* Required */
586 {"GetTotalBytesSent", GetTotalBytesSentArgs
}, /* optional */
587 {"GetTotalBytesReceived", GetTotalBytesReceivedArgs
}, /* optional */
588 {"GetTotalPacketsSent", GetTotalPacketsSentArgs
}, /* optional */
589 {"GetTotalPacketsReceived", GetTotalPacketsReceivedArgs
}, /* optional */
593 /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
594 static const struct stateVar WANCfgVars
[] =
596 {"WANAccessType", 0, 0, 1},
597 /* Allowed Values : DSL / POTS / Cable / Ethernet
598 * Default value : empty string */
599 {"Layer1UpstreamMaxBitRate", 3, 0},
600 {"Layer1DownstreamMaxBitRate", 3, 0},
601 {"PhysicalLinkStatus", 0|0x80, 0, 6, 6},
603 * Up / Down / Initializing (optional) / Unavailable (optionnal)
606 {"TotalBytesSent", 3, 0}, /* Optional */
607 {"TotalBytesReceived", 3, 0}, /* Optional */
608 {"TotalPacketsSent", 3, 0}, /* Optional */
609 {"TotalPacketsReceived", 3, 0},/* Optional */
610 /*{"MaximumActiveConnections", 2, 0}, // allowed Range value // OPTIONAL */
611 /*{"WANAccessProvider", 0, 0},*/ /* Optional */
615 static const struct serviceDesc scpdWANCfg
=
616 { WANCfgActions
, WANCfgVars
};
618 #ifdef ENABLE_L3F_SERVICE
619 /* Read UPnP_IGD_Layer3Forwarding_1.0.pdf */
620 static const struct argument SetDefaultConnectionServiceArgs
[] =
626 static const struct argument GetDefaultConnectionServiceArgs
[] =
632 static const struct action L3FActions
[] =
634 {"SetDefaultConnectionService", SetDefaultConnectionServiceArgs
}, /* Req */
635 {"GetDefaultConnectionService", GetDefaultConnectionServiceArgs
}, /* Req */
639 static const struct stateVar L3FVars
[] =
641 {"DefaultConnectionService", 0|0x80, 0, 0,
642 DEFAULTCONNECTIONSERVICE_MAGICALVALUE
}, /* Required */
646 static const struct serviceDesc scpdL3F
=
647 { L3FActions
, L3FVars
};
650 #ifdef ENABLE_6FC_SERVICE
651 /* see UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
652 static const struct argument GetFirewallStatusArgs
[] =
654 {2|0x80, 0}, /* OUT : FirewallEnabled */
655 {2|0x80, 6}, /* OUT : InboundPinholeAllowed */
659 static const struct argument GetOutboundPinholeTimeoutArgs
[] =
661 {1|0x80|(3<<2), 1}, /* RemoteHost IN A_ARG_TYPE_IPv6Address */
662 {1|0x80|(4<<2), 2}, /* RemotePort IN A_ARG_TYPE_Port */
663 {1|0x80|(5<<2), 1}, /* InternalClient IN A_ARG_TYPE_IPv6Address */
664 {1|0x80|(6<<2), 2}, /* InternalPort IN A_ARG_TYPE_Port */
665 {1|0x80, 3}, /* Protocol IN A_ARG_TYPE_Protocol */
666 {2|0x80, 7}, /* OutboundPinholeTimeout OUT A_ARG_TYPE_OutboundPinholeTimeout */
670 static const struct argument AddPinholeArgs
[] =
672 {1|0x80|(3<<2), 1}, /* RemoteHost IN A_ARG_TYPE_IPv6Address */
673 {1|0x80|(4<<2), 2}, /* RemotePort IN A_ARG_TYPE_Port */
674 {1|0x80|(5<<2), 1}, /* InternalClient IN A_ARG_TYPE_IPv6Address */
675 {1|0x80|(6<<2), 2}, /* InternalPort IN A_ARG_TYPE_Port */
676 {1|0x80, 3}, /* Protocol IN A_ARG_TYPE_Protocol */
677 {1|0x80, 5}, /* LeaseTime IN A_ARG_TYPE_LeaseTime */
678 {2|0x80, 4}, /* UniqueID OUT A_ARG_TYPE_UniqueID */
682 static const struct argument UpdatePinholeArgs
[] =
684 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
685 {1, 5}, /* LeaseTime IN A_ARG_TYPE_LeaseTime */
689 static const struct argument DeletePinholeArgs
[] =
691 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
695 static const struct argument GetPinholePacketsArgs
[] =
697 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
698 {2|0x80, 9}, /* PinholePackets OUT A_ARG_TYPE_PinholePackets */
702 static const struct argument CheckPinholeWorkingArgs
[] =
704 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
705 {2|0x80|(7<<2), 8}, /* IsWorking OUT A_ARG_TYPE_Boolean */
709 static const struct action IPv6FCActions
[] =
711 {"GetFirewallStatus", GetFirewallStatusArgs
}, /* Req */
712 {"GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs
}, /* Opt */
713 {"AddPinhole", AddPinholeArgs
}, /* Req */
714 {"UpdatePinhole", UpdatePinholeArgs
}, /* Req */
715 {"DeletePinhole", DeletePinholeArgs
}, /* Req */
716 {"GetPinholePackets", GetPinholePacketsArgs
}, /* Req */
717 {"CheckPinholeWorking", CheckPinholeWorkingArgs
}, /* Opt */
721 static const struct stateVar IPv6FCVars
[] =
723 {"FirewallEnabled", 1|0x80, 0, 0,
724 FIREWALLENABLED_MAGICALVALUE
}, /* Required */
725 {"A_ARG_TYPE_IPv6Address", 0, 0, 0, 0}, /* Required */
726 {"A_ARG_TYPE_Port", 2, 0, 0, 0}, /* Required */
727 {"A_ARG_TYPE_Protocol", 2, 0, 0, 0}, /* Required */
729 {"A_ARG_TYPE_UniqueID", 2, 0, 0, 0}, /* Required */
730 {"A_ARG_TYPE_LeaseTime", 3, 0, 5, 0}, /* Required */
731 {"InboundPinholeAllowed", 1|0x80, 0, 0,
732 INBOUNDPINHOLEALLOWED_MAGICALVALUE
}, /* Required */
733 {"A_ARG_TYPE_OutboundPinholeTimeout", 3, 0, 7, 0}, /* Optional */
735 {"A_ARG_TYPE_Boolean", 1, 0, 0, 0}, /* Optional */
736 {"A_ARG_TYPE_PinholePackets", 3, 0, 0, 0}, /* Required */
740 static const struct serviceDesc scpd6FC
=
741 { IPv6FCActions
, IPv6FCVars
};
744 #ifdef ENABLE_DP_SERVICE
745 /* UPnP-gw-DeviceProtection-v1-Service.pdf */
746 static const struct action DPActions
[] =
748 {"SendSetupMessage", 0},
749 {"GetSupportedProtocols", 0},
750 {"GetAssignedRoles", 0},
754 static const struct stateVar DPVars
[] =
756 {"SetupReady", 1|0x80},
757 {"SupportedProtocols", 0},
758 {"A_ARG_TYPE_ACL", 0},
759 {"A_ARG_TYPE_IdentityList", 0},
760 {"A_ARG_TYPE_Identity", 0},
761 {"A_ARG_TYPE_Base64", 4},
762 {"A_ARG_TYPE_String", 0},
766 static const struct serviceDesc scpdDP
=
767 { DPActions
, DPVars
};
771 * concatenate the string and use realloc to increase the
772 * memory buffer if needed. */
774 strcat_str(char * str
, int * len
, int * tmplen
, const char * s2
)
780 s2len
= (int)strlen(s2
);
781 if(*tmplen
<= (*len
+ s2len
))
784 newlen
= *tmplen
+ 256;
786 newlen
= *tmplen
+ s2len
+ 1;
787 p
= (char *)realloc(str
, newlen
);
788 if(p
== NULL
) /* handle a failure of realloc() */
793 /*strcpy(str + *len, s2); */
794 memcpy(str
+ *len
, s2
, s2len
+ 1);
800 * concatenate a character and use realloc to increase the
801 * size of the memory buffer if needed */
803 strcat_char(char * str
, int * len
, int * tmplen
, char c
)
807 if(*tmplen
<= (*len
+ 1))
810 p
= (char *)realloc(str
, *tmplen
);
811 if(p
== NULL
) /* handle a failure of realloc() */
824 * concatenate the string representation of the integer.
825 * call strcat_char() */
827 strcat_int(char * str
, int * len
, int * tmplen
, int i
)
833 str
= strcat_char(str
, len
, tmplen
, '-');
836 /* special case for 0 */
837 str
= strcat_char(str
, len
, tmplen
, '0');
841 while(i
&& j
< (int)sizeof(buf
)) {
842 buf
[j
++] = '0' + (i
% 10);
846 str
= strcat_char(str
, len
, tmplen
, buf
[--j
]);
851 /* iterative subroutine using a small stack
852 * This way, the progam stack usage is kept low */
854 genXML(char * str
, int * len
, int * tmplen
,
855 const struct XMLElt
* p
)
860 const char * eltname
, *s
;
865 const char * eltname
;
866 } pile
[16]; /* stack */
868 i
= 0; /* current node */
869 j
= 1; /* i + number of nodes*/
872 eltname
= p
[i
].eltname
;
875 if(eltname
[0] == '/')
877 if(p
[i
].data
&& p
[i
].data
[0])
879 /*printf("<%s>%s<%s>\n", eltname+1, p[i].data, eltname); */
880 str
= strcat_char(str
, len
, tmplen
, '<');
881 str
= strcat_str(str
, len
, tmplen
, eltname
+1);
882 str
= strcat_char(str
, len
, tmplen
, '>');
883 str
= strcat_str(str
, len
, tmplen
, p
[i
].data
);
884 str
= strcat_char(str
, len
, tmplen
, '<');
885 str
= strcat_str(str
, len
, tmplen
, eltname
);
886 str
= strcat_char(str
, len
, tmplen
, '>');
894 /*printf(" pile[%d]\t%d %d\n", top, i, j); */
897 /*printf("</%s>\n", pile[top].eltname); */
898 str
= strcat_char(str
, len
, tmplen
, '<');
899 str
= strcat_char(str
, len
, tmplen
, '/');
900 s
= pile
[top
].eltname
;
901 for(c
= *s
; c
> ' '; c
= *(++s
))
902 str
= strcat_char(str
, len
, tmplen
, c
);
903 str
= strcat_char(str
, len
, tmplen
, '>');
912 /*printf("<%s>\n", eltname); */
913 str
= strcat_char(str
, len
, tmplen
, '<');
914 str
= strcat_str(str
, len
, tmplen
, eltname
);
915 str
= strcat_char(str
, len
, tmplen
, '>');
916 k
= (unsigned long)p
[i
].data
;
920 /*printf(" +pile[%d]\t%d %d\n", top, i, j); */
923 pile
[top
].eltname
= eltname
;
929 * - Generate the root description of the UPnP device.
930 * - the len argument is used to return the length of
931 * the returned string.
932 * - tmp_uuid argument is used to build the uuid string */
934 genRootDesc(int * len
)
939 str
= (char *)malloc(tmplen
);
942 * len
= strlen(xmlver
);
943 /*strcpy(str, xmlver); */
944 memcpy(str
, xmlver
, *len
+ 1);
945 str
= genXML(str
, len
, &tmplen
, rootDesc
);
950 /* genServiceDesc() :
951 * Generate service description with allowed methods and
952 * related variables. */
954 genServiceDesc(int * len
, const struct serviceDesc
* s
)
957 const struct action
* acts
;
958 const struct stateVar
* vars
;
959 const struct argument
* args
;
964 str
= (char *)malloc(tmplen
);
967 /*strcpy(str, xmlver); */
968 *len
= strlen(xmlver
);
969 memcpy(str
, xmlver
, *len
+ 1);
971 acts
= s
->actionList
;
972 vars
= s
->serviceStateTable
;
974 str
= strcat_char(str
, len
, &tmplen
, '<');
975 str
= strcat_str(str
, len
, &tmplen
, root_service
);
976 str
= strcat_char(str
, len
, &tmplen
, '>');
978 str
= strcat_str(str
, len
, &tmplen
,
979 "<specVersion><major>1</major><minor>0</minor></specVersion>");
982 str
= strcat_str(str
, len
, &tmplen
, "<actionList>");
985 str
= strcat_str(str
, len
, &tmplen
, "<action><name>");
986 str
= strcat_str(str
, len
, &tmplen
, acts
[i
].name
);
987 str
= strcat_str(str
, len
, &tmplen
, "</name>");
992 str
= strcat_str(str
, len
, &tmplen
, "<argumentList>");
996 str
= strcat_str(str
, len
, &tmplen
, "<argument><name>");
997 if((args
[j
].dir
& 0x80) == 0) {
998 str
= strcat_str(str
, len
, &tmplen
, "New");
1000 p
= vars
[args
[j
].relatedVar
].name
;
1001 if(args
[j
].dir
& 0x7c) {
1002 /* use magic values ... */
1003 str
= strcat_str(str
, len
, &tmplen
, magicargname
[(args
[j
].dir
& 0x7c) >> 2]);
1004 } else if(0 == memcmp(p
, "PortMapping", 11)
1005 && 0 != memcmp(p
+ 11, "Description", 11)) {
1006 if(0 == memcmp(p
+ 11, "NumberOfEntries", 15)) {
1007 /* PortMappingNumberOfEntries */
1009 if(0 == memcmp(acts
[i
].name
, "GetListOfPortMappings", 22)) {
1010 str
= strcat_str(str
, len
, &tmplen
, "NumberOfPorts");
1012 str
= strcat_str(str
, len
, &tmplen
, "PortMappingIndex");
1015 str
= strcat_str(str
, len
, &tmplen
, "PortMappingIndex");
1018 /* PortMappingEnabled
1019 * PortMappingLeaseDuration
1020 * PortMappingProtocol */
1021 str
= strcat_str(str
, len
, &tmplen
, p
+ 11);
1024 } else if(0 == memcmp(p
, "A_ARG_TYPE_", 11)) {
1025 str
= strcat_str(str
, len
, &tmplen
, p
+ 11);
1026 } else if(0 == memcmp(p
, "ExternalPort", 13)
1028 && 0 == memcmp(acts
[i
].name
, "AddAnyPortMapping", 18)) {
1029 str
= strcat_str(str
, len
, &tmplen
, "ReservedPort");
1032 str
= strcat_str(str
, len
, &tmplen
, p
);
1034 str
= strcat_str(str
, len
, &tmplen
, "</name><direction>");
1035 str
= strcat_str(str
, len
, &tmplen
, (args
[j
].dir
&0x03)==1?"in":"out");
1036 str
= strcat_str(str
, len
, &tmplen
,
1037 "</direction><relatedStateVariable>");
1038 str
= strcat_str(str
, len
, &tmplen
, p
);
1039 str
= strcat_str(str
, len
, &tmplen
,
1040 "</relatedStateVariable></argument>");
1043 str
= strcat_str(str
, len
, &tmplen
,"</argumentList>");
1045 str
= strcat_str(str
, len
, &tmplen
, "</action>");
1046 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
1049 str
= strcat_str(str
, len
, &tmplen
, "</actionList><serviceStateTable>");
1053 str
= strcat_str(str
, len
, &tmplen
,
1054 "<stateVariable sendEvents=\"");
1055 #ifdef ENABLE_EVENTS
1056 str
= strcat_str(str
, len
, &tmplen
, (vars
[i
].itype
& 0x80)?"yes":"no");
1058 /* for the moment always send no. Wait for SUBSCRIBE implementation
1059 * before setting it to yes */
1060 str
= strcat_str(str
, len
, &tmplen
, "no");
1062 str
= strcat_str(str
, len
, &tmplen
, "\"><name>");
1063 str
= strcat_str(str
, len
, &tmplen
, vars
[i
].name
);
1064 str
= strcat_str(str
, len
, &tmplen
, "</name><dataType>");
1065 str
= strcat_str(str
, len
, &tmplen
, upnptypes
[vars
[i
].itype
& 0x0f]);
1066 str
= strcat_str(str
, len
, &tmplen
, "</dataType>");
1067 if(vars
[i
].iallowedlist
)
1069 if((vars
[i
].itype
& 0x0f) == 0)
1072 str
= strcat_str(str
, len
, &tmplen
, "<allowedValueList>");
1073 for(j
=vars
[i
].iallowedlist
; upnpallowedvalues
[j
]; j
++)
1075 str
= strcat_str(str
, len
, &tmplen
, "<allowedValue>");
1076 str
= strcat_str(str
, len
, &tmplen
, upnpallowedvalues
[j
]);
1077 str
= strcat_str(str
, len
, &tmplen
, "</allowedValue>");
1079 str
= strcat_str(str
, len
, &tmplen
, "</allowedValueList>");
1082 str
= strcat_str(str
, len
, &tmplen
, "<allowedValueRange><minimum>");
1083 str
= strcat_int(str
, len
, &tmplen
, upnpallowedranges
[vars
[i
].iallowedlist
]);
1084 str
= strcat_str(str
, len
, &tmplen
, "</minimum><maximum>");
1085 str
= strcat_int(str
, len
, &tmplen
, upnpallowedranges
[vars
[i
].iallowedlist
+1]);
1086 str
= strcat_str(str
, len
, &tmplen
, "</maximum></allowedValueRange>");
1089 /*if(vars[i].defaultValue) */
1090 if(vars
[i
].idefault
)
1092 str
= strcat_str(str
, len
, &tmplen
, "<defaultValue>");
1093 /*str = strcat_str(str, len, &tmplen, vars[i].defaultValue); */
1094 str
= strcat_str(str
, len
, &tmplen
, upnpdefaultvalues
[vars
[i
].idefault
]);
1095 str
= strcat_str(str
, len
, &tmplen
, "</defaultValue>");
1097 str
= strcat_str(str
, len
, &tmplen
, "</stateVariable>");
1098 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
1101 str
= strcat_str(str
, len
, &tmplen
, "</serviceStateTable></scpd>");
1107 * Generate the WANIPConnection xml description */
1109 genWANIPCn(int * len
)
1111 return genServiceDesc(len
, &scpdWANIPCn
);
1115 * Generate the WANInterfaceConfig xml description. */
1117 genWANCfg(int * len
)
1119 return genServiceDesc(len
, &scpdWANCfg
);
1122 #ifdef ENABLE_L3F_SERVICE
1126 return genServiceDesc(len
, &scpdL3F
);
1130 #ifdef ENABLE_6FC_SERVICE
1134 return genServiceDesc(len
, &scpd6FC
);
1138 #ifdef ENABLE_DP_SERVICE
1142 return genServiceDesc(len
, &scpdDP
);
1146 #ifdef ENABLE_EVENTS
1148 genEventVars(int * len
, const struct serviceDesc
* s
)
1151 const struct stateVar
* v
;
1155 str
= (char *)malloc(tmplen
);
1159 v
= s
->serviceStateTable
;
1160 str
= strcat_str(str
, len
, &tmplen
, "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">");
1162 if(v
->itype
& 0x80) {
1163 str
= strcat_str(str
, len
, &tmplen
, "<e:property><");
1164 str
= strcat_str(str
, len
, &tmplen
, v
->name
);
1165 str
= strcat_str(str
, len
, &tmplen
, ">");
1166 /*printf("<e:property><%s>", v->name);*/
1167 switch(v
->ieventvalue
) {
1170 case CONNECTIONSTATUS_MAGICALVALUE
:
1171 /* or get_wan_connection_status_str(ext_if_name) */
1172 str
= strcat_str(str
, len
, &tmplen
,
1173 upnpallowedvalues
[18 + get_wan_connection_status(ext_if_name
)]);
1175 #ifdef ENABLE_6FC_SERVICE
1176 case FIREWALLENABLED_MAGICALVALUE
:
1177 /* see 2.4.2 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
1178 snprintf(tmp
, sizeof(tmp
), "%d",
1179 GETFLAG(IPV6FCFWDISABLEDMASK
) ? 0 : 1);
1180 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1182 case INBOUNDPINHOLEALLOWED_MAGICALVALUE
:
1183 /* see 2.4.3 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
1184 snprintf(tmp
, sizeof(tmp
), "%d",
1185 GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK
) ? 0 : 1);
1186 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1190 case SYSTEMUPDATEID_MAGICALVALUE
:
1191 /* Please read section 2.3.23 SystemUpdateID
1192 * of UPnP-gw-WANIPConnection-v2-Service.pdf */
1193 snprintf(tmp
, sizeof(tmp
), "%d",
1194 1/* system update id */);
1195 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1198 case PORTMAPPINGNUMBEROFENTRIES_MAGICALVALUE
:
1199 /* Port mapping number of entries magical value */
1200 snprintf(tmp
, sizeof(tmp
), "%d",
1201 upnp_get_portmapping_number_of_entries());
1202 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1204 case EXTERNALIPADDRESS_MAGICALVALUE
:
1205 /* External ip address magical value */
1207 str
= strcat_str(str
, len
, &tmplen
, use_ext_ip_addr
);
1209 char ext_ip_addr
[INET_ADDRSTRLEN
];
1210 if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
, NULL
, NULL
) < 0) {
1211 str
= strcat_str(str
, len
, &tmplen
, "0.0.0.0");
1213 str
= strcat_str(str
, len
, &tmplen
, ext_ip_addr
);
1217 case DEFAULTCONNECTIONSERVICE_MAGICALVALUE
:
1218 /* DefaultConnectionService magical value */
1219 str
= strcat_str(str
, len
, &tmplen
, uuidvalue_wcd
);
1221 str
= strcat_str(str
, len
, &tmplen
, ":WANConnectionDevice:2,urn:upnp-org:serviceId:WANIPConn1");
1223 str
= strcat_str(str
, len
, &tmplen
, ":WANConnectionDevice:1,urn:upnp-org:serviceId:WANIPConn1");
1227 str
= strcat_str(str
, len
, &tmplen
, upnpallowedvalues
[v
->ieventvalue
]);
1229 str
= strcat_str(str
, len
, &tmplen
, "</");
1230 str
= strcat_str(str
, len
, &tmplen
, v
->name
);
1231 str
= strcat_str(str
, len
, &tmplen
, "></e:property>");
1232 /*printf("</%s></e:property>\n", v->name);*/
1236 str
= strcat_str(str
, len
, &tmplen
, "</e:propertyset>");
1238 printf("</e:propertyset>\n");
1240 printf("%d\n", tmplen
);
1247 getVarsWANIPCn(int * l
)
1249 return genEventVars(l
,
1254 getVarsWANCfg(int * l
)
1256 return genEventVars(l
,
1260 #ifdef ENABLE_L3F_SERVICE
1264 return genEventVars(l
,
1269 #ifdef ENABLE_6FC_SERVICE
1273 return genEventVars(l
,
1278 #ifdef ENABLE_DP_SERVICE
1282 return genEventVars(l
,
1287 #endif /* ENABLE_EVENTS */