1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
227f667e74Sjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw /*
27da6c28aaSamw  * Description:
28da6c28aaSamw  *
29da6c28aaSamw  *	Contains base code for netbios datagram service.
30da6c28aaSamw  *
31da6c28aaSamw  * Relavent sections from RFC1002:
32da6c28aaSamw  *
33da6c28aaSamw  *  5.3.  NetBIOS DATAGRAM SERVICE PROTOCOLS
34da6c28aaSamw  *
35da6c28aaSamw  *   The following are GLOBAL variables and should be NetBIOS user
36da6c28aaSamw  *   configurable:
37da6c28aaSamw  *
38da6c28aaSamw  *   - SCOPE_ID: the non-leaf section of the domain name preceded by a
39da6c28aaSamw  *     '.'  which represents the domain of the NetBIOS scope for the
40da6c28aaSamw  *     NetBIOS name.  The following protocol description only supports
41da6c28aaSamw  *     single scope operation.
42da6c28aaSamw  *
43da6c28aaSamw  *   - MAX_DATAGRAM_LENGTH: the maximum length of an IP datagram.  The
44da6c28aaSamw  *     minimal maximum length defined in for IP is 576 bytes.  This
45da6c28aaSamw  *     value is used when determining whether to fragment a NetBIOS
46da6c28aaSamw  *     datagram.  Implementations are expected to be capable of
47da6c28aaSamw  *     receiving unfragmented NetBIOS datagrams up to their maximum
48da6c28aaSamw  *     size.
49da6c28aaSamw  *
50da6c28aaSamw  *   - BROADCAST_ADDRESS: the IP address B-nodes use to send datagrams
51da6c28aaSamw  *     with group name destinations and broadcast datagrams.  The
52da6c28aaSamw  *     default is the IP broadcast address for a single IP network.
53da6c28aaSamw  *
54da6c28aaSamw  *
55da6c28aaSamw  *   The following are Defined Constants for the NetBIOS Datagram
56da6c28aaSamw  *   Service:
57da6c28aaSamw  *
58*a0aa776eSAlan Wright  *   - IPPORT_NETBIOS_DGM: the globally well-known UDP port allocated
59da6c28aaSamw  *     where the NetBIOS Datagram Service receives UDP packets.  See
60da6c28aaSamw  *     section 6, "Defined Constants", for its value.
61da6c28aaSamw  */
62da6c28aaSamw 
63da6c28aaSamw /*
64da6c28aaSamw  *
65da6c28aaSamw  *  6.  DEFINED CONSTANTS AND VARIABLES
66da6c28aaSamw  *
67da6c28aaSamw  *   GENERAL:
68da6c28aaSamw  *
69da6c28aaSamw  *      SCOPE_ID                   The name of the NetBIOS scope.
70da6c28aaSamw  *
71da6c28aaSamw  *                                 This is expressed as a character
72da6c28aaSamw  *                                 string meeting the requirements of
73da6c28aaSamw  *                                 the domain name system and without
74da6c28aaSamw  *                                 a leading or trailing "dot".
75da6c28aaSamw  *
76da6c28aaSamw  *                                 An implementation may elect to make
77da6c28aaSamw  *                                 this a single global value for the
78da6c28aaSamw  *                                 node or allow it to be specified
79da6c28aaSamw  *                                 with each separate NetBIOS name
80da6c28aaSamw  *                                 (thus permitting cross-scope
81da6c28aaSamw  *                                 references.)
82da6c28aaSamw  *
83da6c28aaSamw  *      BROADCAST_ADDRESS          An IP address composed of the
84da6c28aaSamw  *                                 node network and subnetwork
85da6c28aaSamw  *                                 numbers with all remaining bits set
86da6c28aaSamw  *                                 to one.
87da6c28aaSamw  *
88da6c28aaSamw  *                                 I.e. "Specific subnet" broadcast
89da6c28aaSamw  *                                 addressing according to section 2.3
90da6c28aaSamw  *                                 of RFC 950.
91da6c28aaSamw  *
92da6c28aaSamw  *      BCAST_REQ_RETRY_TIMEOUT    250 milliseconds.
93da6c28aaSamw  *                                 An adaptive timer may be used.
94da6c28aaSamw  *
95da6c28aaSamw  *      BCAST_REQ_RETRY_COUNT      3
96da6c28aaSamw  *
97da6c28aaSamw  *      UCAST_REQ_RETRY_TIMEOUT    5 seconds
98da6c28aaSamw  *                                 An adaptive timer may be used.
99da6c28aaSamw  *
100da6c28aaSamw  *      UCAST_REQ_RETRY_COUNT      3
101da6c28aaSamw  *
102da6c28aaSamw  *      MAX_DATAGRAM_LENGTH        576 bytes (default)
103da6c28aaSamw  *
104da6c28aaSamw  *   DATAGRAM SERVICE:
105da6c28aaSamw  *
106*a0aa776eSAlan Wright  *      IPPORT_NETBIOS_DGM          138 (decimal)
107da6c28aaSamw  *
108da6c28aaSamw  *      FRAGMENT_TO                2 seconds (default)
109da6c28aaSamw  */
110da6c28aaSamw 
111*a0aa776eSAlan Wright #include <errno.h>
112da6c28aaSamw #include <stdlib.h>
113da6c28aaSamw #include <unistd.h>
114da6c28aaSamw #include <string.h>
115da6c28aaSamw #include <strings.h>
116da6c28aaSamw #include <syslog.h>
117da6c28aaSamw #include <synch.h>
118da6c28aaSamw #include <sys/socket.h>
119da6c28aaSamw #include <arpa/inet.h>
120da6c28aaSamw 
121da6c28aaSamw #include <smbns_netbios.h>
122da6c28aaSamw 
123da6c28aaSamw #include <smbsrv/libsmbns.h>
124da6c28aaSamw 
125da6c28aaSamw static int datagram_sock = -1;
126da6c28aaSamw static short datagram_id = 1;
127da6c28aaSamw static struct datagram_queue smb_datagram_queue;
128da6c28aaSamw static mutex_t smb_dgq_mtx;
129da6c28aaSamw 
1308b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States static void smb_netbios_datagram_error(unsigned char *buf);
1318b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
132da6c28aaSamw /*
133da6c28aaSamw  * Function:  smb_netbios_datagram_tick(void)
134da6c28aaSamw  *
135da6c28aaSamw  * Description:
136da6c28aaSamw  *
137da6c28aaSamw  *	Called once a second to handle time to live timeouts in
138da6c28aaSamw  *	datagram assembly queue.
139da6c28aaSamw  *
140da6c28aaSamw  * Inputs:
141da6c28aaSamw  *
142da6c28aaSamw  * Returns:
143da6c28aaSamw  *	void	-> Nothing at all...
144da6c28aaSamw  */
145da6c28aaSamw 
146da6c28aaSamw void
smb_netbios_datagram_tick(void)147da6c28aaSamw smb_netbios_datagram_tick(void)
148da6c28aaSamw {
149da6c28aaSamw 	struct datagram *entry;
150da6c28aaSamw 	struct datagram *next;
151da6c28aaSamw 
152da6c28aaSamw 	(void) mutex_lock(&smb_dgq_mtx);
153da6c28aaSamw 
154da6c28aaSamw 	for (entry = smb_datagram_queue.forw;
155da6c28aaSamw 	    entry != (struct datagram *)((uintptr_t)&smb_datagram_queue);
156da6c28aaSamw 	    entry = next) {
157da6c28aaSamw 		next = entry->forw;
158da6c28aaSamw 		if (--entry->discard_timer == 0) {
159da6c28aaSamw 			/* Toss it */
160da6c28aaSamw 			QUEUE_CLIP(entry);
161da6c28aaSamw 			free(entry);
162da6c28aaSamw 		}
163da6c28aaSamw 	}
164da6c28aaSamw 	(void) mutex_unlock(&smb_dgq_mtx);
165da6c28aaSamw }
166da6c28aaSamw 
167da6c28aaSamw void
smb_netbios_datagram_fini()168da6c28aaSamw smb_netbios_datagram_fini()
169da6c28aaSamw {
170da6c28aaSamw 	struct datagram *entry;
171da6c28aaSamw 
172da6c28aaSamw 	(void) mutex_lock(&smb_dgq_mtx);
173da6c28aaSamw 	while ((entry = smb_datagram_queue.forw) !=
174da6c28aaSamw 	    (struct datagram *)((uintptr_t)&smb_datagram_queue)) {
175da6c28aaSamw 		QUEUE_CLIP(entry);
176da6c28aaSamw 		free(entry);
177da6c28aaSamw 	}
178da6c28aaSamw 	(void) mutex_unlock(&smb_dgq_mtx);
179da6c28aaSamw }
180da6c28aaSamw 
181da6c28aaSamw /*
182da6c28aaSamw  * Function: int smb_netbios_send_Bnode_datagram(unsigned char *data,
183da6c28aaSamw  *		struct name_entry *source, struct name_entry *destination,
184da6c28aaSamw  *		uint32_t broadcast)
185da6c28aaSamw  *
186da6c28aaSamw  * Description from rfc1002:
187da6c28aaSamw  *
188da6c28aaSamw  *  5.3.1.  B NODE TRANSMISSION OF NetBIOS DATAGRAMS
189da6c28aaSamw  *
190da6c28aaSamw  *   PROCEDURE send_datagram(data, source, destination, broadcast)
191da6c28aaSamw  *
192da6c28aaSamw  *   (*
193da6c28aaSamw  *    * user initiated processing on B node
194da6c28aaSamw  *    *)
195da6c28aaSamw  *
196da6c28aaSamw  *   BEGIN
197da6c28aaSamw  *        group = FALSE;
198da6c28aaSamw  *
199da6c28aaSamw  *        do name discovery on destination name, returns name type and
200da6c28aaSamw  *             IP address;
201da6c28aaSamw  *
202da6c28aaSamw  *        IF name type is group name THEN
203da6c28aaSamw  *        BEGIN
204da6c28aaSamw  *             group = TRUE;
205da6c28aaSamw  *        END
206da6c28aaSamw  *
207da6c28aaSamw  *        (*
208da6c28aaSamw  *         * build datagram service UDP packet;
209da6c28aaSamw  *         *)
210da6c28aaSamw  *        convert source and destination NetBIOS names into
211da6c28aaSamw  *             half-ASCII, biased encoded name;
212da6c28aaSamw  *        SOURCE_NAME = cat(source, SCOPE_ID);
213da6c28aaSamw  *        SOURCE_IP = this nodes IP address;
214*a0aa776eSAlan Wright  *        SOURCE_PORT =  IPPORT_NETBIOS_DGM;
215da6c28aaSamw  *
216da6c28aaSamw  *        IF NetBIOS broadcast THEN
217da6c28aaSamw  *        BEGIN
218da6c28aaSamw  *             DESTINATION_NAME = cat("*", SCOPE_ID)
219da6c28aaSamw  *        END
220da6c28aaSamw  *        ELSE
221da6c28aaSamw  *        BEGIN
222da6c28aaSamw  *             DESTINATION_NAME = cat(destination, SCOPE_ID)
223da6c28aaSamw  *        END
224da6c28aaSamw  *
225da6c28aaSamw  *        MSG_TYPE = select_one_from_set
226da6c28aaSamw  *             {BROADCAST, DIRECT_UNIQUE, DIRECT_GROUP}
227da6c28aaSamw  *        DGM_ID = next transaction id for Datagrams;
228da6c28aaSamw  *        DGM_LENGTH = length of data + length of second level encoded
229da6c28aaSamw  *             source and destination names;
230da6c28aaSamw  *
231da6c28aaSamw  *        IF (length of the NetBIOS Datagram, including UDP and
232da6c28aaSamw  *            IP headers, > MAX_DATAGRAM_LENGTH) THEN
233da6c28aaSamw  *        BEGIN
234da6c28aaSamw  *             (*
235da6c28aaSamw  *              * fragment NetBIOS datagram into 2 UDP packets
236da6c28aaSamw  *              *)
237da6c28aaSamw  *             Put names into 1st UDP packet and any data that fits
238da6c28aaSamw  *                  after names;
239da6c28aaSamw  *             Set MORE and FIRST bits in 1st UDP packets FLAGS;
240da6c28aaSamw  *             OFFSET in 1st UDP = 0;
241da6c28aaSamw  *
242da6c28aaSamw  *             Replicate NetBIOS Datagram header from 1st UDP packet
243da6c28aaSamw  *                  into 2nd UDP packet;
244da6c28aaSamw  *             Put rest of data in 2nd UDP packet;
245da6c28aaSamw  *             Clear MORE and FIRST bits in 2nd UDP packets FLAGS;
246da6c28aaSamw  *             OFFSET in 2nd UDP = DGM_LENGTH - number of name and
247da6c28aaSamw  *                  data bytes in 1st UDP;
248da6c28aaSamw  *        END
249da6c28aaSamw  *        BEGIN
250da6c28aaSamw  *             (*
251da6c28aaSamw  *              * Only need one UDP packet
252da6c28aaSamw  *              *)
253da6c28aaSamw  *             USER_DATA = data;
254da6c28aaSamw  *             Clear MORE bit and set FIRST bit in FLAGS;
255da6c28aaSamw  *             OFFSET = 0;
256da6c28aaSamw  *        END
257da6c28aaSamw  *
258da6c28aaSamw  *        IF (group == TRUE) OR (NetBIOS broadcast) THEN
259da6c28aaSamw  *        BEGIN
260da6c28aaSamw  *             send UDP packet(s) to BROADCAST_ADDRESS;
261da6c28aaSamw  *        END
262da6c28aaSamw  *        ELSE
263da6c28aaSamw  *        BEGIN
264da6c28aaSamw  *             send UDP packet(s) to IP address returned by name
265da6c28aaSamw  *                discovery;
266da6c28aaSamw  *        END
267da6c28aaSamw  *   END (* procedure *)
268da6c28aaSamw  *                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
269da6c28aaSamw  *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
270da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
271da6c28aaSamw  *   |   MSG_TYPE    |     FLAGS     |           DGM_ID              |
272da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
273da6c28aaSamw  *   |                           SOURCE_IP                           |
274da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
275da6c28aaSamw  *   |          SOURCE_PORT          |          DGM_LENGTH           |
276da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
277da6c28aaSamw  *   |         PACKET_OFFSET         |
278da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
279da6c28aaSamw  *
280da6c28aaSamw  *   MSG_TYPE values (in hexidecimal):
281da6c28aaSamw  *
282da6c28aaSamw  *           10 -  DIRECT_UNIQUE DATAGRAM
283da6c28aaSamw  *           11 -  DIRECT_GROUP DATAGRAM
284da6c28aaSamw  *           12 -  BROADCAST DATAGRAM
285da6c28aaSamw  *           13 -  DATAGRAM ERROR
286da6c28aaSamw  *           14 -  DATAGRAM QUERY REQUEST
287da6c28aaSamw  *           15 -  DATAGRAM POSITIVE QUERY RESPONSE
288da6c28aaSamw  *           16 -  DATAGRAM NEGATIVE QUERY RESPONSE
289da6c28aaSamw  *
290da6c28aaSamw  *   Bit definitions of the FLAGS field:
291da6c28aaSamw  *
292da6c28aaSamw  *     0   1   2   3   4   5   6   7
293da6c28aaSamw  *   +---+---+---+---+---+---+---+---+
294da6c28aaSamw  *   | 0 | 0 | 0 | 0 |  SNT  | F | M |
295da6c28aaSamw  *   +---+---+---+---+---+---+---+---+
296da6c28aaSamw  *
297da6c28aaSamw  *   Symbol     Bit(s)   Description
298da6c28aaSamw  *
299da6c28aaSamw  *   M               7   MORE flag, If set then more NetBIOS datagram
300da6c28aaSamw  *                       fragments follow.
301da6c28aaSamw  *
302da6c28aaSamw  *   F               6   FIRST packet flag,  If set then this is first
303da6c28aaSamw  *                       (and possibly only) fragment of NetBIOS
304da6c28aaSamw  *                       datagram
305da6c28aaSamw  *
306da6c28aaSamw  *   SNT           4,5   Source End-Node type:
307da6c28aaSamw  *                          00 = B node
308da6c28aaSamw  *                          01 = P node
309da6c28aaSamw  *                          10 = M node
310da6c28aaSamw  *                          11 = NBDD
311da6c28aaSamw  *   RESERVED      0-3   Reserved, must be zero (0)
312da6c28aaSamw  *      (But MS sets bit 3 in this field)
313da6c28aaSamw  *
314da6c28aaSamw  */
315da6c28aaSamw 
316da6c28aaSamw int
smb_netbios_datagram_send(struct name_entry * src,struct name_entry * dest,unsigned char * data,int length)317da6c28aaSamw smb_netbios_datagram_send(struct name_entry *src, struct name_entry *dest,
318da6c28aaSamw     unsigned char *data, int length)
319da6c28aaSamw {
3207f667e74Sjose borrego 	smb_inaddr_t ipaddr;
321da6c28aaSamw 	size_t count, srclen, destlen, sinlen;
322*a0aa776eSAlan Wright 	addr_entry_t *addr;
323da6c28aaSamw 	struct sockaddr_in sin;
324da6c28aaSamw 	char *buffer;
325da6c28aaSamw 	char ha_source[NETBIOS_DOMAIN_NAME_MAX];
326da6c28aaSamw 	char ha_dest[NETBIOS_DOMAIN_NAME_MAX];
327da6c28aaSamw 
328da6c28aaSamw 	(void) smb_first_level_name_encode(src, (unsigned char *)ha_source,
329da6c28aaSamw 	    sizeof (ha_source));
330da6c28aaSamw 	srclen = strlen(ha_source) + 1;
331da6c28aaSamw 
332da6c28aaSamw 	(void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest,
333da6c28aaSamw 	    sizeof (ha_dest));
334da6c28aaSamw 	destlen = strlen(ha_dest) + 1;
335da6c28aaSamw 
336da6c28aaSamw 	/* give some extra room */
337*a0aa776eSAlan Wright 	if ((buffer = malloc(MAX_DATAGRAM_LENGTH * 4)) == NULL) {
338*a0aa776eSAlan Wright 		syslog(LOG_ERR, "nbt datagram: send: %m");
339da6c28aaSamw 		return (-1);
340da6c28aaSamw 	}
341da6c28aaSamw 
342da6c28aaSamw 	buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE;
343da6c28aaSamw 	switch (smb_node_type) {
344da6c28aaSamw 	case 'B':
345da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST;
346da6c28aaSamw 		break;
347da6c28aaSamw 	case 'P':
348da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST;
349da6c28aaSamw 		break;
350da6c28aaSamw 	case 'M':
351da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST;
352da6c28aaSamw 		break;
353da6c28aaSamw 	case 'H':
354da6c28aaSamw 	default:
355da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST;
356da6c28aaSamw 		break;
357da6c28aaSamw 	}
358da6c28aaSamw 
359da6c28aaSamw 	datagram_id++;
360da6c28aaSamw 	BE_OUT16(&buffer[2], datagram_id);
361da6c28aaSamw 	(void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr,
362da6c28aaSamw 	    sizeof (uint32_t));
363da6c28aaSamw 	(void) memcpy(&buffer[8], &src->addr_list.sin.sin_port,
364da6c28aaSamw 	    sizeof (uint16_t));
365da6c28aaSamw 	BE_OUT16(&buffer[10], length + srclen + destlen);
366da6c28aaSamw 	BE_OUT16(&buffer[12], 0);
367da6c28aaSamw 
368da6c28aaSamw 	bcopy(ha_source, &buffer[14], srclen);
369da6c28aaSamw 	bcopy(ha_dest, &buffer[14 + srclen], destlen);
370da6c28aaSamw 	bcopy(data, &buffer[14 + srclen + destlen], length);
371da6c28aaSamw 	count = &buffer[14 + srclen + destlen + length] - buffer;
372da6c28aaSamw 
373da6c28aaSamw 	bzero(&sin, sizeof (sin));
374da6c28aaSamw 	sin.sin_family = AF_INET;
375da6c28aaSamw 	sinlen = sizeof (sin);
376da6c28aaSamw 	addr = &dest->addr_list;
377da6c28aaSamw 	do {
3787f667e74Sjose borrego 		ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
3797f667e74Sjose borrego 		ipaddr.a_family = AF_INET;
380da6c28aaSamw 		/* Don't send anything to myself... */
381fc724630SAlan Wright 		if (smb_nic_is_local(&ipaddr))
382da6c28aaSamw 			goto next;
383da6c28aaSamw 
3847f667e74Sjose borrego 		sin.sin_addr.s_addr = ipaddr.a_ipv4;
385da6c28aaSamw 		sin.sin_port = addr->sin.sin_port;
386da6c28aaSamw 		(void) sendto(datagram_sock, buffer, count, 0,
387da6c28aaSamw 		    (struct sockaddr *)&sin, sinlen);
388da6c28aaSamw 
389da6c28aaSamw next:		addr = addr->forw;
390da6c28aaSamw 	} while (addr != &dest->addr_list);
391da6c28aaSamw 	free(buffer);
392da6c28aaSamw 	return (0);
393da6c28aaSamw }
394da6c28aaSamw 
395da6c28aaSamw 
396da6c28aaSamw int
smb_netbios_datagram_send_to_net(struct name_entry * src,struct name_entry * dest,char * data,int length)397da6c28aaSamw smb_netbios_datagram_send_to_net(struct name_entry *src,
398da6c28aaSamw     struct name_entry *dest, char *data, int length)
399da6c28aaSamw {
4007f667e74Sjose borrego 	smb_inaddr_t ipaddr;
401da6c28aaSamw 	size_t count, srclen, destlen, sinlen;
402*a0aa776eSAlan Wright 	addr_entry_t *addr;
403da6c28aaSamw 	struct sockaddr_in sin;
404da6c28aaSamw 	char *buffer;
405da6c28aaSamw 	char ha_source[NETBIOS_DOMAIN_NAME_MAX];
406da6c28aaSamw 	char ha_dest[NETBIOS_DOMAIN_NAME_MAX];
407da6c28aaSamw 
408da6c28aaSamw 	(void) smb_first_level_name_encode(src, (unsigned char *)ha_source,
409da6c28aaSamw 	    sizeof (ha_source));
410da6c28aaSamw 	srclen = strlen(ha_source) + 1;
411da6c28aaSamw 
412da6c28aaSamw 	(void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest,
413da6c28aaSamw 	    sizeof (ha_dest));
414da6c28aaSamw 	destlen = strlen(ha_dest) + 1;
415da6c28aaSamw 
416da6c28aaSamw 	/* give some extra room */
417*a0aa776eSAlan Wright 	if ((buffer = malloc(MAX_DATAGRAM_LENGTH * 4)) == NULL) {
418*a0aa776eSAlan Wright 		syslog(LOG_ERR, "nbt datagram: send_to_net: %m");
419da6c28aaSamw 		return (-1);
420da6c28aaSamw 	}
421da6c28aaSamw 
422da6c28aaSamw 	buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE;
423da6c28aaSamw 	switch (smb_node_type) {
424da6c28aaSamw 	case 'B':
425da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST;
426da6c28aaSamw 		break;
427da6c28aaSamw 	case 'P':
428da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST;
429da6c28aaSamw 		break;
430da6c28aaSamw 	case 'M':
431da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST;
432da6c28aaSamw 		break;
433da6c28aaSamw 	case 'H':
434da6c28aaSamw 	default:
435da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST;
436da6c28aaSamw 		break;
437da6c28aaSamw 	}
438da6c28aaSamw 
439da6c28aaSamw 	datagram_id++;
440da6c28aaSamw 	BE_OUT16(&buffer[2], datagram_id);
441da6c28aaSamw 	(void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr,
442da6c28aaSamw 	    sizeof (uint32_t));
443da6c28aaSamw 	(void) memcpy(&buffer[8], &src->addr_list.sin.sin_port,
444da6c28aaSamw 	    sizeof (uint16_t));
445da6c28aaSamw 	BE_OUT16(&buffer[10], length + srclen + destlen);
446da6c28aaSamw 	BE_OUT16(&buffer[12], 0);
447da6c28aaSamw 
448da6c28aaSamw 	bcopy(ha_source, &buffer[14], srclen);
449da6c28aaSamw 	bcopy(ha_dest, &buffer[14 + srclen], destlen);
450da6c28aaSamw 	bcopy(data, &buffer[14 + srclen + destlen], length);
451da6c28aaSamw 	count = &buffer[14 + srclen + destlen + length] - buffer;
452da6c28aaSamw 
453da6c28aaSamw 	bzero(&sin, sizeof (sin));
454da6c28aaSamw 	sin.sin_family = AF_INET;
455da6c28aaSamw 	sinlen = sizeof (sin);
456da6c28aaSamw 	addr = &dest->addr_list;
457da6c28aaSamw 	do {
4587f667e74Sjose borrego 		ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
4597f667e74Sjose borrego 		ipaddr.a_family = AF_INET;
460fc724630SAlan Wright 		if (smb_nic_is_local(&ipaddr))
461da6c28aaSamw 			goto next;
4627b59d02dSjb 
4637f667e74Sjose borrego 		sin.sin_addr.s_addr = ipaddr.a_ipv4;
464da6c28aaSamw 		sin.sin_port = addr->sin.sin_port;
465da6c28aaSamw 		(void) sendto(datagram_sock, buffer, count, 0,
466da6c28aaSamw 		    (struct sockaddr *)&sin, sinlen);
467da6c28aaSamw 
468da6c28aaSamw next:		addr = addr->forw;
469da6c28aaSamw 	} while (addr != &dest->addr_list);
470da6c28aaSamw 	free(buffer);
471da6c28aaSamw 	return (0);
472da6c28aaSamw }
473da6c28aaSamw 
474da6c28aaSamw 
475da6c28aaSamw int
smb_datagram_decode(struct datagram * datagram,int bytes)476da6c28aaSamw smb_datagram_decode(struct datagram *datagram, int bytes)
477da6c28aaSamw {
478da6c28aaSamw 	unsigned char *ha_src;
479da6c28aaSamw 	unsigned char *ha_dest;
480da6c28aaSamw 	unsigned char *data;
481da6c28aaSamw 
4828b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (bytes == DATAGRAM_ERR_HEADER_LENGTH) {
4838b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (datagram->rawbuf[0] == DATAGRAM_TYPE_ERROR_DATAGRAM)
4848b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_netbios_datagram_error(datagram->rawbuf);
485da6c28aaSamw 		return (-1);
486da6c28aaSamw 
487da6c28aaSamw 	}
488da6c28aaSamw 
4898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (bytes >= DATAGRAM_HEADER_LENGTH) {
4908b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		ha_src = &datagram->rawbuf[DATAGRAM_HEADER_LENGTH];
4918b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		ha_dest = ha_src + strlen((char *)ha_src) + 1;
4928b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		data = ha_dest + strlen((char *)ha_dest) + 1;
4938b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
4948b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		bzero(&datagram->src, sizeof (struct name_entry));
4958b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		bzero(&datagram->dest, sizeof (struct name_entry));
4968b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
4978b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		datagram->rawbytes = bytes;
4988b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		datagram->packet_type = datagram->rawbuf[0];
4998b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		datagram->flags = datagram->rawbuf[1];
5008b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		datagram->datagram_id = BE_IN16(&datagram->rawbuf[2]);
5018b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
5028b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		datagram->src.addr_list.sinlen = sizeof (struct sockaddr_in);
5038b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		(void) memcpy(&datagram->src.addr_list.sin.sin_addr.s_addr,
5048b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    &datagram->rawbuf[4], sizeof (uint32_t));
5058b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		(void) memcpy(&datagram->src.addr_list.sin.sin_port,
5068b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    &datagram->rawbuf[8], sizeof (uint16_t));
5078b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		datagram->src.addr_list.forw = datagram->src.addr_list.back =
5088b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    &datagram->src.addr_list;
5098b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
5108b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		datagram->data = data;
5118b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		datagram->data_length = BE_IN16(&datagram->rawbuf[10]);
5128b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		datagram->offset = BE_IN16(&datagram->rawbuf[12]);
5138b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
5148b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (smb_first_level_name_decode(ha_src, &datagram->src) < 0) {
5158b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_tracef("NbtDatagram[%s]: invalid calling name",
5168b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			    inet_ntoa(datagram->src.addr_list.sin.sin_addr));
5178b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_tracef("Calling name: <%02X>%32.32s",
5188b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			    ha_src[0], &ha_src[1]);
5198b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		}
5208b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
5218b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		datagram->dest.addr_list.forw = datagram->dest.addr_list.back =
5228b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    &datagram->dest.addr_list;
5238b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
5248b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (smb_first_level_name_decode(ha_dest, &datagram->dest) < 0) {
5258b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_tracef("NbtDatagram[%s]: invalid called name",
5268b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			    inet_ntoa(datagram->src.addr_list.sin.sin_addr));
5278b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_tracef("Called name: <%02X>%32.32s", ha_dest[0],
5288b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			    &ha_dest[1]);
5298b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		}
530da6c28aaSamw 
5318b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (0);
532da6c28aaSamw 	}
533da6c28aaSamw 
5348b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	/* ignore other malformed datagram packets */
5358b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	return (-1);
5368b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
5378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
5388b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /*
5398b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * 4.4.3. Datagram Error Packet
5408b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  */
5418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States static void
smb_netbios_datagram_error(unsigned char * buf)5428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_netbios_datagram_error(unsigned char *buf)
5438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States {
5448b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	int error;
5458b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	int datagram_id;
5468b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
5478b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (buf[0] != DATAGRAM_TYPE_ERROR_DATAGRAM)
5488b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		return;
5498b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
5508b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	datagram_id = BE_IN16(&buf[2]);
5518b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	error = buf[DATAGRAM_ERR_HEADER_LENGTH - 1];
5528b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	switch (error) {
5538b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	case DATAGRAM_INVALID_SOURCE_NAME_FORMAT:
5548b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_tracef("NbtDatagramError[%d]: invalid source name format",
5558b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    datagram_id);
5568b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		break;
5578b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
5588b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	case DATAGRAM_INVALID_DESTINATION_NAME_FORMAT:
5598b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_tracef("NbtDatagramError[%d]: invalid destination name "
5608b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		    "format", datagram_id);
5618b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		break;
5628b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
5638b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	case DATAGRAM_DESTINATION_NAME_NOT_PRESENT:
5648b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	default:
5658b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		break;
5668b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
567da6c28aaSamw }
568da6c28aaSamw 
569da6c28aaSamw 
570da6c28aaSamw /*
571da6c28aaSamw  * Function: int smb_netbios_process_BPM_datagram(unsigned char *packet,
572*a0aa776eSAlan Wright  *		addr_entry_t *addr)
573da6c28aaSamw  *
574da6c28aaSamw  * Description from rfc1002:
575da6c28aaSamw  *
576da6c28aaSamw  *  5.3.3.  RECEPTION OF NetBIOS DATAGRAMS BY ALL NODES
577da6c28aaSamw  *
578da6c28aaSamw  *   The following algorithm discards out of order NetBIOS Datagram
579da6c28aaSamw  *   fragments.  An implementation which reassembles out of order
580da6c28aaSamw  *   NetBIOS Datagram fragments conforms to this specification.  The
581da6c28aaSamw  *   fragment discard timer is initialized to the value FRAGMENT_TIMEOUT.
582da6c28aaSamw  *   This value should be user configurable.  The default value is
583da6c28aaSamw  *   given in Section 6, "Defined Constants and Variables".
584da6c28aaSamw  *
585da6c28aaSamw  *   PROCEDURE datagram_packet(packet)
586da6c28aaSamw  *
587da6c28aaSamw  *   (*
588da6c28aaSamw  *    * processing initiated by datagram packet reception
589da6c28aaSamw  *    * on B, P and M nodes
590da6c28aaSamw  *    *)
591da6c28aaSamw  *   BEGIN
592da6c28aaSamw  *        (*
593da6c28aaSamw  *         * if this node is a P node, ignore
594da6c28aaSamw  *         * broadcast packets.
595da6c28aaSamw  *         *)
596da6c28aaSamw  *
597da6c28aaSamw  *        IF this is a P node AND incoming packet is
598da6c28aaSamw  *             a broadcast packet THEN
599da6c28aaSamw  *        BEGIN
600da6c28aaSamw  *             discard packet;
601da6c28aaSamw  *        END
602da6c28aaSamw  *
603da6c28aaSamw  *        CASE packet type OF
604da6c28aaSamw  *
605da6c28aaSamw  *           DATAGRAM SERVICE:
606da6c28aaSamw  *           BEGIN
607da6c28aaSamw  *             IF FIRST bit in FLAGS is set THEN
608da6c28aaSamw  *             BEGIN
609da6c28aaSamw  *                  IF MORE bit in FLAGS is set THEN
610da6c28aaSamw  *                  BEGIN
611da6c28aaSamw  *                       Save 1st UDP packet of the Datagram;
612da6c28aaSamw  *                       Set this Datagrams fragment discard
613da6c28aaSamw  *                         timer to FRAGMENT_TIMEOUT;
614da6c28aaSamw  *                       return;
615da6c28aaSamw  *                  END
616da6c28aaSamw  *                  ELSE
617da6c28aaSamw  *                       Datagram is composed of a single
618da6c28aaSamw  *                         UDP packet;
619da6c28aaSamw  *             END
620da6c28aaSamw  *             ELSE
621da6c28aaSamw  *             BEGIN
622da6c28aaSamw  *                  (* Have the second fragment of a Datagram *)
623da6c28aaSamw  *
624da6c28aaSamw  *                  Search for 1st fragment by source IP address
625da6c28aaSamw  *                     and DGM_ID;
626da6c28aaSamw  *                  IF found 1st fragment THEN
627da6c28aaSamw  *                       Process both UDP packets;
628da6c28aaSamw  *                  ELSE
629da6c28aaSamw  *                  BEGIN
630da6c28aaSamw  *                       discard 2nd fragment UDP packet;
631da6c28aaSamw  *                       return;
632da6c28aaSamw  *                  END
633da6c28aaSamw  *             END
634da6c28aaSamw  *
635da6c28aaSamw  *             IF DESTINATION_NAME is '*' THEN
636da6c28aaSamw  *             BEGIN
637da6c28aaSamw  *                  (* NetBIOS broadcast *)
638da6c28aaSamw  *
639da6c28aaSamw  *                  deliver USER_DATA from UDP packet(s) to all
640da6c28aaSamw  *                       outstanding receive broadcast
641da6c28aaSamw  *                       datagram requests;
642da6c28aaSamw  *                  return;
643da6c28aaSamw  *             END
644da6c28aaSamw  *             ELSE
645da6c28aaSamw  *             BEGIN (* non-broadcast *)
646da6c28aaSamw  *                  (* Datagram for Unique or Group Name *)
647da6c28aaSamw  *
648da6c28aaSamw  *                  IF DESTINATION_NAME is not present in the
649da6c28aaSamw  *                     local name table THEN
650da6c28aaSamw  *                  BEGIN
651da6c28aaSamw  *                       (* destination not present *)
652da6c28aaSamw  *                       build DATAGRAM ERROR packet, clear
653da6c28aaSamw  *                            FIRST and MORE bit, put in
654da6c28aaSamw  *                            this nodes IP and PORT, set
655da6c28aaSamw  *                            ERROR_CODE;
656da6c28aaSamw  *                       send DATAGRAM ERROR packet to
657da6c28aaSamw  *                            source IP address and port
658da6c28aaSamw  *                            of UDP;
659da6c28aaSamw  *                       discard UDP packet(s);
660da6c28aaSamw  *                       return;
661da6c28aaSamw  *                  END
662da6c28aaSamw  *                  ELSE
663da6c28aaSamw  *                  BEGIN (* good *)
664da6c28aaSamw  *                       (*
665da6c28aaSamw  *                        * Replicate received NetBIOS datagram for
666da6c28aaSamw  *                        * each recipient
667da6c28aaSamw  *                        *)
668da6c28aaSamw  *                       FOR EACH pending NetBIOS users receive
669da6c28aaSamw  *                            datagram operation
670da6c28aaSamw  *                       BEGIN
671da6c28aaSamw  *                            IF source name of operation
672da6c28aaSamw  *                               matches destination name
673da6c28aaSamw  *                               of packet THEN
674da6c28aaSamw  *                            BEGIN
675da6c28aaSamw  *                               deliver USER_DATA from UDP
676da6c28aaSamw  *                                 packet(s);
677da6c28aaSamw  *                            END
678da6c28aaSamw  *                       END (* for each *)
679da6c28aaSamw  *                       return;
680da6c28aaSamw  *                  END (* good *)
681da6c28aaSamw  *             END (* non-broadcast *)
682da6c28aaSamw  *            END (* datagram service *)
683da6c28aaSamw  *
684da6c28aaSamw  *           DATAGRAM ERROR:
685da6c28aaSamw  *           BEGIN
686da6c28aaSamw  *                (*
687da6c28aaSamw  *                 * name service returned incorrect information
688da6c28aaSamw  *                 *)
689da6c28aaSamw  *
690da6c28aaSamw  *                inform local name service that incorrect
691da6c28aaSamw  *                  information was provided;
692da6c28aaSamw  *
693da6c28aaSamw  *                IF this is a P or M node THEN
694da6c28aaSamw  *                BEGIN
695da6c28aaSamw  *                     (*
696da6c28aaSamw  *                      * tell NetBIOS Name Server that it may
697da6c28aaSamw  *                      * have given incorrect information
698da6c28aaSamw  *                      *)
699da6c28aaSamw  *
700da6c28aaSamw  *                     send NAME RELEASE REQUEST with name
701da6c28aaSamw  *                       and incorrect IP address to NetBIOS
702da6c28aaSamw  *                       Name Server;
703da6c28aaSamw  *                END
704da6c28aaSamw  *           END (* datagram error *)
705da6c28aaSamw  *
706da6c28aaSamw  *        END (* case *)
707da6c28aaSamw  *   END
708da6c28aaSamw  */
709da6c28aaSamw 
710da6c28aaSamw static struct datagram *
smb_netbios_datagram_getq(struct datagram * datagram)711da6c28aaSamw smb_netbios_datagram_getq(struct datagram *datagram)
712da6c28aaSamw {
713da6c28aaSamw 	struct datagram *prev = 0;
714da6c28aaSamw 
715da6c28aaSamw 	(void) mutex_lock(&smb_dgq_mtx);
716da6c28aaSamw 	for (prev = smb_datagram_queue.forw;
717da6c28aaSamw 	    prev != (struct datagram *)((uintptr_t)&smb_datagram_queue);
718da6c28aaSamw 	    prev = prev->forw) {
719da6c28aaSamw 		if (prev->src.addr_list.sin.sin_addr.s_addr ==
720da6c28aaSamw 		    datagram->src.addr_list.sin.sin_addr.s_addr) {
721da6c28aaSamw 			/* Something waiting */
722da6c28aaSamw 			QUEUE_CLIP(prev);
723da6c28aaSamw 			(void) mutex_unlock(&smb_dgq_mtx);
724da6c28aaSamw 			bcopy(datagram->data, &prev->data[prev->data_length],
725da6c28aaSamw 			    datagram->data_length);
726da6c28aaSamw 			prev->data_length += datagram->data_length;
727da6c28aaSamw 			free(datagram);
728da6c28aaSamw 			return (prev);
729da6c28aaSamw 		}
730da6c28aaSamw 	}
731da6c28aaSamw 	(void) mutex_unlock(&smb_dgq_mtx);
732da6c28aaSamw 
733da6c28aaSamw 	return (0);
734da6c28aaSamw }
735da6c28aaSamw 
736da6c28aaSamw static void
smb_netbios_BPM_datagram(struct datagram * datagram)737da6c28aaSamw smb_netbios_BPM_datagram(struct datagram *datagram)
738da6c28aaSamw {
739da6c28aaSamw 	struct name_entry *entry = 0;
740da6c28aaSamw 	struct datagram *qpacket = 0;
741da6c28aaSamw 	pthread_t browser_dispatch;
742da6c28aaSamw 
743da6c28aaSamw 	switch (datagram->packet_type) {
744da6c28aaSamw 	case DATAGRAM_TYPE_BROADCAST :
745da6c28aaSamw 		if (smb_node_type == 'P') {
746da6c28aaSamw 			/*
747da6c28aaSamw 			 * if this node is a P node, ignore
748da6c28aaSamw 			 * broadcast packets.
749da6c28aaSamw 			 */
750da6c28aaSamw 			break;
751da6c28aaSamw 		}
752da6c28aaSamw 		/* FALLTHROUGH */
753da6c28aaSamw 
754da6c28aaSamw 	case DATAGRAM_TYPE_DIRECT_UNIQUE :
755da6c28aaSamw 	case DATAGRAM_TYPE_DIRECT_GROUP :
756da6c28aaSamw 		if ((datagram->flags & DATAGRAM_FLAGS_FIRST) != 0) {
757da6c28aaSamw 			if (datagram->flags & DATAGRAM_FLAGS_MORE) {
758da6c28aaSamw 				/* Save 1st UDP packet of the Datagram */
759da6c28aaSamw 				datagram->discard_timer = FRAGMENT_TIMEOUT;
760da6c28aaSamw 				(void) mutex_lock(&smb_dgq_mtx);
761da6c28aaSamw 				QUEUE_INSERT_TAIL(&smb_datagram_queue, datagram)
762da6c28aaSamw 				(void) mutex_unlock(&smb_dgq_mtx);
763da6c28aaSamw 				return;
764da6c28aaSamw 			}
765da6c28aaSamw 			/* process datagram */
766da6c28aaSamw 		} else {
767da6c28aaSamw 			qpacket = smb_netbios_datagram_getq(datagram);
768da6c28aaSamw 			if (qpacket) {
769da6c28aaSamw 				datagram = qpacket;
770da6c28aaSamw 				goto process_datagram;
771da6c28aaSamw 			}
772da6c28aaSamw 			break;
773da6c28aaSamw 		}
774da6c28aaSamw 
775da6c28aaSamw process_datagram:
776da6c28aaSamw 		entry = 0;
777da6c28aaSamw 		if ((strcmp((char *)datagram->dest.name, "*") == 0) ||
778da6c28aaSamw 		    ((entry =
779da6c28aaSamw 		    smb_netbios_cache_lookup(&datagram->dest)) != 0)) {
780da6c28aaSamw 			if (entry) {
781da6c28aaSamw 				int is_local = IS_LOCAL(entry->attributes);
782da6c28aaSamw 				smb_netbios_cache_unlock_entry(entry);
783da6c28aaSamw 
784da6c28aaSamw 				if (is_local) {
785da6c28aaSamw 					(void) pthread_create(&browser_dispatch,
786da6c28aaSamw 					    0, smb_browser_dispatch,
787da6c28aaSamw 					    (void *)datagram);
788da6c28aaSamw 					(void) pthread_detach(browser_dispatch);
789da6c28aaSamw 					return;
790da6c28aaSamw 				}
791da6c28aaSamw 			}
792da6c28aaSamw 
793da6c28aaSamw 			datagram->rawbuf[0] = DATAGRAM_TYPE_ERROR_DATAGRAM;
794da6c28aaSamw 			datagram->rawbuf[1] &= DATAGRAM_FLAGS_SRC_TYPE;
795da6c28aaSamw 
796da6c28aaSamw 			(void) memcpy(&datagram->rawbuf[4],
797da6c28aaSamw 			    &datagram->src.addr_list.sin.sin_addr.s_addr,
798da6c28aaSamw 			    sizeof (uint32_t));
799*a0aa776eSAlan Wright 			BE_OUT16(&datagram->rawbuf[8], IPPORT_NETBIOS_DGM);
800da6c28aaSamw 
801da6c28aaSamw 			(void) sendto(datagram_sock, datagram->rawbuf,
802da6c28aaSamw 			    datagram->rawbytes, 0,
803da6c28aaSamw 			    (struct sockaddr *)&datagram->src.addr_list.sin,
804da6c28aaSamw 			    datagram->src.addr_list.sinlen);
805da6c28aaSamw 		}
806da6c28aaSamw 		break;
807da6c28aaSamw 
808da6c28aaSamw 	case DATAGRAM_TYPE_ERROR_DATAGRAM :
809da6c28aaSamw 		break;
810da6c28aaSamw 	}
811da6c28aaSamw 	free(datagram);
812da6c28aaSamw }
813da6c28aaSamw 
814da6c28aaSamw /*
815*a0aa776eSAlan Wright  * NetBIOS Datagram Service (port 138)
816da6c28aaSamw  */
817da6c28aaSamw /*ARGSUSED*/
818da6c28aaSamw void *
smb_netbios_datagram_service(void * arg)819*a0aa776eSAlan Wright smb_netbios_datagram_service(void *arg)
820da6c28aaSamw {
821da6c28aaSamw 	struct sockaddr_in 	sin;
822da6c28aaSamw 	struct datagram 	*datagram;
823da6c28aaSamw 	int			bytes, flag = 1;
8247f667e74Sjose borrego 	smb_inaddr_t 		ipaddr;
825da6c28aaSamw 
826da6c28aaSamw 	(void) mutex_lock(&smb_dgq_mtx);
827da6c28aaSamw 	bzero(&smb_datagram_queue, sizeof (smb_datagram_queue));
828da6c28aaSamw 	smb_datagram_queue.forw = smb_datagram_queue.back =
829da6c28aaSamw 	    (struct datagram *)((uintptr_t)&smb_datagram_queue);
830da6c28aaSamw 	(void) mutex_unlock(&smb_dgq_mtx);
831da6c28aaSamw 
832da6c28aaSamw 	if ((datagram_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
833*a0aa776eSAlan Wright 		syslog(LOG_ERR, "nbt datagram: socket failed: %m");
834*a0aa776eSAlan Wright 		smb_netbios_event(NETBIOS_EVENT_ERROR);
835*a0aa776eSAlan Wright 		return (NULL);
836da6c28aaSamw 	}
837da6c28aaSamw 
838*a0aa776eSAlan Wright 	flag = 1;
839*a0aa776eSAlan Wright 	(void) setsockopt(datagram_sock, SOL_SOCKET, SO_REUSEADDR, &flag,
840*a0aa776eSAlan Wright 	    sizeof (flag));
841*a0aa776eSAlan Wright 
842da6c28aaSamw 	bzero(&sin, sizeof (sin));
843da6c28aaSamw 	sin.sin_family = AF_INET;
844*a0aa776eSAlan Wright 	sin.sin_port = htons(IPPORT_NETBIOS_DGM);
845da6c28aaSamw 	if (bind(datagram_sock, (struct sockaddr *)&sin, sizeof (sin)) != 0) {
846*a0aa776eSAlan Wright 		syslog(LOG_ERR, "nbt datagram: bind(%d) failed: %m",
847*a0aa776eSAlan Wright 		    IPPORT_NETBIOS_DGM);
848da6c28aaSamw 		(void) close(datagram_sock);
849*a0aa776eSAlan Wright 		smb_netbios_event(NETBIOS_EVENT_ERROR);
850*a0aa776eSAlan Wright 		return (NULL);
851da6c28aaSamw 	}
852*a0aa776eSAlan Wright 
853*a0aa776eSAlan Wright 	flag = 1;
854da6c28aaSamw 	(void) setsockopt(datagram_sock, SOL_SOCKET, SO_BROADCAST, &flag,
855da6c28aaSamw 	    sizeof (flag));
856da6c28aaSamw 
857*a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_DGM_START);
858da6c28aaSamw 
859*a0aa776eSAlan Wright 	while (smb_netbios_running()) {
860*a0aa776eSAlan Wright 		if ((datagram = malloc(sizeof (struct datagram))) == NULL) {
861*a0aa776eSAlan Wright 			/* Sleep for 10 seconds and try again */
862*a0aa776eSAlan Wright 			smb_netbios_sleep(10);
863da6c28aaSamw 			continue;
864da6c28aaSamw 		}
865da6c28aaSamw 
866*a0aa776eSAlan Wright ignore:		bzero(&datagram->inaddr, sizeof (addr_entry_t));
867da6c28aaSamw 		datagram->inaddr.sinlen = sizeof (datagram->inaddr.sin);
868da6c28aaSamw 		datagram->inaddr.forw = datagram->inaddr.back =
869da6c28aaSamw 		    &datagram->inaddr;
870da6c28aaSamw 
871da6c28aaSamw 		if ((bytes = recvfrom(datagram_sock, datagram->rawbuf,
872da6c28aaSamw 		    MAX_DATAGRAM_LENGTH, 0,
873da6c28aaSamw 		    (struct sockaddr *)&datagram->inaddr.sin,
874da6c28aaSamw 		    &datagram->inaddr.sinlen)) < 0) {
875*a0aa776eSAlan Wright 			syslog(LOG_ERR, "nbt datagram: recvfrom failed: %m");
876*a0aa776eSAlan Wright 			smb_netbios_event(NETBIOS_EVENT_ERROR);
877da6c28aaSamw 			break;
878da6c28aaSamw 		}
879da6c28aaSamw 
880da6c28aaSamw 		/* Ignore any incoming packets from myself... */
8817f667e74Sjose borrego 		ipaddr.a_ipv4 = datagram->inaddr.sin.sin_addr.s_addr;
8827f667e74Sjose borrego 		ipaddr.a_family = AF_INET;
883fc724630SAlan Wright 		if (smb_nic_is_local(&ipaddr)) {
884da6c28aaSamw 			goto ignore;
885da6c28aaSamw 		}
8867b59d02dSjb 
887da6c28aaSamw 		if (smb_datagram_decode(datagram, bytes) < 0)
888da6c28aaSamw 			goto ignore;
889da6c28aaSamw 
890da6c28aaSamw 	/*
891da6c28aaSamw 	 * This code was doing the wrong thing with responses from a
892da6c28aaSamw 	 * Windows2000 PDC because both DATAGRAM_FLAGS_H_NODE and
893da6c28aaSamw 	 * DATAGRAM_FLAGS_NBDD are defined to be the same value (see
894da6c28aaSamw 	 * netbios.h). Since the Windows2000 PDC wants to be an H-Node,
895da6c28aaSamw 	 * we need to handle all messages via smb_netbios_BPM_datagram.
896da6c28aaSamw 	 *
897da6c28aaSamw 	 *	if ((datagram->flags & DATAGRAM_FLAGS_SRC_TYPE) ==
898da6c28aaSamw 	 *	    DATAGRAM_FLAGS_NBDD)
899da6c28aaSamw 	 *		smb_netbios_NBDD_datagram(datagram);
900da6c28aaSamw 	 *	else
901da6c28aaSamw 	 *		smb_netbios_BPM_datagram(datagram);
902da6c28aaSamw 	 */
903da6c28aaSamw 
904da6c28aaSamw 		smb_netbios_BPM_datagram(datagram);
905da6c28aaSamw 	}
906da6c28aaSamw 
907*a0aa776eSAlan Wright 	smb_netbios_event(NETBIOS_EVENT_DGM_STOP);
908*a0aa776eSAlan Wright 	(void) smb_netbios_wait(NETBIOS_EVENT_BROWSER_STOP);
909da6c28aaSamw 
910da6c28aaSamw 	(void) close(datagram_sock);
911da6c28aaSamw 	smb_netbios_datagram_fini();
912*a0aa776eSAlan Wright 	return (NULL);
913da6c28aaSamw }
914da6c28aaSamw 
915da6c28aaSamw static char
916da6c28aaSamw /* LINTED - E_STATIC_UNUSED */
nb_fmt_flags(unsigned char flags)917da6c28aaSamw nb_fmt_flags(unsigned char flags)
918da6c28aaSamw {
919da6c28aaSamw 	switch (flags & DATAGRAM_FLAGS_SRC_TYPE) {
920da6c28aaSamw 	case DATAGRAM_FLAGS_B_NODE:	return ('B');
921da6c28aaSamw 	case DATAGRAM_FLAGS_P_NODE:	return ('P');
922da6c28aaSamw 	case DATAGRAM_FLAGS_M_NODE:	return ('M');
923da6c28aaSamw 	case DATAGRAM_FLAGS_H_NODE:	return ('H');
924da6c28aaSamw 	default:	return ('?');
925da6c28aaSamw 	}
926da6c28aaSamw }
927