1 /* $Id: upnpdescgen.c,v 1.72 2013/03/23 10:46:55 nanard Exp $ */
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2013 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 {"/friendlyName", friendly_name
/*ROOTDEV_FRIENDLYNAME*/}, /* required */
149 {"/manufacturer", ROOTDEV_MANUFACTURER
}, /* required */
151 {"/manufacturerURL", ROOTDEV_MANUFACTURERURL
}, /* optional */
152 {"/modelDescription", ROOTDEV_MODELDESCRIPTION
}, /* recommended */
153 {"/modelName", ROOTDEV_MODELNAME
}, /* required */
154 {"/modelNumber", modelnumber
},
155 {"/modelURL", ROOTDEV_MODELURL
},
156 {"/serialNumber", serialnumber
},
157 {"/UDN", uuidvalue
}, /* required */
158 /* see if /UPC is needed. */
159 #ifdef ENABLE_6FC_SERVICE
160 #define SERVICES_OFFSET 63
162 #define SERVICES_OFFSET 58
164 #if defined(ENABLE_L3F_SERVICE) || defined(HAS_DUMMY_SERVICE) || defined(ENABLE_DP_SERVICE)
165 /* here we dening Services for the root device :
166 * L3F and DUMMY and DeviceProtection */
167 #ifdef ENABLE_L3F_SERVICE
172 #ifdef HAS_DUMMY_SERVICE
177 #ifdef ENABLE_DP_SERVICE
182 #define NSERVICES (NSERVICES1+NSERVICES2+NSERVICES3)
183 {"serviceList", INITHELPER(SERVICES_OFFSET
,NSERVICES
)},
184 {"deviceList", INITHELPER(18,1)},
185 {"/presentationURL", presentationurl
}, /* recommended */
187 {"deviceList", INITHELPER(18,1)},
188 {"/presentationURL", presentationurl
}, /* recommended */
192 {"device", INITHELPER(19,13)},
194 {"/deviceType", DEVICE_TYPE_WAN
}, /* required */
195 /* urn:schemas-upnp-org:device:WANDevice:1 or 2 */
196 {"/friendlyName", WANDEV_FRIENDLYNAME
},
197 {"/manufacturer", WANDEV_MANUFACTURER
},
198 {"/manufacturerURL", WANDEV_MANUFACTURERURL
},
199 {"/modelDescription" , WANDEV_MODELDESCRIPTION
},
200 {"/modelName", WANDEV_MODELNAME
},
201 {"/modelNumber", WANDEV_MODELNUMBER
},
202 {"/modelURL", WANDEV_MODELURL
},
203 {"/serialNumber", serialnumber
},
205 {"/UPC", WANDEV_UPC
}, /* UPC (=12 digit barcode) is optional */
207 {"serviceList", INITHELPER(32,1)},
208 {"deviceList", INITHELPER(38,1)},
210 {"service", INITHELPER(33,5)},
213 "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"},
214 /*{"/serviceId", "urn:upnp-org:serviceId:WANCommonInterfaceConfig"}, */
215 {"/serviceId", "urn:upnp-org:serviceId:WANCommonIFC1"}, /* required */
216 {"/controlURL", WANCFG_CONTROLURL
},
217 {"/eventSubURL", WANCFG_EVENTURL
},
218 {"/SCPDURL", WANCFG_PATH
},
220 {"device", INITHELPER(39,12)},
222 {"/deviceType", DEVICE_TYPE_WANC
},
223 /* urn:schemas-upnp-org:device:WANConnectionDevice:1 or 2 */
224 {"/friendlyName", WANCDEV_FRIENDLYNAME
},
225 {"/manufacturer", WANCDEV_MANUFACTURER
},
226 {"/manufacturerURL", WANCDEV_MANUFACTURERURL
},
227 {"/modelDescription", WANCDEV_MODELDESCRIPTION
},
228 {"/modelName", WANCDEV_MODELNAME
},
229 {"/modelNumber", WANCDEV_MODELNUMBER
},
230 {"/modelURL", WANCDEV_MODELURL
},
231 {"/serialNumber", serialnumber
},
233 {"/UPC", WANCDEV_UPC
}, /* UPC (=12 digit Barcode) is optional */
234 #ifdef ENABLE_6FC_SERVICE
235 {"serviceList", INITHELPER(51,2)},
237 {"serviceList", INITHELPER(51,1)},
240 {"service", INITHELPER(53,5)},
241 {"service", INITHELPER(58,5)},
243 {"/serviceType", SERVICE_TYPE_WANIPC
},
244 /* urn:schemas-upnp-org:service:WANIPConnection:2 for v2 */
245 {"/serviceId", SERVICE_ID_WANIPC
},
246 /* urn:upnp-org:serviceId:WANIPConn1 or 2 */
247 {"/controlURL", WANIPC_CONTROLURL
},
248 {"/eventSubURL", WANIPC_EVENTURL
},
249 {"/SCPDURL", WANIPC_PATH
},
250 #ifdef ENABLE_6FC_SERVICE
252 {"/serviceType", "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"},
253 {"/serviceId", "urn:upnp-org:serviceId:WANIPv6FC1"},
254 {"/controlURL", WANIP6FC_CONTROLURL
},
255 {"/eventSubURL", WANIP6FC_EVENTURL
},
256 {"/SCPDURL", WANIP6FC_PATH
},
258 /* 58 / 63 = SERVICES_OFFSET*/
259 #if defined(HAS_DUMMY_SERVICE) || defined(ENABLE_L3F_SERVICE) || defined(ENABLE_DP_SERVICE)
260 {"service", INITHELPER(SERVICES_OFFSET
+2,5)},
261 {"service", INITHELPER(SERVICES_OFFSET
+7,5)},
263 #ifdef HAS_DUMMY_SERVICE
264 /* 60 / 65 = SERVICES_OFFSET+2 */
265 {"/serviceType", "urn:schemas-dummy-com:service:Dummy:1"},
266 {"/serviceId", "urn:dummy-com:serviceId:dummy1"},
267 {"/controlURL", "/dummy"},
268 {"/eventSubURL", "/dummy"},
269 {"/SCPDURL", DUMMY_PATH
},
271 #ifdef ENABLE_L3F_SERVICE
272 /* 60 / 65 = SERVICES_OFFSET+2 */
273 {"/serviceType", "urn:schemas-upnp-org:service:Layer3Forwarding:1"},
274 {"/serviceId", "urn:upnp-org:serviceId:Layer3Forwarding1"},
275 {"/controlURL", L3F_CONTROLURL
}, /* The Layer3Forwarding service is only */
276 {"/eventSubURL", L3F_EVENTURL
}, /* recommended, not mandatory */
277 {"/SCPDURL", L3F_PATH
},
279 #ifdef ENABLE_DP_SERVICE
280 /* InternetGatewayDevice v2 :
281 * it is RECOMMEDED that DeviceProtection service is implemented and applied.
282 * If DeviceProtection is not implemented and applied, it is RECOMMENDED
283 * that control points are able to access only actions and parameters defined
285 /* 65 / 70 = SERVICES_OFFSET+7 */
286 {"/serviceType", "urn:schemas-upnp-org:service:DeviceProtection:1"},
287 {"/serviceId", "urn:upnp-org:serviceId:DeviceProtection1"},
288 {"/controlURL", DP_CONTROLURL
},
289 {"/eventSubURL", DP_EVENTURL
},
290 {"/SCPDURL", DP_PATH
},
296 /* see UPnP_IGD_WANIPConnection 1.0.pdf
297 static struct XMLElt scpdWANIPCn[] =
299 {root_service, {INITHELPER(1,2)}},
303 static const struct argument AddPortMappingArgs
[] =
305 {1, 11}, /* RemoteHost */
306 {1, 12}, /* ExternalPort */
307 {1, 14}, /* PortMappingProtocol */
308 {1, 13}, /* InternalPort */
309 {1, 15}, /* InternalClient */
310 {1, 9}, /* PortMappingEnabled */
311 {1, 16}, /* PortMappingDescription */
312 {1, 10}, /* PortMappingLeaseDuration */
317 static const struct argument AddAnyPortMappingArgs
[] =
319 {1, 11}, /* RemoteHost */
320 {1, 12}, /* ExternalPort */
321 {1, 14}, /* PortMappingProtocol */
322 {1, 13}, /* InternalPort */
323 {1, 15}, /* InternalClient */
324 {1, 9}, /* PortMappingEnabled */
325 {1, 16}, /* PortMappingDescription */
326 {1, 10}, /* PortMappingLeaseDuration */
327 {2, 12}, /* NewReservedPort / ExternalPort */
331 static const struct argument DeletePortMappingRangeArgs
[] =
333 {1|(1<<2), 12}, /* NewStartPort / ExternalPort */
334 {1|(2<<2), 12}, /* NewEndPort / ExternalPort */
335 {1, 14}, /* NewProtocol / PortMappingProtocol */
336 {1, 18}, /* NewManage / A_ARG_TYPE_Manage */
340 static const struct argument GetListOfPortMappingsArgs
[] =
342 {1|(1<<2), 12}, /* NewStartPort / ExternalPort */
343 {1|(2<<2), 12}, /* NewEndPort / ExternalPort */
344 {1, 14}, /* NewProtocol / PortMappingProtocol */
345 {1, 18}, /* NewManage / A_ARG_TYPE_Manage */
346 {1, 8}, /* NewNumberOfPorts / PortMappingNumberOfEntries */
347 {2, 19}, /* NewPortListing / A_ARG_TYPE_PortListing */
352 static const struct argument GetExternalIPAddressArgs
[] =
358 static const struct argument DeletePortMappingArgs
[] =
366 static const struct argument SetConnectionTypeArgs
[] =
372 static const struct argument GetConnectionTypeInfoArgs
[] =
379 static const struct argument GetStatusInfoArgs
[] =
387 static const struct argument GetNATRSIPStatusArgs
[] =
394 static const struct argument GetGenericPortMappingEntryArgs
[] =
408 static const struct argument GetSpecificPortMappingEntryArgs
[] =
421 static const struct action WANIPCnActions
[] =
423 {"SetConnectionType", SetConnectionTypeArgs
}, /* R */
424 {"GetConnectionTypeInfo", GetConnectionTypeInfoArgs
}, /* R */
425 {"RequestConnection", 0}, /* R */
426 /*{"RequestTermination", 0},*/ /* O */
427 {"ForceTermination", 0}, /* R */
428 /*{"SetAutoDisconnectTime", 0},*/ /* O */
429 /*{"SetIdleDisconnectTime", 0},*/ /* O */
430 /*{"SetWarnDisconnectDelay", 0}, */ /* O */
431 {"GetStatusInfo", GetStatusInfoArgs
}, /* R */
432 /*GetAutoDisconnectTime*/ /* O */
433 /*GetIdleDisconnectTime*/ /* O */
434 /*GetWarnDisconnectDelay*/ /* O */
435 {"GetNATRSIPStatus", GetNATRSIPStatusArgs
}, /* R */
436 {"GetGenericPortMappingEntry", GetGenericPortMappingEntryArgs
}, /* R */
437 {"GetSpecificPortMappingEntry", GetSpecificPortMappingEntryArgs
}, /* R */
438 {"AddPortMapping", AddPortMappingArgs
}, /* R */
439 {"DeletePortMapping", DeletePortMappingArgs
}, /* R */
440 {"GetExternalIPAddress", GetExternalIPAddressArgs
}, /* R */
442 {"DeletePortMappingRange", DeletePortMappingRangeArgs
}, /* R, IGD v2 */
443 {"GetListOfPortMappings", GetListOfPortMappingsArgs
}, /* R, IGD v2 */
444 {"AddAnyPortMapping", AddAnyPortMappingArgs
}, /* R, IGD v2 */
447 {"AddPortMapping", AddPortMappingArgs
}, /* R */
448 {"GetExternalIPAddress", GetExternalIPAddressArgs
}, /* R */
449 {"DeletePortMapping", DeletePortMappingArgs
}, /* R */
450 {"SetConnectionType", SetConnectionTypeArgs
}, /* R */
451 {"GetConnectionTypeInfo", GetConnectionTypeInfoArgs
}, /* R */
452 {"RequestConnection", 0}, /* R */
453 {"ForceTermination", 0}, /* R */
454 {"GetStatusInfo", GetStatusInfoArgs
}, /* R */
455 {"GetNATRSIPStatus", GetNATRSIPStatusArgs
}, /* R */
456 {"GetGenericPortMappingEntry", GetGenericPortMappingEntryArgs
}, /* R */
457 {"GetSpecificPortMappingEntry", GetSpecificPortMappingEntryArgs
}, /* R */
458 /* added in v2 UPnP-gw-WANIPConnection-v2-Service.pdf */
460 {"AddAnyPortMapping", AddAnyPortMappingArgs
},
461 {"DeletePortMappingRange", DeletePortMappingRangeArgs
},
462 {"GetListOfPortMappings", GetListOfPortMappingsArgs
},
467 /* R=Required, O=Optional */
469 /* ignore "warning: missing initializer" */
470 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
472 static const struct stateVar WANIPCnVars
[] =
476 {"ConnectionType", 0, 0/*1*/}, /* required */
477 {"PossibleConnectionTypes", 0|0x80, 0, 14, 15},
479 {"ConnectionType", 0, 1, 14, 15}, /* required */
480 {"PossibleConnectionTypes", 0|0x80, 0, 0, 15},
482 * Allowed values : Unconfigured / IP_Routed / IP_Bridged */
483 {"ConnectionStatus", 0|0x80, 0/*1*/, 18,
484 CONNECTIONSTATUS_MAGICALVALUE
}, /* required */
485 /* Allowed Values : Unconfigured / Connecting(opt) / Connected
486 * PendingDisconnect(opt) / Disconnecting (opt)
488 {"Uptime", 3, 0}, /* Required */
489 {"LastConnectionError", 0, 0, 25}, /* required : */
490 /* Allowed Values : ERROR_NONE(req) / ERROR_COMMAND_ABORTED(opt)
491 * ERROR_NOT_ENABLED_FOR_INTERNET(opt)
492 * ERROR_USER_DISCONNECT(opt)
493 * ERROR_ISP_DISCONNECT(opt)
494 * ERROR_IDLE_DISCONNECT(opt)
495 * ERROR_FORCED_DISCONNECT(opt)
496 * ERROR_NO_CARRIER(opt)
497 * ERROR_IP_CONFIGURATION(opt)
498 * ERROR_UNKNOWN(opt) */
499 {"RSIPAvailable", 1, 0}, /* required */
500 {"NATEnabled", 1, 0}, /* required */
501 {"ExternalIPAddress", 0|0x80, 0, 0,
502 EXTERNALIPADDRESS_MAGICALVALUE
}, /* required. Default : empty string */
503 {"PortMappingNumberOfEntries", 2|0x80, 0, 0,
504 PORTMAPPINGNUMBEROFENTRIES_MAGICALVALUE
}, /* required >= 0 */
505 {"PortMappingEnabled", 1, 0}, /* Required */
507 {"PortMappingLeaseDuration", 3, 2, 1}, /* required */
508 /* TODO : for IGD v2 :
509 * <stateVariable sendEvents="no">
510 * <name>PortMappingLeaseDuration</name>
511 * <dataType>ui4</dataType>
512 * <defaultValue>Vendor-defined</defaultValue>
513 * <allowedValueRange>
514 * <minimum>0</minimum>
515 * <maximum>604800</maximum>
516 * </allowedValueRange>
517 * </stateVariable> */
518 {"RemoteHost", 0, 0}, /* required. Default : empty string */
519 {"ExternalPort", 2, 0}, /* required */
520 {"InternalPort", 2, 0, 3}, /* required */
521 {"PortMappingProtocol", 0, 0, 11}, /* required allowedValues: TCP/UDP */
522 {"InternalClient", 0, 0}, /* required */
523 {"PortMappingDescription", 0, 0}, /* required default: empty string */
524 /* added in v2 UPnP-gw-WANIPConnection-v2-Service.pdf */
526 {"SystemUpdateID", 3|0x80, 0, 0, SYSTEMUPDATEID_MAGICALVALUE
},
527 {"A_ARG_TYPE_Manage", 1, 0},
528 {"A_ARG_TYPE_PortListing", 0, 0},
533 static const struct serviceDesc scpdWANIPCn
=
534 { WANIPCnActions
, WANIPCnVars
};
537 /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
539 static const struct argument GetCommonLinkPropertiesArgs
[] =
548 static const struct argument GetTotalBytesSentArgs
[] =
554 static const struct argument GetTotalBytesReceivedArgs
[] =
560 static const struct argument GetTotalPacketsSentArgs
[] =
566 static const struct argument GetTotalPacketsReceivedArgs
[] =
572 static const struct action WANCfgActions
[] =
574 {"GetCommonLinkProperties", GetCommonLinkPropertiesArgs
}, /* Required */
575 {"GetTotalBytesSent", GetTotalBytesSentArgs
}, /* optional */
576 {"GetTotalBytesReceived", GetTotalBytesReceivedArgs
}, /* optional */
577 {"GetTotalPacketsSent", GetTotalPacketsSentArgs
}, /* optional */
578 {"GetTotalPacketsReceived", GetTotalPacketsReceivedArgs
}, /* optional */
582 /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
583 static const struct stateVar WANCfgVars
[] =
585 {"WANAccessType", 0, 0, 1},
586 /* Allowed Values : DSL / POTS / Cable / Ethernet
587 * Default value : empty string */
588 {"Layer1UpstreamMaxBitRate", 3, 0},
589 {"Layer1DownstreamMaxBitRate", 3, 0},
590 {"PhysicalLinkStatus", 0|0x80, 0, 6, 6},
592 * Up / Down / Initializing (optional) / Unavailable (optionnal)
595 {"TotalBytesSent", 3, 0}, /* Optional */
596 {"TotalBytesReceived", 3, 0}, /* Optional */
597 {"TotalPacketsSent", 3, 0}, /* Optional */
598 {"TotalPacketsReceived", 3, 0},/* Optional */
599 /*{"MaximumActiveConnections", 2, 0}, // allowed Range value // OPTIONAL */
600 /*{"WANAccessProvider", 0, 0},*/ /* Optional */
604 static const struct serviceDesc scpdWANCfg
=
605 { WANCfgActions
, WANCfgVars
};
607 #ifdef ENABLE_L3F_SERVICE
608 /* Read UPnP_IGD_Layer3Forwarding_1.0.pdf */
609 static const struct argument SetDefaultConnectionServiceArgs
[] =
615 static const struct argument GetDefaultConnectionServiceArgs
[] =
621 static const struct action L3FActions
[] =
623 {"SetDefaultConnectionService", SetDefaultConnectionServiceArgs
}, /* Req */
624 {"GetDefaultConnectionService", GetDefaultConnectionServiceArgs
}, /* Req */
628 static const struct stateVar L3FVars
[] =
630 {"DefaultConnectionService", 0|0x80, 0, 0,
631 DEFAULTCONNECTIONSERVICE_MAGICALVALUE
}, /* Required */
635 static const struct serviceDesc scpdL3F
=
636 { L3FActions
, L3FVars
};
639 #ifdef ENABLE_6FC_SERVICE
640 /* see UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
641 static const struct argument GetFirewallStatusArgs
[] =
643 {2|0x80, 0}, /* OUT : FirewallEnabled */
644 {2|0x80, 6}, /* OUT : InboundPinholeAllowed */
648 static const struct argument GetOutboundPinholeTimeoutArgs
[] =
650 {1|0x80|(3<<2), 1}, /* RemoteHost IN A_ARG_TYPE_IPv6Address */
651 {1|0x80|(4<<2), 2}, /* RemotePort IN A_ARG_TYPE_Port */
652 {1|0x80|(5<<2), 1}, /* InternalClient IN A_ARG_TYPE_IPv6Address */
653 {1|0x80|(6<<2), 2}, /* InternalPort IN A_ARG_TYPE_Port */
654 {1|0x80, 3}, /* Protocol IN A_ARG_TYPE_Protocol */
655 {2|0x80, 7}, /* OutboundPinholeTimeout OUT A_ARG_TYPE_OutboundPinholeTimeout */
659 static const struct argument AddPinholeArgs
[] =
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 {1|0x80, 5}, /* LeaseTime IN A_ARG_TYPE_LeaseTime */
667 {2|0x80, 4}, /* UniqueID OUT A_ARG_TYPE_UniqueID */
671 static const struct argument UpdatePinholeArgs
[] =
673 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
674 {1, 5}, /* LeaseTime IN A_ARG_TYPE_LeaseTime */
678 static const struct argument DeletePinholeArgs
[] =
680 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
684 static const struct argument GetPinholePacketsArgs
[] =
686 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
687 {2|0x80, 9}, /* PinholePackets OUT A_ARG_TYPE_PinholePackets */
691 static const struct argument CheckPinholeWorkingArgs
[] =
693 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
694 {2|0x80|(7<<2), 8}, /* IsWorking OUT A_ARG_TYPE_Boolean */
698 static const struct action IPv6FCActions
[] =
700 {"GetFirewallStatus", GetFirewallStatusArgs
}, /* Req */
701 {"GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs
}, /* Opt */
702 {"AddPinhole", AddPinholeArgs
}, /* Req */
703 {"UpdatePinhole", UpdatePinholeArgs
}, /* Req */
704 {"DeletePinhole", DeletePinholeArgs
}, /* Req */
705 {"GetPinholePackets", GetPinholePacketsArgs
}, /* Req */
706 {"CheckPinholeWorking", CheckPinholeWorkingArgs
}, /* Opt */
710 static const struct stateVar IPv6FCVars
[] =
712 {"FirewallEnabled", 1|0x80, 0, 0,
713 FIREWALLENABLED_MAGICALVALUE
}, /* Required */
714 {"A_ARG_TYPE_IPv6Address", 0, 0, 0, 0}, /* Required */
715 {"A_ARG_TYPE_Port", 2, 0, 0, 0}, /* Required */
716 {"A_ARG_TYPE_Protocol", 2, 0, 0, 0}, /* Required */
718 {"A_ARG_TYPE_UniqueID", 2, 0, 0, 0}, /* Required */
719 {"A_ARG_TYPE_LeaseTime", 3, 0, 5, 0}, /* Required */
720 {"InboundPinholeAllowed", 1|0x80, 0, 0,
721 INBOUNDPINHOLEALLOWED_MAGICALVALUE
}, /* Required */
722 {"A_ARG_TYPE_OutboundPinholeTimeout", 3, 0, 7, 0}, /* Optional */
724 {"A_ARG_TYPE_Boolean", 1, 0, 0, 0}, /* Optional */
725 {"A_ARG_TYPE_PinholePackets", 3, 0, 0, 0}, /* Required */
729 static const struct serviceDesc scpd6FC
=
730 { IPv6FCActions
, IPv6FCVars
};
733 #ifdef ENABLE_DP_SERVICE
734 /* UPnP-gw-DeviceProtection-v1-Service.pdf */
735 static const struct action DPActions
[] =
737 {"SendSetupMessage", 0},
738 {"GetSupportedProtocols", 0},
739 {"GetAssignedRoles", 0},
743 static const struct stateVar DPVars
[] =
745 {"SetupReady", 1|0x80},
746 {"SupportedProtocols", 0},
747 {"A_ARG_TYPE_ACL", 0},
748 {"A_ARG_TYPE_IdentityList", 0},
749 {"A_ARG_TYPE_Identity", 0},
750 {"A_ARG_TYPE_Base64", 4},
751 {"A_ARG_TYPE_String", 0},
755 static const struct serviceDesc scpdDP
=
756 { DPActions
, DPVars
};
760 * concatenate the string and use realloc to increase the
761 * memory buffer if needed. */
763 strcat_str(char * str
, int * len
, int * tmplen
, const char * s2
)
769 s2len
= (int)strlen(s2
);
770 if(*tmplen
<= (*len
+ s2len
))
773 newlen
= *tmplen
+ 256;
775 newlen
= *tmplen
+ s2len
+ 1;
776 p
= (char *)realloc(str
, newlen
);
777 if(p
== NULL
) /* handle a failure of realloc() */
782 /*strcpy(str + *len, s2); */
783 memcpy(str
+ *len
, s2
, s2len
+ 1);
789 * concatenate a character and use realloc to increase the
790 * size of the memory buffer if needed */
792 strcat_char(char * str
, int * len
, int * tmplen
, char c
)
796 if(*tmplen
<= (*len
+ 1))
799 p
= (char *)realloc(str
, *tmplen
);
800 if(p
== NULL
) /* handle a failure of realloc() */
813 * concatenate the string representation of the integer.
814 * call strcat_char() */
816 strcat_int(char * str
, int * len
, int * tmplen
, int i
)
822 str
= strcat_char(str
, len
, tmplen
, '-');
825 /* special case for 0 */
826 str
= strcat_char(str
, len
, tmplen
, '0');
830 while(i
&& j
< (int)sizeof(buf
)) {
831 buf
[j
++] = '0' + (i
% 10);
835 str
= strcat_char(str
, len
, tmplen
, buf
[--j
]);
840 /* iterative subroutine using a small stack
841 * This way, the progam stack usage is kept low */
843 genXML(char * str
, int * len
, int * tmplen
,
844 const struct XMLElt
* p
)
849 const char * eltname
, *s
;
854 const char * eltname
;
855 } pile
[16]; /* stack */
857 i
= 0; /* current node */
858 j
= 1; /* i + number of nodes*/
861 eltname
= p
[i
].eltname
;
864 if(eltname
[0] == '/')
866 if(p
[i
].data
&& p
[i
].data
[0])
868 /*printf("<%s>%s<%s>\n", eltname+1, p[i].data, eltname); */
869 str
= strcat_char(str
, len
, tmplen
, '<');
870 str
= strcat_str(str
, len
, tmplen
, eltname
+1);
871 str
= strcat_char(str
, len
, tmplen
, '>');
872 str
= strcat_str(str
, len
, tmplen
, p
[i
].data
);
873 str
= strcat_char(str
, len
, tmplen
, '<');
874 str
= strcat_str(str
, len
, tmplen
, eltname
);
875 str
= strcat_char(str
, len
, tmplen
, '>');
883 /*printf(" pile[%d]\t%d %d\n", top, i, j); */
886 /*printf("</%s>\n", pile[top].eltname); */
887 str
= strcat_char(str
, len
, tmplen
, '<');
888 str
= strcat_char(str
, len
, tmplen
, '/');
889 s
= pile
[top
].eltname
;
890 for(c
= *s
; c
> ' '; c
= *(++s
))
891 str
= strcat_char(str
, len
, tmplen
, c
);
892 str
= strcat_char(str
, len
, tmplen
, '>');
901 /*printf("<%s>\n", eltname); */
902 str
= strcat_char(str
, len
, tmplen
, '<');
903 str
= strcat_str(str
, len
, tmplen
, eltname
);
904 str
= strcat_char(str
, len
, tmplen
, '>');
905 k
= (unsigned long)p
[i
].data
;
909 /*printf(" +pile[%d]\t%d %d\n", top, i, j); */
912 pile
[top
].eltname
= eltname
;
918 * - Generate the root description of the UPnP device.
919 * - the len argument is used to return the length of
920 * the returned string.
921 * - tmp_uuid argument is used to build the uuid string */
923 genRootDesc(int * len
)
928 str
= (char *)malloc(tmplen
);
931 * len
= strlen(xmlver
);
932 /*strcpy(str, xmlver); */
933 memcpy(str
, xmlver
, *len
+ 1);
934 str
= genXML(str
, len
, &tmplen
, rootDesc
);
939 /* genServiceDesc() :
940 * Generate service description with allowed methods and
941 * related variables. */
943 genServiceDesc(int * len
, const struct serviceDesc
* s
)
946 const struct action
* acts
;
947 const struct stateVar
* vars
;
948 const struct argument
* args
;
953 str
= (char *)malloc(tmplen
);
956 /*strcpy(str, xmlver); */
957 *len
= strlen(xmlver
);
958 memcpy(str
, xmlver
, *len
+ 1);
960 acts
= s
->actionList
;
961 vars
= s
->serviceStateTable
;
963 str
= strcat_char(str
, len
, &tmplen
, '<');
964 str
= strcat_str(str
, len
, &tmplen
, root_service
);
965 str
= strcat_char(str
, len
, &tmplen
, '>');
967 str
= strcat_str(str
, len
, &tmplen
,
968 "<specVersion><major>1</major><minor>0</minor></specVersion>");
971 str
= strcat_str(str
, len
, &tmplen
, "<actionList>");
974 str
= strcat_str(str
, len
, &tmplen
, "<action><name>");
975 str
= strcat_str(str
, len
, &tmplen
, acts
[i
].name
);
976 str
= strcat_str(str
, len
, &tmplen
, "</name>");
981 str
= strcat_str(str
, len
, &tmplen
, "<argumentList>");
985 str
= strcat_str(str
, len
, &tmplen
, "<argument><name>");
986 if((args
[j
].dir
& 0x80) == 0) {
987 str
= strcat_str(str
, len
, &tmplen
, "New");
989 p
= vars
[args
[j
].relatedVar
].name
;
990 if(args
[j
].dir
& 0x7c) {
991 /* use magic values ... */
992 str
= strcat_str(str
, len
, &tmplen
, magicargname
[(args
[j
].dir
& 0x7c) >> 2]);
993 } else if(0 == memcmp(p
, "PortMapping", 11)
994 && 0 != memcmp(p
+ 11, "Description", 11)) {
995 if(0 == memcmp(p
+ 11, "NumberOfEntries", 15)) {
996 /* PortMappingNumberOfEntries */
998 if(0 == memcmp(acts
[i
].name
, "GetListOfPortMappings", 22)) {
999 str
= strcat_str(str
, len
, &tmplen
, "NumberOfPorts");
1001 str
= strcat_str(str
, len
, &tmplen
, "PortMappingIndex");
1004 str
= strcat_str(str
, len
, &tmplen
, "PortMappingIndex");
1007 /* PortMappingEnabled
1008 * PortMappingLeaseDuration
1009 * PortMappingProtocol */
1010 str
= strcat_str(str
, len
, &tmplen
, p
+ 11);
1013 } else if(0 == memcmp(p
, "A_ARG_TYPE_", 11)) {
1014 str
= strcat_str(str
, len
, &tmplen
, p
+ 11);
1015 } else if(0 == memcmp(p
, "ExternalPort", 13)
1017 && 0 == memcmp(acts
[i
].name
, "AddAnyPortMapping", 18)) {
1018 str
= strcat_str(str
, len
, &tmplen
, "ReservedPort");
1021 str
= strcat_str(str
, len
, &tmplen
, p
);
1023 str
= strcat_str(str
, len
, &tmplen
, "</name><direction>");
1024 str
= strcat_str(str
, len
, &tmplen
, (args
[j
].dir
&0x03)==1?"in":"out");
1025 str
= strcat_str(str
, len
, &tmplen
,
1026 "</direction><relatedStateVariable>");
1027 str
= strcat_str(str
, len
, &tmplen
, p
);
1028 str
= strcat_str(str
, len
, &tmplen
,
1029 "</relatedStateVariable></argument>");
1032 str
= strcat_str(str
, len
, &tmplen
,"</argumentList>");
1034 str
= strcat_str(str
, len
, &tmplen
, "</action>");
1035 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
1038 str
= strcat_str(str
, len
, &tmplen
, "</actionList><serviceStateTable>");
1042 str
= strcat_str(str
, len
, &tmplen
,
1043 "<stateVariable sendEvents=\"");
1044 #ifdef ENABLE_EVENTS
1045 str
= strcat_str(str
, len
, &tmplen
, (vars
[i
].itype
& 0x80)?"yes":"no");
1047 /* for the moment always send no. Wait for SUBSCRIBE implementation
1048 * before setting it to yes */
1049 str
= strcat_str(str
, len
, &tmplen
, "no");
1051 str
= strcat_str(str
, len
, &tmplen
, "\"><name>");
1052 str
= strcat_str(str
, len
, &tmplen
, vars
[i
].name
);
1053 str
= strcat_str(str
, len
, &tmplen
, "</name><dataType>");
1054 str
= strcat_str(str
, len
, &tmplen
, upnptypes
[vars
[i
].itype
& 0x0f]);
1055 str
= strcat_str(str
, len
, &tmplen
, "</dataType>");
1056 if(vars
[i
].iallowedlist
)
1058 if((vars
[i
].itype
& 0x0f) == 0)
1061 str
= strcat_str(str
, len
, &tmplen
, "<allowedValueList>");
1062 for(j
=vars
[i
].iallowedlist
; upnpallowedvalues
[j
]; j
++)
1064 str
= strcat_str(str
, len
, &tmplen
, "<allowedValue>");
1065 str
= strcat_str(str
, len
, &tmplen
, upnpallowedvalues
[j
]);
1066 str
= strcat_str(str
, len
, &tmplen
, "</allowedValue>");
1068 str
= strcat_str(str
, len
, &tmplen
, "</allowedValueList>");
1071 str
= strcat_str(str
, len
, &tmplen
, "<allowedValueRange><minimum>");
1072 str
= strcat_int(str
, len
, &tmplen
, upnpallowedranges
[vars
[i
].iallowedlist
]);
1073 str
= strcat_str(str
, len
, &tmplen
, "</minimum><maximum>");
1074 str
= strcat_int(str
, len
, &tmplen
, upnpallowedranges
[vars
[i
].iallowedlist
+1]);
1075 str
= strcat_str(str
, len
, &tmplen
, "</maximum></allowedValueRange>");
1078 /*if(vars[i].defaultValue) */
1079 if(vars
[i
].idefault
)
1081 str
= strcat_str(str
, len
, &tmplen
, "<defaultValue>");
1082 /*str = strcat_str(str, len, &tmplen, vars[i].defaultValue); */
1083 str
= strcat_str(str
, len
, &tmplen
, upnpdefaultvalues
[vars
[i
].idefault
]);
1084 str
= strcat_str(str
, len
, &tmplen
, "</defaultValue>");
1086 str
= strcat_str(str
, len
, &tmplen
, "</stateVariable>");
1087 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
1090 str
= strcat_str(str
, len
, &tmplen
, "</serviceStateTable></scpd>");
1096 * Generate the WANIPConnection xml description */
1098 genWANIPCn(int * len
)
1100 return genServiceDesc(len
, &scpdWANIPCn
);
1104 * Generate the WANInterfaceConfig xml description. */
1106 genWANCfg(int * len
)
1108 return genServiceDesc(len
, &scpdWANCfg
);
1111 #ifdef ENABLE_L3F_SERVICE
1115 return genServiceDesc(len
, &scpdL3F
);
1119 #ifdef ENABLE_6FC_SERVICE
1123 return genServiceDesc(len
, &scpd6FC
);
1127 #ifdef ENABLE_DP_SERVICE
1131 return genServiceDesc(len
, &scpdDP
);
1135 #ifdef ENABLE_EVENTS
1137 genEventVars(int * len
, const struct serviceDesc
* s
, const char * servns
)
1140 const struct stateVar
* v
;
1144 str
= (char *)malloc(tmplen
);
1148 v
= s
->serviceStateTable
;
1149 str
= strcat_str(str
, len
, &tmplen
, "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\" xmlns:s=\"");
1150 str
= strcat_str(str
, len
, &tmplen
, servns
);
1151 str
= strcat_str(str
, len
, &tmplen
, "\">");
1153 if(v
->itype
& 0x80) {
1154 str
= strcat_str(str
, len
, &tmplen
, "<e:property><s:");
1155 str
= strcat_str(str
, len
, &tmplen
, v
->name
);
1156 str
= strcat_str(str
, len
, &tmplen
, ">");
1157 /*printf("<e:property><s:%s>", v->name);*/
1158 switch(v
->ieventvalue
) {
1161 case CONNECTIONSTATUS_MAGICALVALUE
:
1162 /* or get_wan_connection_status_str(ext_if_name) */
1163 str
= strcat_str(str
, len
, &tmplen
,
1164 upnpallowedvalues
[18 + get_wan_connection_status(ext_if_name
)]);
1166 #ifdef ENABLE_6FC_SERVICE
1167 case FIREWALLENABLED_MAGICALVALUE
:
1168 /* see 2.4.2 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
1169 snprintf(tmp
, sizeof(tmp
), "%d",
1170 ipv6fc_firewall_enabled
);
1171 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1173 case INBOUNDPINHOLEALLOWED_MAGICALVALUE
:
1174 /* see 2.4.3 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
1175 snprintf(tmp
, sizeof(tmp
), "%d",
1176 ipv6fc_inbound_pinhole_allowed
);
1177 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1181 case SYSTEMUPDATEID_MAGICALVALUE
:
1182 /* Please read section 2.3.23 SystemUpdateID
1183 * of UPnP-gw-WANIPConnection-v2-Service.pdf */
1184 snprintf(tmp
, sizeof(tmp
), "%d",
1185 1/* system update id */);
1186 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1189 case PORTMAPPINGNUMBEROFENTRIES_MAGICALVALUE
:
1190 /* Port mapping number of entries magical value */
1191 snprintf(tmp
, sizeof(tmp
), "%d",
1192 upnp_get_portmapping_number_of_entries());
1193 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1195 case EXTERNALIPADDRESS_MAGICALVALUE
:
1196 /* External ip address magical value */
1198 str
= strcat_str(str
, len
, &tmplen
, use_ext_ip_addr
);
1200 char ext_ip_addr
[INET_ADDRSTRLEN
];
1201 if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
, NULL
, NULL
) < 0) {
1202 str
= strcat_str(str
, len
, &tmplen
, "0.0.0.0");
1204 str
= strcat_str(str
, len
, &tmplen
, ext_ip_addr
);
1208 case DEFAULTCONNECTIONSERVICE_MAGICALVALUE
:
1209 /* DefaultConnectionService magical value */
1210 str
= strcat_str(str
, len
, &tmplen
, uuidvalue
);
1212 str
= strcat_str(str
, len
, &tmplen
, ":WANConnectionDevice:2,urn:upnp-org:serviceId:WANIPConn1");
1214 str
= strcat_str(str
, len
, &tmplen
, ":WANConnectionDevice:1,urn:upnp-org:serviceId:WANIPConn1");
1218 str
= strcat_str(str
, len
, &tmplen
, upnpallowedvalues
[v
->ieventvalue
]);
1220 str
= strcat_str(str
, len
, &tmplen
, "</s:");
1221 str
= strcat_str(str
, len
, &tmplen
, v
->name
);
1222 str
= strcat_str(str
, len
, &tmplen
, "></e:property>");
1223 /*printf("</s:%s></e:property>\n", v->name);*/
1227 str
= strcat_str(str
, len
, &tmplen
, "</e:propertyset>");
1229 printf("</e:propertyset>\n");
1231 printf("%d\n", tmplen
);
1238 getVarsWANIPCn(int * l
)
1240 return genEventVars(l
,
1242 SERVICE_TYPE_WANIPC
);
1246 getVarsWANCfg(int * l
)
1248 return genEventVars(l
,
1250 "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1");
1253 #ifdef ENABLE_L3F_SERVICE
1257 return genEventVars(l
,
1259 "urn:schemas-upnp-org:service:Layer3Forwarding:1");
1263 #ifdef ENABLE_6FC_SERVICE
1267 return genEventVars(l
,
1269 "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1");
1273 #ifdef ENABLE_DP_SERVICE
1277 return genEventVars(l
,
1279 "urn:schemas-upnp-org:service:DeviceProtection:1");
1283 #endif /* ENABLE_EVENTS */