gena_device.c File Reference
`#include "config.h"`
`#include "gena_device.h"`
`#include <assert.h>`
`#include "gena.h"`
`#include "httpreadwrite.h"`
`#include "posix_overwrites.h"`
`#include "ssdplib.h"`
`#include "statcodes.h"`
`#include "upnpapi.h"`
`#include "uuid.h"`
Include dependency graph for gena_device.c:

## Macros

#define | STALE_JOBID (INVALID_JOB_ID - 1)

## Functions

int | genaUnregisterDevice (UpnpDevice_Handle device_handle)
| Unregisters a device.
static int | GeneratePropertySet (char **names, char **values, int count, DOMString *out)
| Generates XML property set for notifications.
static void | free_notify_struct (void *input)
| Frees memory used in notify_threads if the reference count is 0, otherwise decrements the refrence count.
static UPNP_INLINE int | notify_send_and_recv (uri_type *destination_url, membuffer *mid_msg, char *propertySet, http_parser_t *response)
| Sends the notify message and returns a reply.
static int | genaNotify (char *headers, char *propertySet, subscription *sub)
| Function to Notify a particular subscription of a particular event.
static void | genaNotifyThread (void *input)
| Thread job to Notify a control point.
static char * | AllocGenaHeaders (const DOMString propertySet)
| Allocates the GENA header.
void | freeSubscriptionQueuedEvents (subscription *sub)
static int | genaInitNotifyCommon (UpnpDevice_Handle device_handle, char *UDN, char *servId, DOMString propertySet, const Upnp_SID sid)
int | genaInitNotify (UpnpDevice_Handle device_handle, char *UDN, char *servId, char **VarNames, char **VarValues, int var_count, const Upnp_SID sid)
| Sends the intial state table dump to newly subscribed control point.
int | genaInitNotifyExt (UpnpDevice_Handle device_handle, char *UDN, char *servId, IXML_Document *PropSet, const Upnp_SID sid)
| Similar to the genaInitNofity. The only difference is that it takes the xml document for the state table and sends the intial state table dump to newly subscribed control point.
static void | maybeDiscardEvents (LinkedList *listp)
static int | genaNotifyAllCommon (UpnpDevice_Handle device_handle, char *UDN, char *servId, DOMString propertySet)
int | genaNotifyAllExt (UpnpDevice_Handle device_handle, char *UDN, char *servId, IXML_Document *PropSet)
| Sends a notification to all the subscribed control points.
int | genaNotifyAll (UpnpDevice_Handle device_handle, char *UDN, char *servId, char **VarNames, char **VarValues, int var_count)
| Sends a notification to all the subscribed control points.
static int | respond_ok (SOCKINFO *info, int time_out, subscription *sub, http_message_t *request)
| Returns OK message in the case of a subscription request.
static int | create_url_list (memptr *url_list, URL_list *out)
| Function to parse the Callback header value in subscription requests.
int | gena_validate_delivery_urls (SOCKINFO *info, URL_list *url_list)
| Validate that the URLs passed by the user are on the same network segment than the device.
void | gena_process_subscription_request (SOCKINFO *info, http_message_t *request)
| Handles a subscription request from a ctrl point. The socket is not closed on return.
void | gena_process_subscription_renewal_request (SOCKINFO *info, http_message_t *request)
| Handles a subscription renewal request from a ctrl point. The connection is not destroyed on return.
void | gena_process_unsubscribe_request (SOCKINFO *info, http_message_t *request)
| Handles a subscription cancellation request from a ctrl point. The connection is not destroyed on return.

## Function Documentation

## AllocGenaHeaders()

static char * AllocGenaHeaders | ( | const DOMString | propertySet | ) |

static

Allocates the GENA header.

Note
  The header must be destroyed after with a call to free(), otherwise there will be a memory leak.

Returns
  The constructed header.

Parameters

  [in] | propertySet | The property set string.

References UpnpPrintf().

## create_url_list()

static int create_url_list | ( | memptr * | url_list,
|  | URL_list * | out
| ) |  |

static

Function to parse the Callback header value in subscription requests.

Takes in a buffer containing URLS delimited by '<' and '>'. The entire buffer is copied into dynamic memory and stored in the URL_list. Pointers to the individual urls within this buffer are allocated and stored in the URL_list. Only URLs with network addresses are considered (i.e. host:port or domain name).

Returns
  The number of URLs parsed if successful, otherwise UPNP_E_OUTOF_MEMORY.

Parameters

  [in] | url_list | .
  [out] | out | .

References memptr::buf, memptr::length, parse_uri(), HOSTPORT::text, UPNP_E_OUTOF_MEMORY, and URL_LIST::URLs.

Referenced by gena_process_subscription_request().

## free_notify_struct()

static void free_notify_struct | ( | void * | input | ) |

static

Frees memory used in notify_threads if the reference count is 0, otherwise decrements the refrence count.

Parameters

  [in] | input | Notify structure.

References ixmlFreeDOMString().

Referenced by genaNotifyThread().

## gena_process_subscription_renewal_request()

void gena_process_subscription_renewal_request | ( | SOCKINFO * | info,
|  | http_message_t * | request
| ) |  |

Handles a subscription renewal request from a ctrl point. The connection is not destroyed on return.

Parameters

  [in] | info | Socket info of the device.
  [in] | request | Subscription renewal request from the control point.

References memptr::buf, membuffer::buf, device_handle, SOCKINFO::foreign_sockaddr, GetDeviceHandleInfoForPath(), memptr::length, Handle_Info::MaxSubscriptions, Handle_Info::MaxSubscriptionTimeOut, PARSE_OK, respond_ok(), UPNP_E_SUCCESS, UpnpPrintf(), and http_message_t::uri.

Referenced by genaCallback().

## gena_process_subscription_request()

void gena_process_subscription_request | ( | SOCKINFO * | info,
|  | http_message_t * | request
| ) |  |

Handles a subscription request from a ctrl point. The socket is not closed on return.

Parameters

  [in] | info | Socket info of the device.
  [in] | request | Subscription request from the control point.

References memptr::buf, Handle_Info::Callback, Handle_Info::Cookie, create_url_list(), device_handle, SOCKINFO::foreign_sockaddr, gena_validate_delivery_urls(), GetDeviceHandleInfoForPath(), memptr::length, Handle_Info::MaxSubscriptions, Handle_Info::MaxSubscriptionTimeOut, PARSE_OK, respond_ok(), UPNP_E_OUTOF_MEMORY, UPNP_E_SUCCESS, UPNP_EVENT_SUBSCRIPTION_REQUEST, UpnpPrintf(), UpnpSubscriptionRequest_delete(), UpnpSubscriptionRequest_new(), UpnpSubscriptionRequest_strcpy_ServiceId(), UpnpSubscriptionRequest_strcpy_SID(), UpnpSubscriptionRequest_strcpy_UDN(), http_message_t::uri, and URL_LIST::URLs.

Referenced by genaCallback().

## gena_process_unsubscribe_request()

void gena_process_unsubscribe_request | ( | SOCKINFO * | info,
|  | http_message_t * | request
| ) |  |

Handles a subscription cancellation request from a ctrl point. The connection is not destroyed on return.

Parameters

  [in] | info | Socket info of the device.
  [in] | request | UNSUBSCRIBE request from the control point.

References memptr::buf, membuffer::buf, device_handle, SOCKINFO::foreign_sockaddr, GetDeviceHandleInfoForPath(), memptr::length, and http_message_t::uri.

Referenced by genaCallback().

## gena_validate_delivery_urls()

int gena_validate_delivery_urls | ( | SOCKINFO * | info,
|  | URL_list * | url_list
| ) |  |

Validate that the URLs passed by the user are on the same network segment than the device.

Note: This is a fix for CallStanger a.k.a. CVE-2020-12695

Returns
  0 if all URLs are on the same segment or -1 otherwise.

Parameters

  [in] | info | .
  [in] | url_list | .

References SOCKINFO::foreign_sockaddr, gIF_IPV4, gIF_IPV4_NETMASK, gIF_IPV6, gIF_IPV6_PREFIX_LENGTH, gIF_IPV6_ULA_GUA, gIF_IPV6_ULA_GUA_PREFIX_LENGTH, and UpnpPrintf().

Referenced by gena_process_subscription_request().

## genaInitNotify()

int genaInitNotify | ( | UpnpDevice_Handle | device_handle,
|  | char * | UDN,
|  | char * | servId,
|  | char ** | VarNames,
|  | char ** | VarValues,
|  | int | var_count,
|  | const Upnp_SID | sid
| ) |  |

Sends the intial state table dump to newly subscribed control point.

Returns
  GENA_E_SUCCESS if successful, otherwise the appropriate error code.

Note
  No other event will be sent to this control point before the intial state table dump.

Parameters

  [in] | device_handle | Device handle.
  [in] | UDN | Device udn.
  [in] | servId | Service ID.
  [in] | VarNames | Array of variable names.
  [in] | VarValues | Array of variable values.
  [in] | var_count | Array size.
  [in] | sid | Subscription ID.

References device_handle, DOMString, GeneratePropertySet(), and UpnpPrintf().

Referenced by UpnpAcceptSubscription().

## genaInitNotifyExt()

int genaInitNotifyExt | ( | UpnpDevice_Handle | device_handle,
|  | char * | UDN,
|  | char * | servId,
|  | IXML_Document * | PropSet,
|  | const Upnp_SID | sid
| ) |  |

Similar to the genaInitNofity. The only difference is that it takes the xml document for the state table and sends the intial state table dump to newly subscribed control point.

Returns
  GENA_E_SUCCESS if successful, otherwise the appropriate error code.

Note
  No other event will be sent to this control point before the intial state table dump.

Parameters

  [in] | device_handle | Device handle.
  [in] | UDN | Device udn.
  [in] | servId | Service ID.
  [in] | PropSet | Document of the state table.
  [in] | sid | subscription ID.

References device_handle, DOMString, ixmlPrintNode(), UPNP_E_INVALID_PARAM, and UpnpPrintf().

Referenced by UpnpAcceptSubscriptionExt().

## genaNotify()

static int genaNotify | ( | char * | headers,
|  | char * | propertySet,
|  | subscription * | sub
| ) |  |

static

Function to Notify a particular subscription of a particular event.

In general the service should NOT be blocked around this call (this may cause deadlock with a client).

NOTIFY http request is sent and the reply is processed.

Returns
  GENA_SUCCESS if the event was delivered, otherwise returns the appropriate error code.

Parameters

  [in] | headers | Null terminated, includes all headers (including \r\n) except SID and SEQ.
  [in] | propertySet | The evented XML.
  [in] | sub | subscription to be Notified, assumes this is valid for life of function.

References http_MakeMessage(), notify_send_and_recv(), http_message_t::status_code, UPNP_E_OUTOF_MEMORY, and UPNP_E_SUCCESS.

Referenced by genaNotifyThread().

## genaNotifyAll()

int genaNotifyAll | ( | UpnpDevice_Handle | device_handle,
|  | char * | UDN,
|  | char * | servId,
|  | char ** | VarNames,
|  | char ** | VarValues,
|  | int | var_count
| ) |  |

Sends a notification to all the subscribed control points.

Returns
  int

Note
  This function is similar to the genaNotifyAllExt. The only difference is it takes event variable array instead of xml document.

Parameters

  [in] | device_handle | Device handle.
  [in] | UDN | Device udn.
  [in] | servId | Service ID.
  [in] | VarNames | Array of varible names.
  [in] | VarValues | Array of variable values.
  [in] | var_count | Number of variables.

References device_handle, DOMString, GeneratePropertySet(), and UpnpPrintf().

Referenced by UpnpNotify().

## genaNotifyAllExt()

int genaNotifyAllExt | ( | UpnpDevice_Handle | device_handle,
|  | char * | UDN,
|  | char * | servId,
|  | IXML_Document * | PropSet
| ) |  |

Sends a notification to all the subscribed control points.

Returns
  int

Note
  This function is similar to the genaNotifyAll. the only difference is it takes the document instead of event variable array.

Parameters

  [in] | device_handle | Device handle.
  [in] | UDN | Device udn.
  [in] | servId | Service ID.
  [in] | PropSet | XML document Event varible property set.

References device_handle, DOMString, ixmlPrintNode(), UPNP_E_INVALID_PARAM, and UpnpPrintf().

Referenced by UpnpNotifyExt().

## genaNotifyThread()

static void genaNotifyThread | ( | void * | input | ) |

static

Thread job to Notify a control point.

It validates the subscription and copies the subscription. Also make sure that events are sent in order.

Note
  calls the genaNotify to do the actual work.

Parameters

  [in] | input | notify thread structure containing all the headers and property set info.

References free_notify_struct(), genaNotify(), GetHandleInfo(), gSendThreadPool, Handle_Info::ServiceTable, and ThreadPoolAdd().

## genaUnregisterDevice()

int genaUnregisterDevice | ( | UpnpDevice_Handle | device_handle | ) |

Unregisters a device.

Cleans the service table of the device.

Returns
  UPNP_E_SUCCESS on success, GENA_E_BAD_HANDLE on failure.

Parameters

  [in] | device_handle | Device handle.

References device_handle, GetHandleInfo(), Handle_Info::ServiceTable, UPNP_E_SUCCESS, and UpnpPrintf().

Referenced by UpnpUnRegisterRootDeviceLowPower().

## GeneratePropertySet()

static int GeneratePropertySet | ( | char ** | names,
|  | char ** | values,
|  | int | count,
|  | DOMString * | out
| ) |  |

static

Generates XML property set for notifications.

Returns
  UPNP_E_SUCCESS if successful else returns GENA_E_BAD_HANDLE.

Note
  The XML_VERSION comment is NOT sent due to interoperability issues with other UPnP vendors.

Parameters

  [in] | names | Array of variable names (go in the event notify).
  [in] | values | Array of variable values (go in the event notify).
  [in] | count | number of variables.
  [out] | out | PropertySet node in the string format.

References ixmlCloneDOMString(), and UPNP_E_OUTOF_MEMORY.

Referenced by genaInitNotify(), and genaNotifyAll().

## notify_send_and_recv()

static UPNP_INLINE int notify_send_and_recv | ( | uri_type * | destination_url,
|  | membuffer * | mid_msg,
|  | char * | propertySet,
|  | http_parser_t * | response
| ) |  |

static

Sends the notify message and returns a reply.

Returns
  on success returns UPNP_E_SUCCESS, otherwise returns a UPNP error.

Note
  called by genaNotify

Parameters

  [in] | destination_url | subscription callback URL (URL of the control point).
  [in] | mid_msg | Common HTTP headers.
  [in] | propertySet | The evented XML.
  [out] | response | The response from the control point.

References membuffer::buf, http_Connect(), http_MakeMessage(), http_RecvMessage(), http_SendMessage(), membuffer::length, sock_destroy(), sock_init(), HOSTPORT::text, UPNP_E_OUTOF_MEMORY, UPNP_E_SOCKET_CONNECT, UPNP_E_SUCCESS, and UpnpPrintf().

Referenced by genaNotify().

## respond_ok()

static int respond_ok | ( | SOCKINFO * | info,
|  | int | time_out,
|  | subscription * | sub,
|  | http_message_t * | request
| ) |  |

static

Returns OK message in the case of a subscription request.

Returns
  UPNP_E_SUCCESS if successful, otherwise the appropriate error code.

Parameters

  [in] | info | Socket connection of request.
  [in] | time_out | Accepted duration.
  [in] | sub | Accepted subscription.
  [in] | request | Http request.

References membuffer::buf, http_MakeMessage(), http_SendMessage(), membuffer::length, membuffer::size_inc, and UPNP_E_OUTOF_MEMORY.

Referenced by gena_process_subscription_renewal_request(), and gena_process_subscription_request().