Browse Source

WPS: Send SSDP byebye notifications when stopping UPnP advertisements

This will notify control points of the services going away and allows
them to notice this without having to wait timeout on the
initial advertisements.
Jouni Malinen 15 years ago
parent
commit
44577e4c2e
3 changed files with 36 additions and 5 deletions
  1. 1 2
      src/wps/wps_upnp.c
  2. 2 1
      src/wps/wps_upnp_i.h
  3. 33 2
      src/wps/wps_upnp_ssdp.c

+ 1 - 2
src/wps/wps_upnp.c

@@ -964,8 +964,7 @@ void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
 		subscription_destroy(s);
 	}
 
-	advertisement_state_machine_stop(sm);
-	/* TODO: send byebye notifications */
+	advertisement_state_machine_stop(sm, 1);
 
 	event_send_stop_all(sm);
 	os_free(sm->wlanevent);

+ 2 - 1
src/wps/wps_upnp_i.h

@@ -159,7 +159,8 @@ int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
 /* wps_upnp_ssdp.c */
 void msearchreply_state_machine_stop(struct advertisement_state_machine *a);
 int advertisement_state_machine_start(struct upnp_wps_device_sm *sm);
-void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm);
+void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm,
+				      int send_byebye);
 void ssdp_listener_stop(struct upnp_wps_device_sm *sm);
 int ssdp_listener_start(struct upnp_wps_device_sm *sm);
 int ssdp_listener_open(void);

+ 33 - 2
src/wps/wps_upnp_ssdp.c

@@ -228,10 +228,41 @@ static void advertisement_state_machine_handler(void *eloop_data,
 /**
  * advertisement_state_machine_stop - Stop SSDP advertisements
  * @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @send_byebye: Send byebye advertisement messages immediately
  */
-void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm)
+void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm,
+				      int send_byebye)
 {
+	struct advertisement_state_machine *a = &sm->advertisement;
+	int islast = 0;
+	struct wpabuf *msg;
+	struct sockaddr_in dest;
+
 	eloop_cancel_timeout(advertisement_state_machine_handler, NULL, sm);
+	if (!send_byebye)
+		return;
+
+	a->type = ADVERTISE_DOWN;
+	a->state = 0;
+	a->sm = sm;
+
+	os_memset(&dest, 0, sizeof(dest));
+	dest.sin_family = AF_INET;
+	dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
+	dest.sin_port = htons(UPNP_MULTICAST_PORT);
+
+	while (!islast) {
+		msg = next_advertisement(a, &islast);
+		if (msg == NULL)
+			break;
+		if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg),
+			   0, (struct sockaddr *) &dest, sizeof(dest)) < 0) {
+			wpa_printf(MSG_INFO, "WPS UPnP: Advertisement sendto "
+				   "failed: %d (%s)", errno, strerror(errno));
+		}
+		wpabuf_free(msg);
+		a->state++;
+	}
 }
 
 
@@ -317,7 +348,7 @@ int advertisement_state_machine_start(struct upnp_wps_device_sm *sm)
 	struct advertisement_state_machine *a = &sm->advertisement;
 	int next_timeout_msec;
 
-	advertisement_state_machine_stop(sm);
+	advertisement_state_machine_stop(sm, 0);
 
 	/*
 	 * Start out advertising down, this automatically switches