1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <arpa/inet.h> 28 #include <assert.h> 29 #include <fcntl.h> 30 #include <libdlpi.h> 31 #include <libnwam.h> 32 #include <net/if.h> 33 #include <pthread.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <sys/fcntl.h> 38 #include <unistd.h> 39 40 #include "events.h" 41 #include "ncp.h" 42 #include "ncu.h" 43 #include "objects.h" 44 #include "util.h" 45 46 /* 47 * dlpi_events.c - this file contains routines to retrieve 48 * DL_NOTE_LINK_[UP|DOWN] events from the system and packages them for high 49 * level processing. Holding a dlpi_handle to a link prevents the 50 * associated driver unloading that can happen when IP is not plumbed, 51 * so it is vital to ensure that the handle is open for the lifetime 52 * of the WiFi connection. 53 */ 54 55 /* 56 * This is a callback function executed when dlpi_recv() gets a DL_NOTE_LINK_UP. 57 * It packages up the event for consumption by the link state machine. 58 */ 59 /* ARGSUSED0 */ 60 static void 61 nwamd_dlpi_notify(dlpi_handle_t dhp, dlpi_notifyinfo_t *info, void *arg) 62 { 63 nwamd_event_t ev; 64 char *name = arg; 65 66 if (info->dni_note & DL_NOTE_LINK_UP) 67 ev = nwamd_event_init_link_state(name, B_TRUE); 68 else 69 ev = nwamd_event_init_link_state(name, B_FALSE); 70 if (ev != NULL) 71 nwamd_event_enqueue(ev); 72 } 73 74 /* 75 * We are only intested in DL_NOTE_LINK_UP events which we've registered for 76 * in nwamd_dlpi_add_link(). But we have to keep calling dlpi_recv() to 77 * force the notification callback to be executed. 78 */ 79 static void * 80 nwamd_dlpi_thread(void *arg) 81 { 82 int rc; 83 dlpi_handle_t *dh = arg; 84 85 do { 86 rc = dlpi_recv(*dh, NULL, NULL, NULL, NULL, -1, NULL); 87 } while (rc == DLPI_SUCCESS); 88 nlog(LOG_ERR, "dlpi_recv failed: %s", dlpi_strerror(rc)); 89 return (NULL); 90 } 91 92 /* 93 * This is called when we want to start receiving notifications from state 94 * changes on a link. 95 */ 96 void 97 nwamd_dlpi_add_link(nwamd_object_t obj) 98 { 99 nwamd_ncu_t *ncu = obj->nwamd_object_data; 100 nwamd_link_t *link; 101 dlpi_notifyid_t id; 102 int rc; 103 104 nlog(LOG_DEBUG, "nwamd_dlpi_add_link: ncu %p (%s) type %d", 105 ncu, obj->nwamd_object_name, ncu != NULL ? ncu->ncu_type : -1); 106 107 assert(ncu != NULL && ncu->ncu_type == NWAM_NCU_TYPE_LINK); 108 109 link = &ncu->ncu_node.u_link; 110 111 /* Already running? */ 112 if (link->nwamd_link_dlpi_thread != 0) { 113 nlog(LOG_DEBUG, "nwamd_dlpi_add_link(%s) already running", 114 obj->nwamd_object_name); 115 return; 116 } 117 118 rc = dlpi_open(ncu->ncu_name, &link->nwamd_link_dhp, 0); 119 if (rc != DLPI_SUCCESS) { 120 nlog(LOG_ERR, "nwamd_dlpi_add_link: dlpi_open(%s) = %s", 121 ncu->ncu_name, dlpi_strerror(rc)); 122 return; 123 } 124 125 nwamd_set_unset_link_properties(ncu, B_TRUE); 126 127 rc = dlpi_enabnotify(link->nwamd_link_dhp, 128 DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN, nwamd_dlpi_notify, 129 ncu->ncu_name, &id); 130 if (rc != DLPI_SUCCESS) { 131 nlog(LOG_ERR, 132 "nwamd_dlpi_add_link: dlpi_enabnotify(%s) = %s", 133 obj->nwamd_object_name, dlpi_strerror(rc)); 134 dlpi_close(link->nwamd_link_dhp); 135 return; 136 } 137 138 rc = pthread_create(&link->nwamd_link_dlpi_thread, NULL, 139 nwamd_dlpi_thread, &link->nwamd_link_dhp); 140 if (rc != 0) { 141 nlog(LOG_ERR, "nwamd_dlpi_add_link: couldn't create " 142 "dlpi thread for %s: %s", obj->nwamd_object_name, 143 strerror(rc)); 144 dlpi_close(link->nwamd_link_dhp); 145 } 146 } 147 148 /* 149 * This function is called when we are no longer interested in receiving 150 * notification from state changes on a link. 151 */ 152 void 153 nwamd_dlpi_delete_link(nwamd_object_t obj) 154 { 155 nwamd_ncu_t *ncu = obj->nwamd_object_data; 156 157 nlog(LOG_DEBUG, "nwamd_dlpi_delete_link: ncu %p (%s) type %d", 158 ncu, obj->nwamd_object_name, ncu != NULL ? ncu->ncu_type : -1); 159 160 if (ncu->ncu_node.u_link.nwamd_link_dlpi_thread != 0) { 161 (void) pthread_cancel( 162 ncu->ncu_node.u_link.nwamd_link_dlpi_thread); 163 (void) pthread_join(ncu->ncu_node.u_link.nwamd_link_dlpi_thread, 164 NULL); 165 ncu->ncu_node.u_link.nwamd_link_dlpi_thread = 0; 166 /* Unset properties before closing */ 167 nwamd_set_unset_link_properties(ncu, B_FALSE); 168 } 169 170 dlpi_close(ncu->ncu_node.u_link.nwamd_link_dhp); 171 ncu->ncu_node.u_link.nwamd_link_dhp = NULL; 172 } 173