| 1 |
/* |
|---|
| 2 |
Copyright 2007, Broadcom Corporation |
|---|
| 3 |
All Rights Reserved. |
|---|
| 4 |
|
|---|
| 5 |
THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY |
|---|
| 6 |
KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM |
|---|
| 7 |
SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS |
|---|
| 8 |
FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. |
|---|
| 9 |
*/ |
|---|
| 10 |
|
|---|
| 11 |
#include <stdarg.h> |
|---|
| 12 |
|
|---|
| 13 |
#include "upnp_osl.h" |
|---|
| 14 |
#include "upnp_dbg.h" |
|---|
| 15 |
#include "upnp.h" |
|---|
| 16 |
#include <osl.h> |
|---|
| 17 |
#include <sbutils.h> |
|---|
| 18 |
#include <bcmnvram.h> |
|---|
| 19 |
#include <wlioctl.h> |
|---|
| 20 |
#include <wlutils.h> |
|---|
| 21 |
#include <cyutils.h> |
|---|
| 22 |
/* |
|---|
| 23 |
#define DEV_MFR "Broadcom" |
|---|
| 24 |
#define DEV_MFR_URL "http://www.broadcom.com/" |
|---|
| 25 |
#define DEV_MODEL_DESCRIPTION "Residential Gateway Device" |
|---|
| 26 |
#define DEV_MODEL "Wireless Base Station" |
|---|
| 27 |
#define DEV_MODEL_NO "MN-500" |
|---|
| 28 |
#define DEV_MODEL_URL "http://www.broadcom.com/" |
|---|
| 29 |
*/ |
|---|
| 30 |
|
|---|
| 31 |
extern PService init_service(PServiceTemplate svctmpl, PDevice pdev); |
|---|
| 32 |
extern void destroy_service(PService); |
|---|
| 33 |
|
|---|
| 34 |
void device_devicelist(PDevice pdev, UFILE *up); |
|---|
| 35 |
void device_servicelist(PDevice pdev, UFILE *up); |
|---|
| 36 |
|
|---|
| 37 |
PDevice root_devices = NULL; |
|---|
| 38 |
|
|---|
| 39 |
/* recursive routine to initialize a device, and all its subdevices. |
|---|
| 40 |
Also all services within a device are intialized by calling their |
|---|
| 41 |
specific initialization function, if available. */ |
|---|
| 42 |
PDevice init_device(PDevice parent, PDeviceTemplate pdevtmpl, ...) |
|---|
| 43 |
{ |
|---|
| 44 |
static int indent = 0; |
|---|
| 45 |
int i; |
|---|
| 46 |
PFDEVINIT func; |
|---|
| 47 |
PDevice pdev, subdev; |
|---|
| 48 |
PService psvc; |
|---|
| 49 |
va_list ap; |
|---|
| 50 |
|
|---|
| 51 |
UPNP_TRACE(("%*sInitializing %sdevice \"%s\".\r\n", indent, "", (parent ? "" : "root "), pdevtmpl->type)); |
|---|
| 52 |
|
|---|
| 53 |
if (pdevtmpl->schema == NULL) |
|---|
| 54 |
pdevtmpl->schema = "schemas-upnp-org"; |
|---|
| 55 |
|
|---|
| 56 |
pdev = (Device *) malloc(sizeof(Device)); |
|---|
| 57 |
memset(pdev, 0, sizeof(Device)); |
|---|
| 58 |
pdev->parent = parent; |
|---|
| 59 |
pdev->template = pdevtmpl; |
|---|
| 60 |
|
|---|
| 61 |
// call the device's intialization function, if defined. |
|---|
| 62 |
if ((func = pdevtmpl->devinit) != NULL) { |
|---|
| 63 |
va_start( ap, pdevtmpl); |
|---|
| 64 |
(*func)(pdev, DEVICE_CREATE, ap); |
|---|
| 65 |
va_end( ap); |
|---|
| 66 |
} |
|---|
| 67 |
|
|---|
| 68 |
// we do a top down, depth-first traversal of the device heirarchy. |
|---|
| 69 |
// sub-devices will be initialized before we complete initialization of the root device. |
|---|
| 70 |
// |
|---|
| 71 |
for (i = 0; i < pdevtmpl->ndevices; i++) { |
|---|
| 72 |
indent += 4; |
|---|
| 73 |
subdev = init_device(pdev, &(pdevtmpl->devicelist[i])); |
|---|
| 74 |
indent -= 4; |
|---|
| 75 |
subdev->next = pdev->subdevs; |
|---|
| 76 |
pdev->subdevs = subdev; |
|---|
| 77 |
} |
|---|
| 78 |
|
|---|
| 79 |
// Initialize each service in this device. |
|---|
| 80 |
// |
|---|
| 81 |
for (i = 0; i < pdevtmpl->nservices; i++) { |
|---|
| 82 |
psvc = init_service(pdevtmpl->services[i], pdev); |
|---|
| 83 |
|
|---|
| 84 |
psvc->next = pdev->services; |
|---|
| 85 |
pdev->services = psvc; |
|---|
| 86 |
} |
|---|
| 87 |
|
|---|
| 88 |
if (ISROOT(pdev)) { |
|---|
| 89 |
pdev->next = root_devices; |
|---|
| 90 |
root_devices = pdev; |
|---|
| 91 |
} |
|---|
| 92 |
|
|---|
| 93 |
return pdev; |
|---|
| 94 |
} |
|---|
| 95 |
|
|---|
| 96 |
void destroy_device(PDevice pdev) |
|---|
| 97 |
{ |
|---|
| 98 |
static int indent = 0; |
|---|
| 99 |
PFDEVINIT func; |
|---|
| 100 |
PDevice psubdev, nextdev, *ppdev; |
|---|
| 101 |
PService psvc, nextsvc; |
|---|
| 102 |
|
|---|
| 103 |
UPNP_TRACE(("%*sDestroying %sdevice \"%s\".\r\n", indent, "", (ISROOT(pdev) ? "root " : ""), pdev->template->type)); |
|---|
| 104 |
|
|---|
| 105 |
// destroy all subdevices in this device. |
|---|
| 106 |
if (pdev->subdevs) { |
|---|
| 107 |
for (psubdev = pdev->subdevs; psubdev; psubdev = nextdev) { |
|---|
| 108 |
nextdev = psubdev->next; |
|---|
| 109 |
indent += 4; |
|---|
| 110 |
destroy_device(psubdev); |
|---|
| 111 |
indent -= 4; |
|---|
| 112 |
} |
|---|
| 113 |
} |
|---|
| 114 |
|
|---|
| 115 |
// destroy all service in this device. |
|---|
| 116 |
if (pdev->services) { |
|---|
| 117 |
for (psvc = pdev->services; psvc; psvc = nextsvc) { |
|---|
| 118 |
nextsvc = psvc->next; |
|---|
| 119 |
destroy_service(psvc); |
|---|
| 120 |
} |
|---|
| 121 |
} |
|---|
| 122 |
|
|---|
| 123 |
// call this device's destroy function, if defined. |
|---|
| 124 |
if ((func = pdev->template->devinit) != NULL) { |
|---|
| 125 |
(*func)(pdev, DEVICE_DESTROY, (va_list) NULL ); |
|---|
| 126 |
} |
|---|
| 127 |
|
|---|
| 128 |
// remove the device from the root device list |
|---|
| 129 |
if (ISROOT(pdev)) { |
|---|
| 130 |
for (ppdev = &root_devices; *ppdev; ppdev = &(*ppdev)->next) { |
|---|
| 131 |
if (*ppdev == pdev) { |
|---|
| 132 |
*ppdev = (*ppdev)->next; |
|---|
| 133 |
break; |
|---|
| 134 |
} |
|---|
| 135 |
} |
|---|
| 136 |
} |
|---|
| 137 |
|
|---|
| 138 |
// finally, free the memory allocated in init_device(); |
|---|
| 139 |
free(pdev); |
|---|
| 140 |
} |
|---|
| 141 |
|
|---|
| 142 |
|
|---|
| 143 |
/* Print an XML device description for a device and all its subdevices. |
|---|
| 144 |
We used to just print the static XML device description from a file, but now that the |
|---|
| 145 |
IGD is more dynamic and can adjust to different gateway configurations, |
|---|
| 146 |
we must dynamically generate the XML. |
|---|
| 147 |
*/ |
|---|
| 148 |
void device_xml(PDevice pdev, UFILE *up) |
|---|
| 149 |
{ |
|---|
| 150 |
PFDEVXML func; |
|---|
| 151 |
char *friendlyname; |
|---|
| 152 |
char *model_no = NULL; |
|---|
| 153 |
|
|---|
| 154 |
// call the device's xml function, if defined. |
|---|
| 155 |
if ((func = pdev->template->devxml) != NULL) { |
|---|
| 156 |
(*func)(pdev, up); |
|---|
| 157 |
return; |
|---|
| 158 |
} |
|---|
| 159 |
|
|---|
| 160 |
if (ISROOT(pdev)) { |
|---|
| 161 |
uprintf(up, |
|---|
| 162 |
"<?xml version=\"1.0\"?>\r\n" |
|---|
| 163 |
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\r\n" |
|---|
| 164 |
"<specVersion>\r\n" |
|---|
| 165 |
"<major>1</major>\r\n" |
|---|
| 166 |
"<minor>0</minor>\r\n" |
|---|
| 167 |
"</specVersion>\r\n" |
|---|
| 168 |
); |
|---|
| 169 |
uprintf(up, "<URLBase>http://%s:%d</URLBase>\r\n", nvram_safe_get("lan_ipaddr"), HTTP_PORT); |
|---|
| 170 |
} |
|---|
| 171 |
|
|---|
| 172 |
if (pdev->friendlyname) |
|---|
| 173 |
friendlyname = pdev->friendlyname; |
|---|
| 174 |
else { |
|---|
| 175 |
friendlyname = pdev->template->type; |
|---|
| 176 |
} |
|---|
| 177 |
|
|---|
| 178 |
model_no = nvram_get("DD_BOARD"); |
|---|
| 179 |
if (!model_no || strlen(model_no) == 0) { |
|---|
| 180 |
model_no = DEV_MODEL_NO; |
|---|
| 181 |
} |
|---|
| 182 |
|
|---|
| 183 |
uprintf(up, "<device>\r\n"); |
|---|
| 184 |
uprintf(up, "<deviceType>%s</deviceType>\r\n", pdev->template->type); |
|---|
| 185 |
if (ISROOT(pdev)) { |
|---|
| 186 |
uprintf(up, "<presentationURL>/index.asp</presentationURL>\r\n"); |
|---|
| 187 |
} |
|---|
| 188 |
uprintf(up, "<friendlyName>%s</friendlyName>\r\n", friendlyname); |
|---|
| 189 |
uprintf(up, "<manufacturer>%s</manufacturer>\r\n", DEV_MFR); |
|---|
| 190 |
uprintf(up, "<manufacturerURL>%s</manufacturerURL>\r\n", DEV_MFR_URL); |
|---|
| 191 |
uprintf(up, "<modelDescription>%s</modelDescription>\r\n", DEV_MODEL_DESCRIPTION); |
|---|
| 192 |
uprintf(up, "<modelName>%s</modelName>\r\n", DEV_MODEL); |
|---|
| 193 |
uprintf(up, "<modelNumber>%s</modelNumber>\r\n", model_no); |
|---|
| 194 |
uprintf(up, "<modelURL>%s</modelURL>\r\n", DEV_MODEL_URL); |
|---|
| 195 |
uprintf(up, "<UDN>%s</UDN>\r\n", pdev->udn); |
|---|
| 196 |
|
|---|
| 197 |
// generate XML for any services in this device. |
|---|
| 198 |
device_servicelist(pdev, up); |
|---|
| 199 |
|
|---|
| 200 |
// generate XML for any subdevices in this device. |
|---|
| 201 |
device_devicelist(pdev, up); |
|---|
| 202 |
|
|---|
| 203 |
uprintf(up, "</device>\r\n"); |
|---|
| 204 |
|
|---|
| 205 |
if (ISROOT(pdev)) { |
|---|
| 206 |
uprintf(up, "</root>\r\n"); |
|---|
| 207 |
} |
|---|
| 208 |
} |
|---|
| 209 |
|
|---|
| 210 |
|
|---|
| 211 |
void device_devicelist(PDevice pdev, UFILE *up) |
|---|
| 212 |
{ |
|---|
| 213 |
PDevice psubdev; |
|---|
| 214 |
|
|---|
| 215 |
// generate XML for any subdevices in this device. |
|---|
| 216 |
if (pdev->subdevs) { |
|---|
| 217 |
uprintf(up, "<deviceList>\r\n"); |
|---|
| 218 |
for (psubdev = pdev->subdevs; psubdev; psubdev = psubdev->next) |
|---|
| 219 |
device_xml(psubdev, up); |
|---|
| 220 |
uprintf(up, "</deviceList>\r\n"); |
|---|
| 221 |
} |
|---|
| 222 |
} |
|---|
| 223 |
|
|---|
| 224 |
|
|---|
| 225 |
void device_servicelist(PDevice pdev, UFILE *up) |
|---|
| 226 |
{ |
|---|
| 227 |
char svcurl[200]; |
|---|
| 228 |
PService psvc; |
|---|
| 229 |
|
|---|
| 230 |
// generate XML for any services in this device. |
|---|
| 231 |
if (pdev->services) { |
|---|
| 232 |
uprintf(up, "<serviceList>\r\n"); |
|---|
| 233 |
forall_services(pdev, psvc) { |
|---|
| 234 |
snprintf(svcurl, sizeof(svcurl), "/%s/%s", pdev->udn, psvc->template->name); |
|---|
| 235 |
|
|---|
| 236 |
uprintf(up, "<service>\r\n"); |
|---|
| 237 |
uprintf(up, "<serviceType>urn:%s:service:%s</serviceType>\r\n", |
|---|
| 238 |
psvc->template->schema, psvc->template->name); |
|---|
| 239 |
if (psvc->template->serviceid) { |
|---|
| 240 |
uprintf(up, "<serviceId>%s%d</serviceId>\r\n", |
|---|
| 241 |
psvc->template->serviceid, psvc->instance); |
|---|
| 242 |
} else { |
|---|
| 243 |
uprintf(up, "<serviceId>urn:upnp-org:serviceId:%s%d</serviceId>\r\n", |
|---|
| 244 |
psvc->template->name, psvc->instance); |
|---|
| 245 |
} |
|---|
| 246 |
uprintf(up, "<controlURL>/%s/%s</controlURL>\r\n", pdev->udn, psvc->template->name); |
|---|
| 247 |
uprintf(up, "<eventSubURL>/%s/%s</eventSubURL>\r\n", pdev->udn, psvc->template->name); |
|---|
| 248 |
uprintf(up, "<SCPDURL>/dynsvc/%s.xml</SCPDURL>\r\n", psvc->template->name); |
|---|
| 249 |
uprintf(up, "</service>\r\n"); |
|---|
| 250 |
} |
|---|
| 251 |
uprintf(up, "</serviceList>\r\n"); |
|---|
| 252 |
} |
|---|
| 253 |
} |
|---|
| 254 |
|
|---|
| 255 |
|
|---|
| 256 |
/* Given a device pointer, return the root device for that device. */ |
|---|
| 257 |
PDevice rootdev(PDevice pdev) |
|---|
| 258 |
{ |
|---|
| 259 |
while (pdev->parent) |
|---|
| 260 |
pdev = pdev->parent; |
|---|
| 261 |
return pdev; |
|---|
| 262 |
} |
|---|
| 263 |
|
|---|
| 264 |
|
|---|
| 265 |
/* Device iterator used by the forall_devices() macro. |
|---|
| 266 |
|
|---|
| 267 |
The first call to device_iterator() should have NULL as its argument. |
|---|
| 268 |
Subsequent calls will return the next device in depth first, pre-order. |
|---|
| 269 |
*/ |
|---|
| 270 |
PDevice device_iterator(PDevice pdev) |
|---|
| 271 |
{ |
|---|
| 272 |
PDevice nextdev; |
|---|
| 273 |
|
|---|
| 274 |
if (pdev == NULL) { |
|---|
| 275 |
nextdev = root_devices; |
|---|
| 276 |
} else { |
|---|
| 277 |
if (pdev->subdevs) { |
|---|
| 278 |
nextdev = pdev->subdevs; |
|---|
| 279 |
} else { |
|---|
| 280 |
nextdev = pdev; |
|---|
| 281 |
while (nextdev) { |
|---|
| 282 |
if (nextdev->next) { |
|---|
| 283 |
nextdev = nextdev->next; |
|---|
| 284 |
break; |
|---|
| 285 |
} else { |
|---|
| 286 |
nextdev = nextdev->parent; |
|---|
| 287 |
} |
|---|
| 288 |
} |
|---|
| 289 |
} |
|---|
| 290 |
} |
|---|
| 291 |
|
|---|
| 292 |
return nextdev; |
|---|
| 293 |
} |
|---|
| 294 |
|
|---|
| 295 |
|
|---|
| 296 |
|
|---|