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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Main startup code for SMB/NETBIOS and some utility routines 30 * for the NETBIOS layer. 31 */ 32 33 #include <synch.h> 34 #include <unistd.h> 35 #include <syslog.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <sys/socket.h> 39 40 #include <smbns_netbios.h> 41 42 netbios_status_t nb_status; 43 44 static pthread_t smb_nbns_thr; /* name service */ 45 static pthread_t smb_nbds_thr; /* dgram service */ 46 static pthread_t smb_nbts_thr; /* timer */ 47 static pthread_t smb_nbbs_thr; /* browser */ 48 49 static void *smb_netbios_timer(void *); 50 51 void 52 smb_netbios_chg_status(uint32_t status, int set) 53 { 54 (void) mutex_lock(&nb_status.mtx); 55 if (set) 56 nb_status.state |= status; 57 else 58 nb_status.state &= ~status; 59 (void) cond_broadcast(&nb_status.cv); 60 (void) mutex_unlock(&nb_status.mtx); 61 } 62 63 void 64 smb_netbios_shutdown(void) 65 { 66 smb_netbios_chg_status(NETBIOS_SHUTTING_DOWN, 1); 67 68 (void) pthread_join(smb_nbts_thr, 0); 69 (void) pthread_join(smb_nbbs_thr, 0); 70 (void) pthread_join(smb_nbns_thr, 0); 71 (void) pthread_join(smb_nbds_thr, 0); 72 73 nb_status.state = NETBIOS_SHUT_DOWN; 74 } 75 76 int 77 smb_netbios_start(void) 78 { 79 int rc; 80 mutex_t *mp; 81 cond_t *cvp; 82 83 /* Startup Netbios named; port 137 */ 84 rc = pthread_create(&smb_nbns_thr, 0, 85 smb_netbios_name_service_daemon, 0); 86 if (rc) 87 return (-1); 88 89 mp = &nb_status.mtx; 90 cvp = &nb_status.cv; 91 92 (void) mutex_lock(mp); 93 while (!(nb_status.state & (NETBIOS_NAME_SVC_RUNNING | 94 NETBIOS_NAME_SVC_FAILED))) { 95 (void) cond_wait(cvp, mp); 96 } 97 98 if (nb_status.state & NETBIOS_NAME_SVC_FAILED) { 99 (void) mutex_unlock(mp); 100 smb_netbios_shutdown(); 101 return (-1); 102 } 103 (void) mutex_unlock(mp); 104 105 smb_netbios_name_config(); 106 107 /* Startup Netbios datagram service; port 138 */ 108 rc = pthread_create(&smb_nbds_thr, 0, 109 smb_netbios_datagram_service_daemon, 0); 110 if (rc != 0) { 111 smb_netbios_shutdown(); 112 return (-1); 113 } 114 115 (void) mutex_lock(mp); 116 while (!(nb_status.state & (NETBIOS_DATAGRAM_SVC_RUNNING | 117 NETBIOS_DATAGRAM_SVC_FAILED))) { 118 (void) cond_wait(cvp, mp); 119 } 120 121 if (nb_status.state & NETBIOS_DATAGRAM_SVC_FAILED) { 122 (void) mutex_unlock(mp); 123 smb_netbios_shutdown(); 124 return (-1); 125 } 126 (void) mutex_unlock(mp); 127 128 /* Startup Netbios browser service */ 129 rc = pthread_create(&smb_nbbs_thr, 0, smb_browser_daemon, 0); 130 if (rc) { 131 smb_netbios_shutdown(); 132 return (-1); 133 } 134 135 /* Startup Our internal, 1 second resolution, timer */ 136 rc = pthread_create(&smb_nbts_thr, 0, smb_netbios_timer, 0); 137 if (rc != 0) { 138 smb_netbios_shutdown(); 139 return (-1); 140 } 141 142 (void) mutex_lock(mp); 143 while (!(nb_status.state & (NETBIOS_TIMER_RUNNING | 144 NETBIOS_TIMER_FAILED))) { 145 (void) cond_wait(cvp, mp); 146 } 147 148 if (nb_status.state & NETBIOS_TIMER_FAILED) { 149 (void) mutex_unlock(mp); 150 smb_netbios_shutdown(); 151 return (-1); 152 } 153 (void) mutex_unlock(mp); 154 155 return (0); 156 } 157 158 /*ARGSUSED*/ 159 static void * 160 smb_netbios_timer(void *arg) 161 { 162 static unsigned int ticks; 163 164 smb_netbios_chg_status(NETBIOS_TIMER_RUNNING, 1); 165 166 while ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) { 167 (void) sleep(1); 168 169 if (nb_status.state & NETBIOS_DATAGRAM_SVC_RUNNING) 170 smb_netbios_datagram_tick(); 171 else 172 break; 173 174 if (nb_status.state & NETBIOS_NAME_SVC_RUNNING) { 175 smb_netbios_name_tick(); 176 177 /* every 10 minutes */ 178 if ((ticks % 600) == 0) 179 smb_netbios_cache_clean(); 180 } 181 else 182 break; 183 } 184 185 nb_status.state &= ~NETBIOS_TIMER_RUNNING; 186 if ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) { 187 /* either name or datagram service has failed */ 188 smb_netbios_shutdown(); 189 } 190 191 return (0); 192 } 193 194 int 195 smb_first_level_name_encode(struct name_entry *name, 196 unsigned char *out, int max_out) 197 { 198 return (netbios_first_level_name_encode(name->name, name->scope, 199 out, max_out)); 200 } 201 202 int 203 smb_first_level_name_decode(unsigned char *in, struct name_entry *name) 204 { 205 return (netbios_first_level_name_decode((char *)in, (char *)name->name, 206 (char *)name->scope)); 207 } 208 209 /* 210 * smb_encode_netbios_name 211 * 212 * Set up the name and scope fields in the destination name_entry structure. 213 * The name is padded with spaces to 15 bytes. The suffix is copied into the 214 * last byte, i.e. "netbiosname <suffix>". The scope is copied and folded 215 * to uppercase. 216 */ 217 void 218 smb_encode_netbios_name(unsigned char *name, char suffix, unsigned char *scope, 219 struct name_entry *dest) 220 { 221 char tmp_name[NETBIOS_NAME_SZ]; 222 mts_wchar_t wtmp_name[NETBIOS_NAME_SZ]; 223 unsigned int cpid; 224 int len; 225 size_t rc; 226 227 len = 0; 228 rc = mts_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ); 229 230 if (rc != (size_t)-1) { 231 wtmp_name[NETBIOS_NAME_SZ - 1] = 0; 232 cpid = oem_get_smb_cpid(); 233 rc = unicodestooems(tmp_name, wtmp_name, NETBIOS_NAME_SZ, cpid); 234 if (rc > 0) 235 len = strlen(tmp_name); 236 } 237 238 (void) memset(dest->name, ' ', NETBIOS_NAME_SZ - 1); 239 if (len) { 240 (void) utf8_strupr(tmp_name); 241 (void) memcpy(dest->name, tmp_name, len); 242 } 243 dest->name[NETBIOS_NAME_SZ - 1] = suffix; 244 245 if (scope == NULL) { 246 (void) smb_config_getstr(SMB_CI_NBSCOPE, (char *)dest->scope, 247 NETBIOS_DOMAIN_NAME_MAX); 248 } else { 249 (void) strlcpy((char *)dest->scope, (const char *)scope, 250 NETBIOS_DOMAIN_NAME_MAX); 251 } 252 (void) utf8_strupr((char *)dest->scope); 253 } 254 255 void 256 smb_init_name_struct(unsigned char *name, char suffix, unsigned char *scope, 257 uint32_t ipaddr, unsigned short port, uint32_t attr, 258 uint32_t addr_attr, struct name_entry *dest) 259 { 260 bzero(dest, sizeof (struct name_entry)); 261 smb_encode_netbios_name(name, suffix, scope, dest); 262 263 switch (smb_node_type) { 264 case 'H': 265 dest->attributes = attr | NAME_ATTR_OWNER_TYPE_HNODE; 266 break; 267 case 'M': 268 dest->attributes = attr | NAME_ATTR_OWNER_TYPE_MNODE; 269 break; 270 case 'P': 271 dest->attributes = attr | NAME_ATTR_OWNER_TYPE_PNODE; 272 break; 273 case 'B': 274 default: 275 dest->attributes = attr | NAME_ATTR_OWNER_TYPE_BNODE; 276 break; 277 } 278 279 dest->addr_list.refresh_ttl = dest->addr_list.ttl = 280 TO_SECONDS(DEFAULT_TTL); 281 282 dest->addr_list.sin.sin_family = AF_INET; 283 dest->addr_list.sinlen = sizeof (dest->addr_list.sin); 284 dest->addr_list.sin.sin_addr.s_addr = ipaddr; 285 dest->addr_list.sin.sin_port = port; 286 dest->addr_list.attributes = addr_attr; 287 dest->addr_list.forw = dest->addr_list.back = &dest->addr_list; 288 } 289