16ba597c5SAnurag S. Maskey /*
26ba597c5SAnurag S. Maskey  * CDDL HEADER START
36ba597c5SAnurag S. Maskey  *
46ba597c5SAnurag S. Maskey  * The contents of this file are subject to the terms of the
56ba597c5SAnurag S. Maskey  * Common Development and Distribution License (the "License").
66ba597c5SAnurag S. Maskey  * You may not use this file except in compliance with the License.
76ba597c5SAnurag S. Maskey  *
86ba597c5SAnurag S. Maskey  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ba597c5SAnurag S. Maskey  * or http://www.opensolaris.org/os/licensing.
106ba597c5SAnurag S. Maskey  * See the License for the specific language governing permissions
116ba597c5SAnurag S. Maskey  * and limitations under the License.
126ba597c5SAnurag S. Maskey  *
136ba597c5SAnurag S. Maskey  * When distributing Covered Code, include this CDDL HEADER in each
146ba597c5SAnurag S. Maskey  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ba597c5SAnurag S. Maskey  * If applicable, add the following below this CDDL HEADER, with the
166ba597c5SAnurag S. Maskey  * fields enclosed by brackets "[]" replaced with your own identifying
176ba597c5SAnurag S. Maskey  * information: Portions Copyright [yyyy] [name of copyright owner]
186ba597c5SAnurag S. Maskey  *
196ba597c5SAnurag S. Maskey  * CDDL HEADER END
206ba597c5SAnurag S. Maskey  */
216ba597c5SAnurag S. Maskey 
226ba597c5SAnurag S. Maskey /*
23*f6da83d4SAnurag S. Maskey  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
246ba597c5SAnurag S. Maskey  */
256ba597c5SAnurag S. Maskey 
266ba597c5SAnurag S. Maskey #include <arpa/inet.h>
276ba597c5SAnurag S. Maskey #include <assert.h>
286ba597c5SAnurag S. Maskey #include <fcntl.h>
296ba597c5SAnurag S. Maskey #include <libdlpi.h>
306ba597c5SAnurag S. Maskey #include <libnwam.h>
316ba597c5SAnurag S. Maskey #include <net/if.h>
326ba597c5SAnurag S. Maskey #include <pthread.h>
336ba597c5SAnurag S. Maskey #include <stdio.h>
346ba597c5SAnurag S. Maskey #include <stdlib.h>
356ba597c5SAnurag S. Maskey #include <string.h>
366ba597c5SAnurag S. Maskey #include <sys/fcntl.h>
376ba597c5SAnurag S. Maskey #include <unistd.h>
386ba597c5SAnurag S. Maskey 
396ba597c5SAnurag S. Maskey #include "events.h"
406ba597c5SAnurag S. Maskey #include "ncp.h"
416ba597c5SAnurag S. Maskey #include "ncu.h"
426ba597c5SAnurag S. Maskey #include "objects.h"
436ba597c5SAnurag S. Maskey #include "util.h"
446ba597c5SAnurag S. Maskey 
456ba597c5SAnurag S. Maskey /*
466ba597c5SAnurag S. Maskey  * dlpi_events.c - this file contains routines to retrieve
476ba597c5SAnurag S. Maskey  * DL_NOTE_LINK_[UP|DOWN] events from the system and packages them for high
486ba597c5SAnurag S. Maskey  * level processing.  Holding a dlpi_handle to a link prevents the
496ba597c5SAnurag S. Maskey  * associated driver unloading that can happen when IP is not plumbed,
506ba597c5SAnurag S. Maskey  * so it is vital to ensure that the handle is open for the lifetime
516ba597c5SAnurag S. Maskey  * of the WiFi connection.
526ba597c5SAnurag S. Maskey  */
536ba597c5SAnurag S. Maskey 
546ba597c5SAnurag S. Maskey /*
556ba597c5SAnurag S. Maskey  * This is a callback function executed when dlpi_recv() gets a DL_NOTE_LINK_UP.
566ba597c5SAnurag S. Maskey  * It packages up the event for consumption by the link state machine.
576ba597c5SAnurag S. Maskey  */
586ba597c5SAnurag S. Maskey /* ARGSUSED0 */
596ba597c5SAnurag S. Maskey static void
nwamd_dlpi_notify(dlpi_handle_t dhp,dlpi_notifyinfo_t * info,void * arg)606ba597c5SAnurag S. Maskey nwamd_dlpi_notify(dlpi_handle_t dhp, dlpi_notifyinfo_t *info, void *arg)
616ba597c5SAnurag S. Maskey {
626ba597c5SAnurag S. Maskey 	nwamd_event_t ev;
636ba597c5SAnurag S. Maskey 	char *name = arg;
646ba597c5SAnurag S. Maskey 
656ba597c5SAnurag S. Maskey 	if (info->dni_note & DL_NOTE_LINK_UP)
666ba597c5SAnurag S. Maskey 		ev = nwamd_event_init_link_state(name, B_TRUE);
676ba597c5SAnurag S. Maskey 	else
686ba597c5SAnurag S. Maskey 		ev = nwamd_event_init_link_state(name, B_FALSE);
696ba597c5SAnurag S. Maskey 	if (ev != NULL)
706ba597c5SAnurag S. Maskey 		nwamd_event_enqueue(ev);
716ba597c5SAnurag S. Maskey }
726ba597c5SAnurag S. Maskey 
736ba597c5SAnurag S. Maskey /*
746ba597c5SAnurag S. Maskey  * We are only intested in DL_NOTE_LINK_UP events which we've registered for
756ba597c5SAnurag S. Maskey  * in nwamd_dlpi_add_link().  But we have to keep calling dlpi_recv() to
766ba597c5SAnurag S. Maskey  * force the notification callback to be executed.
776ba597c5SAnurag S. Maskey  */
786ba597c5SAnurag S. Maskey static void *
nwamd_dlpi_thread(void * arg)796ba597c5SAnurag S. Maskey nwamd_dlpi_thread(void *arg)
806ba597c5SAnurag S. Maskey {
816ba597c5SAnurag S. Maskey 	int rc;
826ba597c5SAnurag S. Maskey 	dlpi_handle_t *dh = arg;
836ba597c5SAnurag S. Maskey 
846ba597c5SAnurag S. Maskey 	do {
856ba597c5SAnurag S. Maskey 		rc = dlpi_recv(*dh, NULL, NULL, NULL, NULL, -1, NULL);
866ba597c5SAnurag S. Maskey 	} while (rc == DLPI_SUCCESS);
876ba597c5SAnurag S. Maskey 	nlog(LOG_ERR, "dlpi_recv failed: %s", dlpi_strerror(rc));
886ba597c5SAnurag S. Maskey 	return (NULL);
896ba597c5SAnurag S. Maskey }
906ba597c5SAnurag S. Maskey 
916ba597c5SAnurag S. Maskey /*
926ba597c5SAnurag S. Maskey  * This is called when we want to start receiving notifications from state
936ba597c5SAnurag S. Maskey  * changes on a link.
946ba597c5SAnurag S. Maskey  */
956ba597c5SAnurag S. Maskey void
nwamd_dlpi_add_link(nwamd_object_t obj)966ba597c5SAnurag S. Maskey nwamd_dlpi_add_link(nwamd_object_t obj)
976ba597c5SAnurag S. Maskey {
986ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu = obj->nwamd_object_data;
996ba597c5SAnurag S. Maskey 	nwamd_link_t *link;
1006ba597c5SAnurag S. Maskey 	dlpi_notifyid_t id;
1016ba597c5SAnurag S. Maskey 	int rc;
1026ba597c5SAnurag S. Maskey 
1036ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_dlpi_add_link: ncu %p (%s) type %d",
1046ba597c5SAnurag S. Maskey 	    ncu, obj->nwamd_object_name, ncu != NULL ? ncu->ncu_type : -1);
1056ba597c5SAnurag S. Maskey 
1066ba597c5SAnurag S. Maskey 	assert(ncu != NULL && ncu->ncu_type == NWAM_NCU_TYPE_LINK);
1076ba597c5SAnurag S. Maskey 
108*f6da83d4SAnurag S. Maskey 	link = &ncu->ncu_link;
1096ba597c5SAnurag S. Maskey 
1106ba597c5SAnurag S. Maskey 	/* Already running? */
1116ba597c5SAnurag S. Maskey 	if (link->nwamd_link_dlpi_thread != 0) {
1126ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_dlpi_add_link(%s) already running",
1136ba597c5SAnurag S. Maskey 		    obj->nwamd_object_name);
1146ba597c5SAnurag S. Maskey 		return;
1156ba597c5SAnurag S. Maskey 	}
1166ba597c5SAnurag S. Maskey 
1176ba597c5SAnurag S. Maskey 	rc = dlpi_open(ncu->ncu_name, &link->nwamd_link_dhp, 0);
1186ba597c5SAnurag S. Maskey 	if (rc != DLPI_SUCCESS) {
1196ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_dlpi_add_link: dlpi_open(%s) = %s",
1206ba597c5SAnurag S. Maskey 		    ncu->ncu_name, dlpi_strerror(rc));
1216ba597c5SAnurag S. Maskey 		return;
1226ba597c5SAnurag S. Maskey 	}
1236ba597c5SAnurag S. Maskey 
1246ba597c5SAnurag S. Maskey 	nwamd_set_unset_link_properties(ncu, B_TRUE);
1256ba597c5SAnurag S. Maskey 
1266ba597c5SAnurag S. Maskey 	rc = dlpi_enabnotify(link->nwamd_link_dhp,
1276ba597c5SAnurag S. Maskey 	    DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN, nwamd_dlpi_notify,
1286ba597c5SAnurag S. Maskey 	    ncu->ncu_name, &id);
1296ba597c5SAnurag S. Maskey 	if (rc != DLPI_SUCCESS) {
1306ba597c5SAnurag S. Maskey 		nlog(LOG_ERR,
1316ba597c5SAnurag S. Maskey 		    "nwamd_dlpi_add_link: dlpi_enabnotify(%s) = %s",
1326ba597c5SAnurag S. Maskey 		    obj->nwamd_object_name, dlpi_strerror(rc));
1336ba597c5SAnurag S. Maskey 		dlpi_close(link->nwamd_link_dhp);
1346ba597c5SAnurag S. Maskey 		return;
1356ba597c5SAnurag S. Maskey 	}
1366ba597c5SAnurag S. Maskey 
1376ba597c5SAnurag S. Maskey 	rc = pthread_create(&link->nwamd_link_dlpi_thread, NULL,
1386ba597c5SAnurag S. Maskey 	    nwamd_dlpi_thread, &link->nwamd_link_dhp);
1396ba597c5SAnurag S. Maskey 	if (rc != 0) {
1406ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_dlpi_add_link: couldn't create "
1416ba597c5SAnurag S. Maskey 		    "dlpi thread for %s: %s", obj->nwamd_object_name,
1426ba597c5SAnurag S. Maskey 		    strerror(rc));
1436ba597c5SAnurag S. Maskey 		dlpi_close(link->nwamd_link_dhp);
1446ba597c5SAnurag S. Maskey 	}
1456ba597c5SAnurag S. Maskey }
1466ba597c5SAnurag S. Maskey 
1476ba597c5SAnurag S. Maskey /*
1486ba597c5SAnurag S. Maskey  * This function is called when we are no longer interested in receiving
1496ba597c5SAnurag S. Maskey  * notification from state changes on a link.
1506ba597c5SAnurag S. Maskey  */
1516ba597c5SAnurag S. Maskey void
nwamd_dlpi_delete_link(nwamd_object_t obj)1526ba597c5SAnurag S. Maskey nwamd_dlpi_delete_link(nwamd_object_t obj)
1536ba597c5SAnurag S. Maskey {
1546ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu = obj->nwamd_object_data;
1556ba597c5SAnurag S. Maskey 
1566ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_dlpi_delete_link: ncu %p (%s) type %d",
1576ba597c5SAnurag S. Maskey 	    ncu, obj->nwamd_object_name, ncu != NULL ? ncu->ncu_type : -1);
1586ba597c5SAnurag S. Maskey 
159*f6da83d4SAnurag S. Maskey 	if (ncu->ncu_link.nwamd_link_dlpi_thread != 0) {
1606ba597c5SAnurag S. Maskey 		(void) pthread_cancel(
161*f6da83d4SAnurag S. Maskey 		    ncu->ncu_link.nwamd_link_dlpi_thread);
162*f6da83d4SAnurag S. Maskey 		(void) pthread_join(ncu->ncu_link.nwamd_link_dlpi_thread, NULL);
163*f6da83d4SAnurag S. Maskey 		ncu->ncu_link.nwamd_link_dlpi_thread = 0;
1646ba597c5SAnurag S. Maskey 		/* Unset properties before closing */
1656ba597c5SAnurag S. Maskey 		nwamd_set_unset_link_properties(ncu, B_FALSE);
1666ba597c5SAnurag S. Maskey 	}
1676ba597c5SAnurag S. Maskey 
168*f6da83d4SAnurag S. Maskey 	dlpi_close(ncu->ncu_link.nwamd_link_dhp);
169*f6da83d4SAnurag S. Maskey 	ncu->ncu_link.nwamd_link_dhp = NULL;
1706ba597c5SAnurag S. Maskey }
171