1 /* $Id: upnpdescgen.c,v 1.82 2016/02/16 12:15:02 nanard Exp $ */
2 /* vim: tabstop=4 shiftwidth=4 noexpandtab */
4 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
5 * (c) 2006-2016 Thomas Bernard
6 * This software is subject to the conditions detailed
7 * in the LICENCE file provided within the distribution */
15 #include "getifaddr.h"
16 #include "upnpredirect.h"
18 #include "upnpdescgen.h"
19 #include "miniupnpdpath.h"
20 #include "upnpglobalvars.h"
21 #include "upnpdescstrings.h"
23 #include "getconnstatus.h"
26 /* Event magical values codes */
27 #define SETUPREADY_MAGICALVALUE (248)
28 #define CONNECTIONSTATUS_MAGICALVALUE (249)
29 #define FIREWALLENABLED_MAGICALVALUE (250)
30 #define INBOUNDPINHOLEALLOWED_MAGICALVALUE (251)
31 #define SYSTEMUPDATEID_MAGICALVALUE (252)
32 #define PORTMAPPINGNUMBEROFENTRIES_MAGICALVALUE (253)
33 #define EXTERNALIPADDRESS_MAGICALVALUE (254)
34 #define DEFAULTCONNECTIONSERVICE_MAGICALVALUE (255)
37 static const char * const upnptypes
[] =
46 static const char * const upnpdefaultvalues
[] =
49 "IP_Routed"/*"Unconfigured"*/, /* 1 default value for ConnectionType */
50 "3600", /* 2 default value for PortMappingLeaseDuration */
51 "Unconfigured", /* 3 default value for ConnectionStatus */
52 "0", /* 4 default value for RSIPAvailable */
53 "1", /* 5 default value for NATEnabled */
54 "ERROR_NONE", /* 6 default value for LastConnectionError */
57 static const char * const upnpallowedvalues
[] =
73 "Unconfigured", /* 14 */
77 "Unconfigured", /* 18 */
84 "ERROR_NONE", /* 25 */
86 * ERROR_COMMAND_ABORTED
87 * ERROR_NOT_ENABLED_FOR_INTERNET
88 * ERROR_USER_DISCONNECT
89 * ERROR_ISP_DISCONNECT
90 * ERROR_IDLE_DISCONNECT
91 * ERROR_FORCED_DISCONNECT
93 * ERROR_IP_CONFIGURATION
100 static const int upnpallowedranges
[] = {
102 /* 1 PortMappingLeaseDuration */
111 /* 7 OutboundPinholeTimeout */
116 static const char * magicargname
[] = {
120 "RemoteHost", /* 3 */
121 "RemotePort", /* 4 */
122 "InternalClient", /* 5 */
123 "InternalPort", /* 6 */
125 #ifdef ENABLE_DP_SERVICE
126 "ProtocolType", /* 8 */
128 "OutMessage", /* 10 */
129 "ProtocolList", /* 11 */
131 #endif /* ENABLE_DP_SERVICE */
134 static const char xmlver
[] =
135 "<?xml version=\"1.0\"?>\r\n";
136 static const char root_service
[] =
137 "scpd xmlns=\"urn:schemas-upnp-org:service-1-0\"";
138 static const char root_device
[] =
139 "root xmlns=\"urn:schemas-upnp-org:device-1-0\"";
141 /* root Description of the UPnP Device
142 * fixed to match UPnP_IGD_InternetGatewayDevice 1.0.pdf
143 * Needs to be checked with UPnP-gw-InternetGatewayDevice-v2-Device.pdf
144 * presentationURL is only "recommended" but the router doesn't appears
145 * in "Network connections" in Windows XP if it is not present. */
146 static const struct XMLElt rootDesc
[] =
149 {root_device
, INITHELPER(1,2)},
150 {"specVersion", INITHELPER(3,2)},
151 #if defined(ENABLE_L3F_SERVICE) || defined(HAS_DUMMY_SERVICE) || defined(ENABLE_DP_SERVICE)
152 {"device", INITHELPER(5,13)},
154 {"device", INITHELPER(5,12)},
156 {"/major", UPNP_VERSION_MAJOR_STR
},
157 {"/minor", UPNP_VERSION_MINOR_STR
},
159 {"/deviceType", DEVICE_TYPE_IGD
},
160 /* urn:schemas-upnp-org:device:InternetGatewayDevice:1 or 2 */
161 #ifdef ENABLE_MANUFACTURER_INFO_CONFIGURATION
162 {"/friendlyName", friendly_name
/*ROOTDEV_FRIENDLYNAME*/}, /* required */
163 {"/manufacturer", manufacturer_name
/*ROOTDEV_MANUFACTURER*/}, /* required */
165 {"/manufacturerURL", manufacturer_url
/*ROOTDEV_MANUFACTURERURL*/}, /* optional */
166 {"/modelDescription", model_description
/*ROOTDEV_MODELDESCRIPTION*/}, /* recommended */
167 {"/modelName", model_name
/*ROOTDEV_MODELNAME*/}, /* required */
168 {"/modelNumber", modelnumber
},
169 {"/modelURL", model_url
/*ROOTDEV_MODELURL*/},
171 {"/friendlyName", ROOTDEV_FRIENDLYNAME
}, /* required */
172 {"/manufacturer", ROOTDEV_MANUFACTURER
}, /* required */
174 {"/manufacturerURL", ROOTDEV_MANUFACTURERURL
}, /* optional */
175 {"/modelDescription", ROOTDEV_MODELDESCRIPTION
}, /* recommended */
176 {"/modelName", ROOTDEV_MODELNAME
}, /* required */
177 {"/modelNumber", modelnumber
},
178 {"/modelURL", ROOTDEV_MODELURL
},
180 {"/serialNumber", serialnumber
},
181 {"/UDN", uuidvalue_igd
}, /* required */
182 /* see if /UPC is needed. */
183 #ifdef ENABLE_6FC_SERVICE
184 #define SERVICES_OFFSET 63
186 #define SERVICES_OFFSET 58
188 #if defined(ENABLE_L3F_SERVICE) || defined(HAS_DUMMY_SERVICE) || defined(ENABLE_DP_SERVICE)
189 /* here we dening Services for the root device :
190 * L3F and DUMMY and DeviceProtection */
191 #ifdef ENABLE_L3F_SERVICE
196 #ifdef HAS_DUMMY_SERVICE
201 #ifdef ENABLE_DP_SERVICE
206 #define NSERVICES (NSERVICES1+NSERVICES2+NSERVICES3)
207 {"serviceList", INITHELPER(SERVICES_OFFSET
,NSERVICES
)},
208 {"deviceList", INITHELPER(18,1)},
209 {"/presentationURL", presentationurl
}, /* recommended */
211 {"deviceList", INITHELPER(18,1)},
212 {"/presentationURL", presentationurl
}, /* recommended */
216 {"device", INITHELPER(19,13)},
218 {"/deviceType", DEVICE_TYPE_WAN
}, /* required */
219 /* urn:schemas-upnp-org:device:WANDevice:1 or 2 */
220 {"/friendlyName", WANDEV_FRIENDLYNAME
},
221 {"/manufacturer", WANDEV_MANUFACTURER
},
222 {"/manufacturerURL", WANDEV_MANUFACTURERURL
},
223 {"/modelDescription" , WANDEV_MODELDESCRIPTION
},
224 {"/modelName", WANDEV_MODELNAME
},
225 {"/modelNumber", WANDEV_MODELNUMBER
},
226 {"/modelURL", WANDEV_MODELURL
},
227 {"/serialNumber", serialnumber
},
228 {"/UDN", uuidvalue_wan
},
229 {"/UPC", WANDEV_UPC
}, /* UPC (=12 digit barcode) is optional */
231 {"serviceList", INITHELPER(32,1)},
232 {"deviceList", INITHELPER(38,1)},
234 {"service", INITHELPER(33,5)},
237 "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"},
238 /*{"/serviceId", "urn:upnp-org:serviceId:WANCommonInterfaceConfig"}, */
239 {"/serviceId", "urn:upnp-org:serviceId:WANCommonIFC1"}, /* required */
240 {"/SCPDURL", WANCFG_PATH
},
241 {"/controlURL", WANCFG_CONTROLURL
},
242 {"/eventSubURL", WANCFG_EVENTURL
},
244 {"device", INITHELPER(39,12)},
246 {"/deviceType", DEVICE_TYPE_WANC
},
247 /* urn:schemas-upnp-org:device:WANConnectionDevice:1 or 2 */
248 {"/friendlyName", WANCDEV_FRIENDLYNAME
},
249 {"/manufacturer", WANCDEV_MANUFACTURER
},
250 {"/manufacturerURL", WANCDEV_MANUFACTURERURL
},
251 {"/modelDescription", WANCDEV_MODELDESCRIPTION
},
252 {"/modelName", WANCDEV_MODELNAME
},
253 {"/modelNumber", WANCDEV_MODELNUMBER
},
254 {"/modelURL", WANCDEV_MODELURL
},
255 {"/serialNumber", serialnumber
},
256 {"/UDN", uuidvalue_wcd
},
257 {"/UPC", WANCDEV_UPC
}, /* UPC (=12 digit Barcode) is optional */
258 #ifdef ENABLE_6FC_SERVICE
259 {"serviceList", INITHELPER(51,2)},
261 {"serviceList", INITHELPER(51,1)},
264 {"service", INITHELPER(53,5)},
265 {"service", INITHELPER(58,5)},
267 {"/serviceType", SERVICE_TYPE_WANIPC
},
268 /* urn:schemas-upnp-org:service:WANIPConnection:2 for v2 */
269 {"/serviceId", SERVICE_ID_WANIPC
},
270 /* urn:upnp-org:serviceId:WANIPConn1 or 2 */
271 {"/SCPDURL", WANIPC_PATH
},
272 {"/controlURL", WANIPC_CONTROLURL
},
273 {"/eventSubURL", WANIPC_EVENTURL
},
274 #ifdef ENABLE_6FC_SERVICE
276 {"/serviceType", "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1"},
277 {"/serviceId", "urn:upnp-org:serviceId:WANIPv6Firewall1"},
278 {"/SCPDURL", WANIP6FC_PATH
},
279 {"/controlURL", WANIP6FC_CONTROLURL
},
280 {"/eventSubURL", WANIP6FC_EVENTURL
},
282 /* 58 / 63 = SERVICES_OFFSET*/
283 #if defined(HAS_DUMMY_SERVICE) || defined(ENABLE_L3F_SERVICE) || defined(ENABLE_DP_SERVICE)
284 {"service", INITHELPER(SERVICES_OFFSET
+2,5)},
285 {"service", INITHELPER(SERVICES_OFFSET
+7,5)},
287 #ifdef HAS_DUMMY_SERVICE
288 /* 60 / 65 = SERVICES_OFFSET+2 */
289 {"/serviceType", "urn:schemas-dummy-com:service:Dummy:1"},
290 {"/serviceId", "urn:dummy-com:serviceId:dummy1"},
291 {"/SCPDURL", DUMMY_PATH
},
292 {"/controlURL", "/dummy"},
293 {"/eventSubURL", "/dummy"},
295 #ifdef ENABLE_L3F_SERVICE
296 /* 60 / 65 = SERVICES_OFFSET+2 */
297 {"/serviceType", "urn:schemas-upnp-org:service:Layer3Forwarding:1"},
298 {"/serviceId", "urn:upnp-org:serviceId:L3Forwarding1"},
299 {"/SCPDURL", L3F_PATH
},
300 {"/controlURL", L3F_CONTROLURL
}, /* The Layer3Forwarding service is only */
301 {"/eventSubURL", L3F_EVENTURL
}, /* recommended, not mandatory */
303 #ifdef ENABLE_DP_SERVICE
304 /* InternetGatewayDevice v2 :
305 * it is RECOMMEDED that DeviceProtection service is implemented and applied.
306 * If DeviceProtection is not implemented and applied, it is RECOMMENDED
307 * that control points are able to access only actions and parameters defined
309 /* 65 / 70 = SERVICES_OFFSET+7 */
310 {"/serviceType", "urn:schemas-upnp-org:service:DeviceProtection:1"},
311 {"/serviceId", "urn:upnp-org:serviceId:DeviceProtection1"},
312 {"/SCPDURL", DP_PATH
},
313 {"/controlURL", DP_CONTROLURL
},
314 {"/eventSubURL", DP_EVENTURL
},
320 /* see UPnP_IGD_WANIPConnection 1.0.pdf
321 static struct XMLElt scpdWANIPCn[] =
323 {root_service, {INITHELPER(1,2)}},
327 static const struct argument AddPortMappingArgs
[] =
329 {1, 11}, /* RemoteHost */
330 {1, 12}, /* ExternalPort */
331 {1, 14}, /* PortMappingProtocol */
332 {1, 13}, /* InternalPort */
333 {1, 15}, /* InternalClient */
334 {1, 9}, /* PortMappingEnabled */
335 {1, 16}, /* PortMappingDescription */
336 {1, 10}, /* PortMappingLeaseDuration */
341 static const struct argument AddAnyPortMappingArgs
[] =
343 {1, 11}, /* RemoteHost */
344 {1, 12}, /* ExternalPort */
345 {1, 14}, /* PortMappingProtocol */
346 {1, 13}, /* InternalPort */
347 {1, 15}, /* InternalClient */
348 {1, 9}, /* PortMappingEnabled */
349 {1, 16}, /* PortMappingDescription */
350 {1, 10}, /* PortMappingLeaseDuration */
351 {2, 12}, /* NewReservedPort / ExternalPort */
355 static const struct argument DeletePortMappingRangeArgs
[] =
357 {1|(1<<2), 12}, /* NewStartPort / ExternalPort */
358 {1|(2<<2), 12}, /* NewEndPort / ExternalPort */
359 {1, 14}, /* NewProtocol / PortMappingProtocol */
360 {1, 18}, /* NewManage / A_ARG_TYPE_Manage */
364 static const struct argument GetListOfPortMappingsArgs
[] =
366 {1|(1<<2), 12}, /* NewStartPort / ExternalPort */
367 {1|(2<<2), 12}, /* NewEndPort / ExternalPort */
368 {1, 14}, /* NewProtocol / PortMappingProtocol */
369 {1, 18}, /* NewManage / A_ARG_TYPE_Manage */
370 {1, 8}, /* NewNumberOfPorts / PortMappingNumberOfEntries */
371 {2, 19}, /* NewPortListing / A_ARG_TYPE_PortListing */
376 static const struct argument GetExternalIPAddressArgs
[] =
382 static const struct argument DeletePortMappingArgs
[] =
384 {1, 11}, /* RemoteHost */
385 {1, 12}, /* ExternalPort */
386 {1, 14}, /* PortMappingProtocol */
390 static const struct argument SetConnectionTypeArgs
[] =
396 static const struct argument GetConnectionTypeInfoArgs
[] =
403 static const struct argument GetStatusInfoArgs
[] =
411 static const struct argument GetNATRSIPStatusArgs
[] =
418 static const struct argument GetGenericPortMappingEntryArgs
[] =
432 static const struct argument GetSpecificPortMappingEntryArgs
[] =
445 static const struct action WANIPCnActions
[] =
447 {"SetConnectionType", SetConnectionTypeArgs
}, /* R */
448 {"GetConnectionTypeInfo", GetConnectionTypeInfoArgs
}, /* R */
449 {"RequestConnection", 0}, /* R */
450 /*{"RequestTermination", 0},*/ /* O */
451 {"ForceTermination", 0}, /* R */
452 /*{"SetAutoDisconnectTime", 0},*/ /* O */
453 /*{"SetIdleDisconnectTime", 0},*/ /* O */
454 /*{"SetWarnDisconnectDelay", 0}, */ /* O */
455 {"GetStatusInfo", GetStatusInfoArgs
}, /* R */
456 /*GetAutoDisconnectTime*/ /* O */
457 /*GetIdleDisconnectTime*/ /* O */
458 /*GetWarnDisconnectDelay*/ /* O */
459 {"GetNATRSIPStatus", GetNATRSIPStatusArgs
}, /* R */
460 {"GetGenericPortMappingEntry", GetGenericPortMappingEntryArgs
}, /* R */
461 {"GetSpecificPortMappingEntry", GetSpecificPortMappingEntryArgs
}, /* R */
462 {"AddPortMapping", AddPortMappingArgs
}, /* R */
463 {"DeletePortMapping", DeletePortMappingArgs
}, /* R */
464 {"GetExternalIPAddress", GetExternalIPAddressArgs
}, /* R */
466 {"DeletePortMappingRange", DeletePortMappingRangeArgs
}, /* R, IGD v2 */
467 {"GetListOfPortMappings", GetListOfPortMappingsArgs
}, /* R, IGD v2 */
468 {"AddAnyPortMapping", AddAnyPortMappingArgs
}, /* R, IGD v2 */
471 {"AddPortMapping", AddPortMappingArgs
}, /* R */
472 {"GetExternalIPAddress", GetExternalIPAddressArgs
}, /* R */
473 {"DeletePortMapping", DeletePortMappingArgs
}, /* R */
474 {"SetConnectionType", SetConnectionTypeArgs
}, /* R */
475 {"GetConnectionTypeInfo", GetConnectionTypeInfoArgs
}, /* R */
476 {"RequestConnection", 0}, /* R */
477 {"ForceTermination", 0}, /* R */
478 {"GetStatusInfo", GetStatusInfoArgs
}, /* R */
479 {"GetNATRSIPStatus", GetNATRSIPStatusArgs
}, /* R */
480 {"GetGenericPortMappingEntry", GetGenericPortMappingEntryArgs
}, /* R */
481 {"GetSpecificPortMappingEntry", GetSpecificPortMappingEntryArgs
}, /* R */
482 /* added in v2 UPnP-gw-WANIPConnection-v2-Service.pdf */
484 {"AddAnyPortMapping", AddAnyPortMappingArgs
},
485 {"DeletePortMappingRange", DeletePortMappingRangeArgs
},
486 {"GetListOfPortMappings", GetListOfPortMappingsArgs
},
491 /* R=Required, O=Optional */
493 /* ignore "warning: missing initializer" */
494 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
497 * {name, itype(&event), idefault, iallowedlist, ieventvalue} */
498 static const struct stateVar WANIPCnVars
[] =
502 {"ConnectionType", 0, 0/*1*/}, /* required */
503 {"PossibleConnectionTypes", 0|0x80, 0, 14, 15},
505 {"ConnectionType", 0, 1, 14, 15}, /* required */
506 {"PossibleConnectionTypes", 0|0x80, 0, 0, 15},
508 {"ConnectionType", 0, 1, 0, 15}, /* required */
509 {"PossibleConnectionTypes", 0|0x80, 0, 14, 15},
512 * Allowed values : Unconfigured / IP_Routed / IP_Bridged */
513 {"ConnectionStatus", 0|0x80, 3, 18,
514 CONNECTIONSTATUS_MAGICALVALUE
}, /* required */
515 /* Allowed Values : Unconfigured / Connecting(opt) / Connected
516 * PendingDisconnect(opt) / Disconnecting (opt)
518 {"Uptime", 3, 0}, /* Required */
519 {"LastConnectionError", 0, 6, 25}, /* required : */
520 /* Allowed Values : ERROR_NONE(req) / ERROR_COMMAND_ABORTED(opt)
521 * ERROR_NOT_ENABLED_FOR_INTERNET(opt)
522 * ERROR_USER_DISCONNECT(opt)
523 * ERROR_ISP_DISCONNECT(opt)
524 * ERROR_IDLE_DISCONNECT(opt)
525 * ERROR_FORCED_DISCONNECT(opt)
526 * ERROR_NO_CARRIER(opt)
527 * ERROR_IP_CONFIGURATION(opt)
528 * ERROR_UNKNOWN(opt) */
529 {"RSIPAvailable", 1, 4}, /* required */
530 {"NATEnabled", 1, 5}, /* required */
531 {"ExternalIPAddress", 0|0x80, 0, 0,
532 EXTERNALIPADDRESS_MAGICALVALUE
}, /* required. Default : empty string */
533 {"PortMappingNumberOfEntries", 2|0x80, 0, 0,
534 PORTMAPPINGNUMBEROFENTRIES_MAGICALVALUE
}, /* required >= 0 */
535 {"PortMappingEnabled", 1, 0}, /* Required */
537 {"PortMappingLeaseDuration", 3, 2, 1}, /* required */
538 /* TODO : for IGD v2 :
539 * <stateVariable sendEvents="no">
540 * <name>PortMappingLeaseDuration</name>
541 * <dataType>ui4</dataType>
542 * <defaultValue>Vendor-defined</defaultValue>
543 * <allowedValueRange>
544 * <minimum>0</minimum>
545 * <maximum>604800</maximum>
546 * </allowedValueRange>
547 * </stateVariable> */
548 {"RemoteHost", 0, 0}, /* required. Default : empty string */
549 {"ExternalPort", 2, 0}, /* required */
550 {"InternalPort", 2, 0, 3}, /* required */
551 {"PortMappingProtocol", 0, 0, 11}, /* required allowedValues: TCP/UDP */
552 {"InternalClient", 0, 0}, /* required */
553 {"PortMappingDescription", 0, 0}, /* required default: empty string */
554 /* added in v2 UPnP-gw-WANIPConnection-v2-Service.pdf */
556 {"SystemUpdateID", 3|0x80, 0, 0, SYSTEMUPDATEID_MAGICALVALUE
},
557 {"A_ARG_TYPE_Manage", 1, 0},
558 {"A_ARG_TYPE_PortListing", 0, 0},
563 static const struct serviceDesc scpdWANIPCn
=
564 { WANIPCnActions
, WANIPCnVars
};
567 /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
569 static const struct argument GetCommonLinkPropertiesArgs
[] =
578 static const struct argument GetTotalBytesSentArgs
[] =
584 static const struct argument GetTotalBytesReceivedArgs
[] =
590 static const struct argument GetTotalPacketsSentArgs
[] =
596 static const struct argument GetTotalPacketsReceivedArgs
[] =
602 static const struct action WANCfgActions
[] =
604 {"GetCommonLinkProperties", GetCommonLinkPropertiesArgs
}, /* Required */
605 {"GetTotalBytesSent", GetTotalBytesSentArgs
}, /* optional */
606 {"GetTotalBytesReceived", GetTotalBytesReceivedArgs
}, /* optional */
607 {"GetTotalPacketsSent", GetTotalPacketsSentArgs
}, /* optional */
608 {"GetTotalPacketsReceived", GetTotalPacketsReceivedArgs
}, /* optional */
612 /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
613 static const struct stateVar WANCfgVars
[] =
615 {"WANAccessType", 0, 0, 1},
616 /* Allowed Values : DSL / POTS / Cable / Ethernet
617 * Default value : empty string */
618 {"Layer1UpstreamMaxBitRate", 3, 0},
619 {"Layer1DownstreamMaxBitRate", 3, 0},
620 {"PhysicalLinkStatus", 0|0x80, 0, 6, 6},
622 * Up / Down / Initializing (optional) / Unavailable (optionnal)
625 {"TotalBytesSent", 3, 0}, /* Optional */
626 {"TotalBytesReceived", 3, 0}, /* Optional */
627 {"TotalPacketsSent", 3, 0}, /* Optional */
628 {"TotalPacketsReceived", 3, 0},/* Optional */
629 /*{"MaximumActiveConnections", 2, 0}, // allowed Range value // OPTIONAL */
630 /*{"WANAccessProvider", 0, 0},*/ /* Optional */
634 static const struct serviceDesc scpdWANCfg
=
635 { WANCfgActions
, WANCfgVars
};
637 #ifdef ENABLE_L3F_SERVICE
638 /* Read UPnP_IGD_Layer3Forwarding_1.0.pdf */
639 static const struct argument SetDefaultConnectionServiceArgs
[] =
645 static const struct argument GetDefaultConnectionServiceArgs
[] =
651 static const struct action L3FActions
[] =
653 {"SetDefaultConnectionService", SetDefaultConnectionServiceArgs
}, /* Req */
654 {"GetDefaultConnectionService", GetDefaultConnectionServiceArgs
}, /* Req */
658 static const struct stateVar L3FVars
[] =
660 {"DefaultConnectionService", 0|0x80, 0, 0,
661 DEFAULTCONNECTIONSERVICE_MAGICALVALUE
}, /* Required */
665 static const struct serviceDesc scpdL3F
=
666 { L3FActions
, L3FVars
};
669 #ifdef ENABLE_6FC_SERVICE
670 /* see UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
671 static const struct argument GetFirewallStatusArgs
[] =
673 {2|0x80, 0}, /* OUT : FirewallEnabled */
674 {2|0x80, 6}, /* OUT : InboundPinholeAllowed */
678 static const struct argument GetOutboundPinholeTimeoutArgs
[] =
680 {1|0x80|(3<<2), 1}, /* RemoteHost IN A_ARG_TYPE_IPv6Address */
681 {1|0x80|(4<<2), 2}, /* RemotePort IN A_ARG_TYPE_Port */
682 {1|0x80|(5<<2), 1}, /* InternalClient IN A_ARG_TYPE_IPv6Address */
683 {1|0x80|(6<<2), 2}, /* InternalPort IN A_ARG_TYPE_Port */
684 {1|0x80, 3}, /* Protocol IN A_ARG_TYPE_Protocol */
685 {2|0x80, 7}, /* OutboundPinholeTimeout OUT A_ARG_TYPE_OutboundPinholeTimeout */
689 static const struct argument AddPinholeArgs
[] =
691 {1|0x80|(3<<2), 1}, /* RemoteHost IN A_ARG_TYPE_IPv6Address */
692 {1|0x80|(4<<2), 2}, /* RemotePort IN A_ARG_TYPE_Port */
693 {1|0x80|(5<<2), 1}, /* InternalClient IN A_ARG_TYPE_IPv6Address */
694 {1|0x80|(6<<2), 2}, /* InternalPort IN A_ARG_TYPE_Port */
695 {1|0x80, 3}, /* Protocol IN A_ARG_TYPE_Protocol */
696 {1|0x80, 5}, /* LeaseTime IN A_ARG_TYPE_LeaseTime */
697 {2|0x80, 4}, /* UniqueID OUT A_ARG_TYPE_UniqueID */
701 static const struct argument UpdatePinholeArgs
[] =
703 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
704 {1, 5}, /* LeaseTime IN A_ARG_TYPE_LeaseTime */
708 static const struct argument DeletePinholeArgs
[] =
710 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
714 static const struct argument GetPinholePacketsArgs
[] =
716 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
717 {2|0x80, 9}, /* PinholePackets OUT A_ARG_TYPE_PinholePackets */
721 static const struct argument CheckPinholeWorkingArgs
[] =
723 {1|0x80, 4}, /* UniqueID IN A_ARG_TYPE_UniqueID */
724 {2|0x80|(7<<2), 8}, /* IsWorking OUT A_ARG_TYPE_Boolean */
728 static const struct action IPv6FCActions
[] =
730 {"GetFirewallStatus", GetFirewallStatusArgs
}, /* Req */
731 {"GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs
}, /* Opt */
732 {"AddPinhole", AddPinholeArgs
}, /* Req */
733 {"UpdatePinhole", UpdatePinholeArgs
}, /* Req */
734 {"DeletePinhole", DeletePinholeArgs
}, /* Req */
735 {"GetPinholePackets", GetPinholePacketsArgs
}, /* Req */
736 {"CheckPinholeWorking", CheckPinholeWorkingArgs
}, /* Opt */
740 static const struct stateVar IPv6FCVars
[] =
742 {"FirewallEnabled", 1|0x80, 0, 0,
743 FIREWALLENABLED_MAGICALVALUE
}, /* Required */
744 {"A_ARG_TYPE_IPv6Address", 0, 0, 0, 0}, /* Required */
745 {"A_ARG_TYPE_Port", 2, 0, 0, 0}, /* Required */
746 {"A_ARG_TYPE_Protocol", 2, 0, 0, 0}, /* Required */
748 {"A_ARG_TYPE_UniqueID", 2, 0, 0, 0}, /* Required */
749 {"A_ARG_TYPE_LeaseTime", 3, 0, 5, 0}, /* Required */
750 {"InboundPinholeAllowed", 1|0x80, 0, 0,
751 INBOUNDPINHOLEALLOWED_MAGICALVALUE
}, /* Required */
752 {"A_ARG_TYPE_OutboundPinholeTimeout", 3, 0, 7, 0}, /* Optional */
754 {"A_ARG_TYPE_Boolean", 1, 0, 0, 0}, /* Optional */
755 {"A_ARG_TYPE_PinholePackets", 3, 0, 0, 0}, /* Required */
759 static const struct serviceDesc scpd6FC
=
760 { IPv6FCActions
, IPv6FCVars
};
763 #ifdef ENABLE_DP_SERVICE
764 /* UPnP-gw-DeviceProtection-v1-Service.pdf */
766 static const struct argument SendSetupMessageArgs
[] =
768 {1|0x80|(8<<2), 6}, /* ProtocolType : in ProtocolType / A_ARG_TYPE_String */
769 {1|0x80|(9<<2), 5}, /* InMessage : in InMessage / A_ARG_TYPE_Base64 */
770 {2|0x80|(10<<2), 5}, /* OutMessage : out OutMessage / A_ARG_TYPE_Base64 */
774 static const struct argument GetSupportedProtocolsArgs
[] =
776 {2|0x80|(11<<2), 1}, /* ProtocolList : out ProtocolList / SupportedProtocols */
780 static const struct argument GetAssignedRolesArgs
[] =
782 {2|0x80|(12<<2), 6}, /* RoleList : out RoleList / A_ARG_TYPE_String */
786 static const struct action DPActions
[] =
788 {"SendSetupMessage", SendSetupMessageArgs
},
789 {"GetSupportedProtocols", GetSupportedProtocolsArgs
},
790 {"GetAssignedRoles", GetAssignedRolesArgs
},
794 static const struct stateVar DPVars
[] =
796 {"SetupReady", 1|0x80, 0, 0, SETUPREADY_MAGICALVALUE
},
797 {"SupportedProtocols", 0},
798 {"A_ARG_TYPE_ACL", 0},
799 {"A_ARG_TYPE_IdentityList", 0},
800 {"A_ARG_TYPE_Identity", 0},
801 {"A_ARG_TYPE_Base64", 4},
802 {"A_ARG_TYPE_String", 0},
806 static const struct serviceDesc scpdDP
=
807 { DPActions
, DPVars
};
811 * concatenate the string and use realloc to increase the
812 * memory buffer if needed. */
814 strcat_str(char * str
, int * len
, int * tmplen
, const char * s2
)
820 s2len
= (int)strlen(s2
);
821 if(*tmplen
<= (*len
+ s2len
))
824 newlen
= *tmplen
+ 256;
826 newlen
= *tmplen
+ s2len
+ 1;
827 p
= (char *)realloc(str
, newlen
);
828 if(p
== NULL
) /* handle a failure of realloc() */
833 /*strcpy(str + *len, s2); */
834 memcpy(str
+ *len
, s2
, s2len
+ 1);
840 * concatenate a character and use realloc to increase the
841 * size of the memory buffer if needed */
843 strcat_char(char * str
, int * len
, int * tmplen
, char c
)
847 if(*tmplen
<= (*len
+ 1))
850 p
= (char *)realloc(str
, *tmplen
);
851 if(p
== NULL
) /* handle a failure of realloc() */
864 * concatenate the string representation of the integer.
865 * call strcat_char() */
867 strcat_int(char * str
, int * len
, int * tmplen
, int i
)
873 str
= strcat_char(str
, len
, tmplen
, '-');
876 /* special case for 0 */
877 str
= strcat_char(str
, len
, tmplen
, '0');
881 while(i
&& j
< (int)sizeof(buf
)) {
882 buf
[j
++] = '0' + (i
% 10);
886 str
= strcat_char(str
, len
, tmplen
, buf
[--j
]);
891 /* iterative subroutine using a small stack
892 * This way, the progam stack usage is kept low */
894 genXML(char * str
, int * len
, int * tmplen
,
895 const struct XMLElt
* p
)
900 const char * eltname
, *s
;
905 const char * eltname
;
906 } pile
[16]; /* stack */
908 i
= 0; /* current node */
909 j
= 1; /* i + number of nodes*/
912 eltname
= p
[i
].eltname
;
915 if(eltname
[0] == '/')
917 if(p
[i
].data
&& p
[i
].data
[0])
919 /*printf("<%s>%s<%s>\n", eltname+1, p[i].data, eltname); */
920 str
= strcat_char(str
, len
, tmplen
, '<');
921 str
= strcat_str(str
, len
, tmplen
, eltname
+1);
922 str
= strcat_char(str
, len
, tmplen
, '>');
923 str
= strcat_str(str
, len
, tmplen
, p
[i
].data
);
924 str
= strcat_char(str
, len
, tmplen
, '<');
925 str
= strcat_str(str
, len
, tmplen
, eltname
);
926 str
= strcat_char(str
, len
, tmplen
, '>');
934 /*printf(" pile[%d]\t%d %d\n", top, i, j); */
937 /*printf("</%s>\n", pile[top].eltname); */
938 str
= strcat_char(str
, len
, tmplen
, '<');
939 str
= strcat_char(str
, len
, tmplen
, '/');
940 s
= pile
[top
].eltname
;
941 for(c
= *s
; c
> ' '; c
= *(++s
))
942 str
= strcat_char(str
, len
, tmplen
, c
);
943 str
= strcat_char(str
, len
, tmplen
, '>');
952 /*printf("<%s>\n", eltname); */
953 str
= strcat_char(str
, len
, tmplen
, '<');
954 str
= strcat_str(str
, len
, tmplen
, eltname
);
955 if(memcmp(eltname
, "root ", 5) == 0) {
956 char configid_str
[16];
957 /* add configId attribute, required by UDA 1.1 */
958 snprintf(configid_str
, sizeof(configid_str
), "\"%u\"", upnp_configid
);
959 str
= strcat_str(str
, len
, tmplen
, " configId=");
960 str
= strcat_str(str
, len
, tmplen
, configid_str
);
962 str
= strcat_char(str
, len
, tmplen
, '>');
963 k
= (unsigned long)p
[i
].data
;
967 /*printf(" +pile[%d]\t%d %d\n", top, i, j); */
970 pile
[top
].eltname
= eltname
;
976 * - Generate the root description of the UPnP device.
977 * - the len argument is used to return the length of
978 * the returned string.
979 * - tmp_uuid argument is used to build the uuid string */
981 genRootDesc(int * len
)
986 str
= (char *)malloc(tmplen
);
989 * len
= strlen(xmlver
);
990 /*strcpy(str, xmlver); */
991 memcpy(str
, xmlver
, *len
+ 1);
992 str
= genXML(str
, len
, &tmplen
, rootDesc
);
997 /* genServiceDesc() :
998 * Generate service description with allowed methods and
999 * related variables. */
1001 genServiceDesc(int * len
, const struct serviceDesc
* s
)
1004 const struct action
* acts
;
1005 const struct stateVar
* vars
;
1006 const struct argument
* args
;
1011 str
= (char *)malloc(tmplen
);
1014 /*strcpy(str, xmlver); */
1015 *len
= strlen(xmlver
);
1016 memcpy(str
, xmlver
, *len
+ 1);
1018 acts
= s
->actionList
;
1019 vars
= s
->serviceStateTable
;
1021 str
= strcat_char(str
, len
, &tmplen
, '<');
1022 str
= strcat_str(str
, len
, &tmplen
, root_service
);
1023 str
= strcat_char(str
, len
, &tmplen
, '>');
1025 str
= strcat_str(str
, len
, &tmplen
,
1026 "<specVersion><major>" UPNP_VERSION_MAJOR_STR
"</major>"
1027 "<minor>" UPNP_VERSION_MINOR_STR
"</minor></specVersion>");
1030 str
= strcat_str(str
, len
, &tmplen
, "<actionList>");
1033 str
= strcat_str(str
, len
, &tmplen
, "<action><name>");
1034 str
= strcat_str(str
, len
, &tmplen
, acts
[i
].name
);
1035 str
= strcat_str(str
, len
, &tmplen
, "</name>");
1037 args
= acts
[i
].args
;
1040 str
= strcat_str(str
, len
, &tmplen
, "<argumentList>");
1044 str
= strcat_str(str
, len
, &tmplen
, "<argument><name>");
1045 if((args
[j
].dir
& 0x80) == 0) {
1046 str
= strcat_str(str
, len
, &tmplen
, "New");
1048 p
= vars
[args
[j
].relatedVar
].name
;
1049 if(args
[j
].dir
& 0x7c) {
1050 /* use magic values ... */
1051 str
= strcat_str(str
, len
, &tmplen
, magicargname
[(args
[j
].dir
& 0x7c) >> 2]);
1052 } else if(0 == memcmp(p
, "PortMapping", 11)
1053 && 0 != memcmp(p
+ 11, "Description", 11)) {
1054 if(0 == memcmp(p
+ 11, "NumberOfEntries", 15)) {
1055 /* PortMappingNumberOfEntries */
1057 if(0 == memcmp(acts
[i
].name
, "GetListOfPortMappings", 22)) {
1058 str
= strcat_str(str
, len
, &tmplen
, "NumberOfPorts");
1060 str
= strcat_str(str
, len
, &tmplen
, "PortMappingIndex");
1063 str
= strcat_str(str
, len
, &tmplen
, "PortMappingIndex");
1066 /* PortMappingEnabled
1067 * PortMappingLeaseDuration
1068 * PortMappingProtocol */
1069 str
= strcat_str(str
, len
, &tmplen
, p
+ 11);
1072 } else if(0 == memcmp(p
, "A_ARG_TYPE_", 11)) {
1073 str
= strcat_str(str
, len
, &tmplen
, p
+ 11);
1074 } else if(0 == memcmp(p
, "ExternalPort", 13)
1076 && 0 == memcmp(acts
[i
].name
, "AddAnyPortMapping", 18)) {
1077 str
= strcat_str(str
, len
, &tmplen
, "ReservedPort");
1080 str
= strcat_str(str
, len
, &tmplen
, p
);
1082 str
= strcat_str(str
, len
, &tmplen
, "</name><direction>");
1083 str
= strcat_str(str
, len
, &tmplen
, (args
[j
].dir
&0x03)==1?"in":"out");
1084 str
= strcat_str(str
, len
, &tmplen
,
1085 "</direction><relatedStateVariable>");
1086 str
= strcat_str(str
, len
, &tmplen
, p
);
1087 str
= strcat_str(str
, len
, &tmplen
,
1088 "</relatedStateVariable></argument>");
1091 str
= strcat_str(str
, len
, &tmplen
,"</argumentList>");
1093 str
= strcat_str(str
, len
, &tmplen
, "</action>");
1094 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
1097 str
= strcat_str(str
, len
, &tmplen
, "</actionList><serviceStateTable>");
1101 str
= strcat_str(str
, len
, &tmplen
,
1102 "<stateVariable sendEvents=\"");
1103 #ifdef ENABLE_EVENTS
1104 str
= strcat_str(str
, len
, &tmplen
, (vars
[i
].itype
& 0x80)?"yes":"no");
1106 /* for the moment always send no. Wait for SUBSCRIBE implementation
1107 * before setting it to yes */
1108 str
= strcat_str(str
, len
, &tmplen
, "no");
1110 str
= strcat_str(str
, len
, &tmplen
, "\"><name>");
1111 str
= strcat_str(str
, len
, &tmplen
, vars
[i
].name
);
1112 str
= strcat_str(str
, len
, &tmplen
, "</name><dataType>");
1113 str
= strcat_str(str
, len
, &tmplen
, upnptypes
[vars
[i
].itype
& 0x0f]);
1114 str
= strcat_str(str
, len
, &tmplen
, "</dataType>");
1115 /*if(vars[i].defaultValue) */
1116 if(vars
[i
].idefault
)
1118 str
= strcat_str(str
, len
, &tmplen
, "<defaultValue>");
1119 /*str = strcat_str(str, len, &tmplen, vars[i].defaultValue); */
1120 str
= strcat_str(str
, len
, &tmplen
, upnpdefaultvalues
[vars
[i
].idefault
]);
1121 str
= strcat_str(str
, len
, &tmplen
, "</defaultValue>");
1123 if(vars
[i
].iallowedlist
)
1125 if((vars
[i
].itype
& 0x0f) == 0)
1128 str
= strcat_str(str
, len
, &tmplen
, "<allowedValueList>");
1129 for(j
=vars
[i
].iallowedlist
; upnpallowedvalues
[j
]; j
++)
1131 str
= strcat_str(str
, len
, &tmplen
, "<allowedValue>");
1132 str
= strcat_str(str
, len
, &tmplen
, upnpallowedvalues
[j
]);
1133 str
= strcat_str(str
, len
, &tmplen
, "</allowedValue>");
1135 str
= strcat_str(str
, len
, &tmplen
, "</allowedValueList>");
1138 str
= strcat_str(str
, len
, &tmplen
, "<allowedValueRange><minimum>");
1139 str
= strcat_int(str
, len
, &tmplen
, upnpallowedranges
[vars
[i
].iallowedlist
]);
1140 str
= strcat_str(str
, len
, &tmplen
, "</minimum><maximum>");
1141 str
= strcat_int(str
, len
, &tmplen
, upnpallowedranges
[vars
[i
].iallowedlist
+1]);
1142 str
= strcat_str(str
, len
, &tmplen
, "</maximum></allowedValueRange>");
1145 str
= strcat_str(str
, len
, &tmplen
, "</stateVariable>");
1146 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
1149 str
= strcat_str(str
, len
, &tmplen
, "</serviceStateTable></scpd>");
1155 * Generate the WANIPConnection xml description */
1157 genWANIPCn(int * len
)
1159 return genServiceDesc(len
, &scpdWANIPCn
);
1163 * Generate the WANInterfaceConfig xml description. */
1165 genWANCfg(int * len
)
1167 return genServiceDesc(len
, &scpdWANCfg
);
1170 #ifdef ENABLE_L3F_SERVICE
1174 return genServiceDesc(len
, &scpdL3F
);
1178 #ifdef ENABLE_6FC_SERVICE
1182 return genServiceDesc(len
, &scpd6FC
);
1186 #ifdef ENABLE_DP_SERVICE
1190 return genServiceDesc(len
, &scpdDP
);
1194 #ifdef ENABLE_EVENTS
1196 genEventVars(int * len
, const struct serviceDesc
* s
)
1199 const struct stateVar
* v
;
1203 str
= (char *)malloc(tmplen
);
1207 v
= s
->serviceStateTable
;
1208 str
= strcat_str(str
, len
, &tmplen
, "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">");
1210 if(v
->itype
& 0x80) {
1211 str
= strcat_str(str
, len
, &tmplen
, "<e:property><");
1212 str
= strcat_str(str
, len
, &tmplen
, v
->name
);
1213 str
= strcat_str(str
, len
, &tmplen
, ">");
1214 /*printf("<e:property><%s>", v->name);*/
1215 switch(v
->ieventvalue
) {
1218 #ifdef ENABLE_DP_SERVICE
1219 case SETUPREADY_MAGICALVALUE
:
1220 /* always ready for setup */
1221 snprintf(tmp
, sizeof(tmp
), "%d", 1);
1222 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1225 case CONNECTIONSTATUS_MAGICALVALUE
:
1226 /* or get_wan_connection_status_str(ext_if_name) */
1227 str
= strcat_str(str
, len
, &tmplen
,
1228 upnpallowedvalues
[18 + get_wan_connection_status(ext_if_name
)]);
1230 #ifdef ENABLE_6FC_SERVICE
1231 case FIREWALLENABLED_MAGICALVALUE
:
1232 /* see 2.4.2 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
1233 snprintf(tmp
, sizeof(tmp
), "%d",
1234 GETFLAG(IPV6FCFWDISABLEDMASK
) ? 0 : 1);
1235 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1237 case INBOUNDPINHOLEALLOWED_MAGICALVALUE
:
1238 /* see 2.4.3 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
1239 snprintf(tmp
, sizeof(tmp
), "%d",
1240 GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK
) ? 0 : 1);
1241 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1245 case SYSTEMUPDATEID_MAGICALVALUE
:
1246 /* Please read section 2.3.23 SystemUpdateID
1247 * of UPnP-gw-WANIPConnection-v2-Service.pdf */
1248 snprintf(tmp
, sizeof(tmp
), "%d",
1249 1/* system update id */);
1250 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1253 case PORTMAPPINGNUMBEROFENTRIES_MAGICALVALUE
:
1254 /* Port mapping number of entries magical value */
1255 snprintf(tmp
, sizeof(tmp
), "%d",
1256 upnp_get_portmapping_number_of_entries());
1257 str
= strcat_str(str
, len
, &tmplen
, tmp
);
1259 case EXTERNALIPADDRESS_MAGICALVALUE
:
1260 /* External ip address magical value */
1262 str
= strcat_str(str
, len
, &tmplen
, use_ext_ip_addr
);
1264 char ext_ip_addr
[INET_ADDRSTRLEN
];
1265 if(getifaddr(ext_if_name
, ext_ip_addr
, INET_ADDRSTRLEN
, NULL
, NULL
) < 0) {
1266 str
= strcat_str(str
, len
, &tmplen
, "0.0.0.0");
1268 str
= strcat_str(str
, len
, &tmplen
, ext_ip_addr
);
1272 case DEFAULTCONNECTIONSERVICE_MAGICALVALUE
:
1273 /* DefaultConnectionService magical value */
1274 str
= strcat_str(str
, len
, &tmplen
, uuidvalue_wcd
);
1276 str
= strcat_str(str
, len
, &tmplen
, ":WANConnectionDevice:2,urn:upnp-org:serviceId:WANIPConn1");
1278 str
= strcat_str(str
, len
, &tmplen
, ":WANConnectionDevice:1,urn:upnp-org:serviceId:WANIPConn1");
1282 str
= strcat_str(str
, len
, &tmplen
, upnpallowedvalues
[v
->ieventvalue
]);
1284 str
= strcat_str(str
, len
, &tmplen
, "</");
1285 str
= strcat_str(str
, len
, &tmplen
, v
->name
);
1286 str
= strcat_str(str
, len
, &tmplen
, "></e:property>");
1287 /*printf("</%s></e:property>\n", v->name);*/
1291 str
= strcat_str(str
, len
, &tmplen
, "</e:propertyset>");
1293 printf("</e:propertyset>\n");
1295 printf("%d\n", tmplen
);
1302 getVarsWANIPCn(int * l
)
1304 return genEventVars(l
,
1309 getVarsWANCfg(int * l
)
1311 return genEventVars(l
,
1315 #ifdef ENABLE_L3F_SERVICE
1319 return genEventVars(l
,
1324 #ifdef ENABLE_6FC_SERVICE
1328 return genEventVars(l
,
1333 #ifdef ENABLE_DP_SERVICE
1337 return genEventVars(l
,
1342 #endif /* ENABLE_EVENTS */