111767SAnurag.Maskey@Sun.COM /*
211767SAnurag.Maskey@Sun.COM * CDDL HEADER START
311767SAnurag.Maskey@Sun.COM *
411767SAnurag.Maskey@Sun.COM * The contents of this file are subject to the terms of the
511767SAnurag.Maskey@Sun.COM * Common Development and Distribution License (the "License").
611767SAnurag.Maskey@Sun.COM * You may not use this file except in compliance with the License.
711767SAnurag.Maskey@Sun.COM *
811767SAnurag.Maskey@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911767SAnurag.Maskey@Sun.COM * or http://www.opensolaris.org/os/licensing.
1011767SAnurag.Maskey@Sun.COM * See the License for the specific language governing permissions
1111767SAnurag.Maskey@Sun.COM * and limitations under the License.
1211767SAnurag.Maskey@Sun.COM *
1311767SAnurag.Maskey@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1411767SAnurag.Maskey@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511767SAnurag.Maskey@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1611767SAnurag.Maskey@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1711767SAnurag.Maskey@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1811767SAnurag.Maskey@Sun.COM *
1911767SAnurag.Maskey@Sun.COM * CDDL HEADER END
2011767SAnurag.Maskey@Sun.COM */
2111767SAnurag.Maskey@Sun.COM
2211767SAnurag.Maskey@Sun.COM /*
23*12576SAnurag.Maskey@Oracle.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2411767SAnurag.Maskey@Sun.COM */
2511767SAnurag.Maskey@Sun.COM
2611767SAnurag.Maskey@Sun.COM #include <arpa/inet.h>
2711767SAnurag.Maskey@Sun.COM #include <assert.h>
2811767SAnurag.Maskey@Sun.COM #include <fcntl.h>
2911767SAnurag.Maskey@Sun.COM #include <libdlpi.h>
3011767SAnurag.Maskey@Sun.COM #include <libnwam.h>
3111767SAnurag.Maskey@Sun.COM #include <net/if.h>
3211767SAnurag.Maskey@Sun.COM #include <pthread.h>
3311767SAnurag.Maskey@Sun.COM #include <stdio.h>
3411767SAnurag.Maskey@Sun.COM #include <stdlib.h>
3511767SAnurag.Maskey@Sun.COM #include <string.h>
3611767SAnurag.Maskey@Sun.COM #include <sys/fcntl.h>
3711767SAnurag.Maskey@Sun.COM #include <unistd.h>
3811767SAnurag.Maskey@Sun.COM
3911767SAnurag.Maskey@Sun.COM #include "events.h"
4011767SAnurag.Maskey@Sun.COM #include "ncp.h"
4111767SAnurag.Maskey@Sun.COM #include "ncu.h"
4211767SAnurag.Maskey@Sun.COM #include "objects.h"
4311767SAnurag.Maskey@Sun.COM #include "util.h"
4411767SAnurag.Maskey@Sun.COM
4511767SAnurag.Maskey@Sun.COM /*
4611767SAnurag.Maskey@Sun.COM * dlpi_events.c - this file contains routines to retrieve
4711767SAnurag.Maskey@Sun.COM * DL_NOTE_LINK_[UP|DOWN] events from the system and packages them for high
4811767SAnurag.Maskey@Sun.COM * level processing. Holding a dlpi_handle to a link prevents the
4911767SAnurag.Maskey@Sun.COM * associated driver unloading that can happen when IP is not plumbed,
5011767SAnurag.Maskey@Sun.COM * so it is vital to ensure that the handle is open for the lifetime
5111767SAnurag.Maskey@Sun.COM * of the WiFi connection.
5211767SAnurag.Maskey@Sun.COM */
5311767SAnurag.Maskey@Sun.COM
5411767SAnurag.Maskey@Sun.COM /*
5511767SAnurag.Maskey@Sun.COM * This is a callback function executed when dlpi_recv() gets a DL_NOTE_LINK_UP.
5611767SAnurag.Maskey@Sun.COM * It packages up the event for consumption by the link state machine.
5711767SAnurag.Maskey@Sun.COM */
5811767SAnurag.Maskey@Sun.COM /* ARGSUSED0 */
5911767SAnurag.Maskey@Sun.COM static void
nwamd_dlpi_notify(dlpi_handle_t dhp,dlpi_notifyinfo_t * info,void * arg)6011767SAnurag.Maskey@Sun.COM nwamd_dlpi_notify(dlpi_handle_t dhp, dlpi_notifyinfo_t *info, void *arg)
6111767SAnurag.Maskey@Sun.COM {
6211767SAnurag.Maskey@Sun.COM nwamd_event_t ev;
6311767SAnurag.Maskey@Sun.COM char *name = arg;
6411767SAnurag.Maskey@Sun.COM
6511767SAnurag.Maskey@Sun.COM if (info->dni_note & DL_NOTE_LINK_UP)
6611767SAnurag.Maskey@Sun.COM ev = nwamd_event_init_link_state(name, B_TRUE);
6711767SAnurag.Maskey@Sun.COM else
6811767SAnurag.Maskey@Sun.COM ev = nwamd_event_init_link_state(name, B_FALSE);
6911767SAnurag.Maskey@Sun.COM if (ev != NULL)
7011767SAnurag.Maskey@Sun.COM nwamd_event_enqueue(ev);
7111767SAnurag.Maskey@Sun.COM }
7211767SAnurag.Maskey@Sun.COM
7311767SAnurag.Maskey@Sun.COM /*
7411767SAnurag.Maskey@Sun.COM * We are only intested in DL_NOTE_LINK_UP events which we've registered for
7511767SAnurag.Maskey@Sun.COM * in nwamd_dlpi_add_link(). But we have to keep calling dlpi_recv() to
7611767SAnurag.Maskey@Sun.COM * force the notification callback to be executed.
7711767SAnurag.Maskey@Sun.COM */
7811767SAnurag.Maskey@Sun.COM static void *
nwamd_dlpi_thread(void * arg)7911767SAnurag.Maskey@Sun.COM nwamd_dlpi_thread(void *arg)
8011767SAnurag.Maskey@Sun.COM {
8111767SAnurag.Maskey@Sun.COM int rc;
8211767SAnurag.Maskey@Sun.COM dlpi_handle_t *dh = arg;
8311767SAnurag.Maskey@Sun.COM
8411767SAnurag.Maskey@Sun.COM do {
8511767SAnurag.Maskey@Sun.COM rc = dlpi_recv(*dh, NULL, NULL, NULL, NULL, -1, NULL);
8611767SAnurag.Maskey@Sun.COM } while (rc == DLPI_SUCCESS);
8711767SAnurag.Maskey@Sun.COM nlog(LOG_ERR, "dlpi_recv failed: %s", dlpi_strerror(rc));
8811767SAnurag.Maskey@Sun.COM return (NULL);
8911767SAnurag.Maskey@Sun.COM }
9011767SAnurag.Maskey@Sun.COM
9111767SAnurag.Maskey@Sun.COM /*
9211767SAnurag.Maskey@Sun.COM * This is called when we want to start receiving notifications from state
9311767SAnurag.Maskey@Sun.COM * changes on a link.
9411767SAnurag.Maskey@Sun.COM */
9511767SAnurag.Maskey@Sun.COM void
nwamd_dlpi_add_link(nwamd_object_t obj)9611767SAnurag.Maskey@Sun.COM nwamd_dlpi_add_link(nwamd_object_t obj)
9711767SAnurag.Maskey@Sun.COM {
9811767SAnurag.Maskey@Sun.COM nwamd_ncu_t *ncu = obj->nwamd_object_data;
9911767SAnurag.Maskey@Sun.COM nwamd_link_t *link;
10011767SAnurag.Maskey@Sun.COM dlpi_notifyid_t id;
10111767SAnurag.Maskey@Sun.COM int rc;
10211767SAnurag.Maskey@Sun.COM
10311767SAnurag.Maskey@Sun.COM nlog(LOG_DEBUG, "nwamd_dlpi_add_link: ncu %p (%s) type %d",
10411767SAnurag.Maskey@Sun.COM ncu, obj->nwamd_object_name, ncu != NULL ? ncu->ncu_type : -1);
10511767SAnurag.Maskey@Sun.COM
10611767SAnurag.Maskey@Sun.COM assert(ncu != NULL && ncu->ncu_type == NWAM_NCU_TYPE_LINK);
10711767SAnurag.Maskey@Sun.COM
108*12576SAnurag.Maskey@Oracle.COM link = &ncu->ncu_link;
10911767SAnurag.Maskey@Sun.COM
11011767SAnurag.Maskey@Sun.COM /* Already running? */
11111767SAnurag.Maskey@Sun.COM if (link->nwamd_link_dlpi_thread != 0) {
11211767SAnurag.Maskey@Sun.COM nlog(LOG_DEBUG, "nwamd_dlpi_add_link(%s) already running",
11311767SAnurag.Maskey@Sun.COM obj->nwamd_object_name);
11411767SAnurag.Maskey@Sun.COM return;
11511767SAnurag.Maskey@Sun.COM }
11611767SAnurag.Maskey@Sun.COM
11711767SAnurag.Maskey@Sun.COM rc = dlpi_open(ncu->ncu_name, &link->nwamd_link_dhp, 0);
11811767SAnurag.Maskey@Sun.COM if (rc != DLPI_SUCCESS) {
11911767SAnurag.Maskey@Sun.COM nlog(LOG_ERR, "nwamd_dlpi_add_link: dlpi_open(%s) = %s",
12011767SAnurag.Maskey@Sun.COM ncu->ncu_name, dlpi_strerror(rc));
12111767SAnurag.Maskey@Sun.COM return;
12211767SAnurag.Maskey@Sun.COM }
12311767SAnurag.Maskey@Sun.COM
12411767SAnurag.Maskey@Sun.COM nwamd_set_unset_link_properties(ncu, B_TRUE);
12511767SAnurag.Maskey@Sun.COM
12611767SAnurag.Maskey@Sun.COM rc = dlpi_enabnotify(link->nwamd_link_dhp,
12711767SAnurag.Maskey@Sun.COM DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN, nwamd_dlpi_notify,
12811767SAnurag.Maskey@Sun.COM ncu->ncu_name, &id);
12911767SAnurag.Maskey@Sun.COM if (rc != DLPI_SUCCESS) {
13011767SAnurag.Maskey@Sun.COM nlog(LOG_ERR,
13111767SAnurag.Maskey@Sun.COM "nwamd_dlpi_add_link: dlpi_enabnotify(%s) = %s",
13211767SAnurag.Maskey@Sun.COM obj->nwamd_object_name, dlpi_strerror(rc));
13311767SAnurag.Maskey@Sun.COM dlpi_close(link->nwamd_link_dhp);
13411767SAnurag.Maskey@Sun.COM return;
13511767SAnurag.Maskey@Sun.COM }
13611767SAnurag.Maskey@Sun.COM
13711767SAnurag.Maskey@Sun.COM rc = pthread_create(&link->nwamd_link_dlpi_thread, NULL,
13811767SAnurag.Maskey@Sun.COM nwamd_dlpi_thread, &link->nwamd_link_dhp);
13911767SAnurag.Maskey@Sun.COM if (rc != 0) {
14011767SAnurag.Maskey@Sun.COM nlog(LOG_ERR, "nwamd_dlpi_add_link: couldn't create "
14111767SAnurag.Maskey@Sun.COM "dlpi thread for %s: %s", obj->nwamd_object_name,
14211767SAnurag.Maskey@Sun.COM strerror(rc));
14311767SAnurag.Maskey@Sun.COM dlpi_close(link->nwamd_link_dhp);
14411767SAnurag.Maskey@Sun.COM }
14511767SAnurag.Maskey@Sun.COM }
14611767SAnurag.Maskey@Sun.COM
14711767SAnurag.Maskey@Sun.COM /*
14811767SAnurag.Maskey@Sun.COM * This function is called when we are no longer interested in receiving
14911767SAnurag.Maskey@Sun.COM * notification from state changes on a link.
15011767SAnurag.Maskey@Sun.COM */
15111767SAnurag.Maskey@Sun.COM void
nwamd_dlpi_delete_link(nwamd_object_t obj)15211767SAnurag.Maskey@Sun.COM nwamd_dlpi_delete_link(nwamd_object_t obj)
15311767SAnurag.Maskey@Sun.COM {
15411767SAnurag.Maskey@Sun.COM nwamd_ncu_t *ncu = obj->nwamd_object_data;
15511767SAnurag.Maskey@Sun.COM
15611767SAnurag.Maskey@Sun.COM nlog(LOG_DEBUG, "nwamd_dlpi_delete_link: ncu %p (%s) type %d",
15711767SAnurag.Maskey@Sun.COM ncu, obj->nwamd_object_name, ncu != NULL ? ncu->ncu_type : -1);
15811767SAnurag.Maskey@Sun.COM
159*12576SAnurag.Maskey@Oracle.COM if (ncu->ncu_link.nwamd_link_dlpi_thread != 0) {
16011767SAnurag.Maskey@Sun.COM (void) pthread_cancel(
161*12576SAnurag.Maskey@Oracle.COM ncu->ncu_link.nwamd_link_dlpi_thread);
162*12576SAnurag.Maskey@Oracle.COM (void) pthread_join(ncu->ncu_link.nwamd_link_dlpi_thread, NULL);
163*12576SAnurag.Maskey@Oracle.COM ncu->ncu_link.nwamd_link_dlpi_thread = 0;
16411767SAnurag.Maskey@Sun.COM /* Unset properties before closing */
16511767SAnurag.Maskey@Sun.COM nwamd_set_unset_link_properties(ncu, B_FALSE);
16611767SAnurag.Maskey@Sun.COM }
16711767SAnurag.Maskey@Sun.COM
168*12576SAnurag.Maskey@Oracle.COM dlpi_close(ncu->ncu_link.nwamd_link_dhp);
169*12576SAnurag.Maskey@Oracle.COM ncu->ncu_link.nwamd_link_dhp = NULL;
17011767SAnurag.Maskey@Sun.COM }
171