xref: /illumos-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c (revision 7f667e74610492ddbce8ce60f52ece95d2401949)
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 /*
22*7f667e74Sjose 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  *
58da6c28aaSamw  *   - DGM_SRVC_UDP_PORT: 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  *
106da6c28aaSamw  *      DGM_SRVC_UDP_PORT          138 (decimal)
107da6c28aaSamw  *
108da6c28aaSamw  *      FRAGMENT_TO                2 seconds (default)
109da6c28aaSamw  */
110da6c28aaSamw 
111da6c28aaSamw #include <stdlib.h>
112da6c28aaSamw #include <unistd.h>
113da6c28aaSamw #include <string.h>
114da6c28aaSamw #include <strings.h>
115da6c28aaSamw #include <syslog.h>
116da6c28aaSamw #include <synch.h>
117da6c28aaSamw #include <sys/socket.h>
118da6c28aaSamw #include <arpa/inet.h>
119da6c28aaSamw 
120da6c28aaSamw #include <smbns_netbios.h>
121da6c28aaSamw 
122da6c28aaSamw #include <smbsrv/libsmbns.h>
123da6c28aaSamw 
124da6c28aaSamw static int datagram_sock = -1;
125da6c28aaSamw static short datagram_id = 1;
126da6c28aaSamw static struct datagram_queue smb_datagram_queue;
127da6c28aaSamw static mutex_t smb_dgq_mtx;
128da6c28aaSamw 
129da6c28aaSamw /*
130da6c28aaSamw  * Function:  smb_netbios_datagram_tick(void)
131da6c28aaSamw  *
132da6c28aaSamw  * Description:
133da6c28aaSamw  *
134da6c28aaSamw  *	Called once a second to handle time to live timeouts in
135da6c28aaSamw  *	datagram assembly queue.
136da6c28aaSamw  *
137da6c28aaSamw  * Inputs:
138da6c28aaSamw  *
139da6c28aaSamw  * Returns:
140da6c28aaSamw  *	void	-> Nothing at all...
141da6c28aaSamw  */
142da6c28aaSamw 
143da6c28aaSamw void
144da6c28aaSamw smb_netbios_datagram_tick(void)
145da6c28aaSamw {
146da6c28aaSamw 	struct datagram *entry;
147da6c28aaSamw 	struct datagram *next;
148da6c28aaSamw 
149da6c28aaSamw 	(void) mutex_lock(&smb_dgq_mtx);
150da6c28aaSamw 
151da6c28aaSamw 	for (entry = smb_datagram_queue.forw;
152da6c28aaSamw 	    entry != (struct datagram *)((uintptr_t)&smb_datagram_queue);
153da6c28aaSamw 	    entry = next) {
154da6c28aaSamw 		next = entry->forw;
155da6c28aaSamw 		if (--entry->discard_timer == 0) {
156da6c28aaSamw 			/* Toss it */
157da6c28aaSamw 			QUEUE_CLIP(entry);
158da6c28aaSamw 			free(entry);
159da6c28aaSamw 		}
160da6c28aaSamw 	}
161da6c28aaSamw 	(void) mutex_unlock(&smb_dgq_mtx);
162da6c28aaSamw }
163da6c28aaSamw 
164da6c28aaSamw void
165da6c28aaSamw smb_netbios_datagram_fini()
166da6c28aaSamw {
167da6c28aaSamw 	struct datagram *entry;
168da6c28aaSamw 
169da6c28aaSamw 	(void) mutex_lock(&smb_dgq_mtx);
170da6c28aaSamw 	while ((entry = smb_datagram_queue.forw) !=
171da6c28aaSamw 	    (struct datagram *)((uintptr_t)&smb_datagram_queue)) {
172da6c28aaSamw 		QUEUE_CLIP(entry);
173da6c28aaSamw 		free(entry);
174da6c28aaSamw 	}
175da6c28aaSamw 	(void) mutex_unlock(&smb_dgq_mtx);
176da6c28aaSamw }
177da6c28aaSamw 
178da6c28aaSamw /*
179da6c28aaSamw  * Function: int smb_netbios_send_Bnode_datagram(unsigned char *data,
180da6c28aaSamw  *		struct name_entry *source, struct name_entry *destination,
181da6c28aaSamw  *		uint32_t broadcast)
182da6c28aaSamw  *
183da6c28aaSamw  * Description from rfc1002:
184da6c28aaSamw  *
185da6c28aaSamw  *  5.3.1.  B NODE TRANSMISSION OF NetBIOS DATAGRAMS
186da6c28aaSamw  *
187da6c28aaSamw  *   PROCEDURE send_datagram(data, source, destination, broadcast)
188da6c28aaSamw  *
189da6c28aaSamw  *   (*
190da6c28aaSamw  *    * user initiated processing on B node
191da6c28aaSamw  *    *)
192da6c28aaSamw  *
193da6c28aaSamw  *   BEGIN
194da6c28aaSamw  *        group = FALSE;
195da6c28aaSamw  *
196da6c28aaSamw  *        do name discovery on destination name, returns name type and
197da6c28aaSamw  *             IP address;
198da6c28aaSamw  *
199da6c28aaSamw  *        IF name type is group name THEN
200da6c28aaSamw  *        BEGIN
201da6c28aaSamw  *             group = TRUE;
202da6c28aaSamw  *        END
203da6c28aaSamw  *
204da6c28aaSamw  *        (*
205da6c28aaSamw  *         * build datagram service UDP packet;
206da6c28aaSamw  *         *)
207da6c28aaSamw  *        convert source and destination NetBIOS names into
208da6c28aaSamw  *             half-ASCII, biased encoded name;
209da6c28aaSamw  *        SOURCE_NAME = cat(source, SCOPE_ID);
210da6c28aaSamw  *        SOURCE_IP = this nodes IP address;
211da6c28aaSamw  *        SOURCE_PORT =  DGM_SRVC_UDP_PORT;
212da6c28aaSamw  *
213da6c28aaSamw  *        IF NetBIOS broadcast THEN
214da6c28aaSamw  *        BEGIN
215da6c28aaSamw  *             DESTINATION_NAME = cat("*", SCOPE_ID)
216da6c28aaSamw  *        END
217da6c28aaSamw  *        ELSE
218da6c28aaSamw  *        BEGIN
219da6c28aaSamw  *             DESTINATION_NAME = cat(destination, SCOPE_ID)
220da6c28aaSamw  *        END
221da6c28aaSamw  *
222da6c28aaSamw  *        MSG_TYPE = select_one_from_set
223da6c28aaSamw  *             {BROADCAST, DIRECT_UNIQUE, DIRECT_GROUP}
224da6c28aaSamw  *        DGM_ID = next transaction id for Datagrams;
225da6c28aaSamw  *        DGM_LENGTH = length of data + length of second level encoded
226da6c28aaSamw  *             source and destination names;
227da6c28aaSamw  *
228da6c28aaSamw  *        IF (length of the NetBIOS Datagram, including UDP and
229da6c28aaSamw  *            IP headers, > MAX_DATAGRAM_LENGTH) THEN
230da6c28aaSamw  *        BEGIN
231da6c28aaSamw  *             (*
232da6c28aaSamw  *              * fragment NetBIOS datagram into 2 UDP packets
233da6c28aaSamw  *              *)
234da6c28aaSamw  *             Put names into 1st UDP packet and any data that fits
235da6c28aaSamw  *                  after names;
236da6c28aaSamw  *             Set MORE and FIRST bits in 1st UDP packets FLAGS;
237da6c28aaSamw  *             OFFSET in 1st UDP = 0;
238da6c28aaSamw  *
239da6c28aaSamw  *             Replicate NetBIOS Datagram header from 1st UDP packet
240da6c28aaSamw  *                  into 2nd UDP packet;
241da6c28aaSamw  *             Put rest of data in 2nd UDP packet;
242da6c28aaSamw  *             Clear MORE and FIRST bits in 2nd UDP packets FLAGS;
243da6c28aaSamw  *             OFFSET in 2nd UDP = DGM_LENGTH - number of name and
244da6c28aaSamw  *                  data bytes in 1st UDP;
245da6c28aaSamw  *        END
246da6c28aaSamw  *        BEGIN
247da6c28aaSamw  *             (*
248da6c28aaSamw  *              * Only need one UDP packet
249da6c28aaSamw  *              *)
250da6c28aaSamw  *             USER_DATA = data;
251da6c28aaSamw  *             Clear MORE bit and set FIRST bit in FLAGS;
252da6c28aaSamw  *             OFFSET = 0;
253da6c28aaSamw  *        END
254da6c28aaSamw  *
255da6c28aaSamw  *        IF (group == TRUE) OR (NetBIOS broadcast) THEN
256da6c28aaSamw  *        BEGIN
257da6c28aaSamw  *             send UDP packet(s) to BROADCAST_ADDRESS;
258da6c28aaSamw  *        END
259da6c28aaSamw  *        ELSE
260da6c28aaSamw  *        BEGIN
261da6c28aaSamw  *             send UDP packet(s) to IP address returned by name
262da6c28aaSamw  *                discovery;
263da6c28aaSamw  *        END
264da6c28aaSamw  *   END (* procedure *)
265da6c28aaSamw  *                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
266da6c28aaSamw  *    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
267da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
268da6c28aaSamw  *   |   MSG_TYPE    |     FLAGS     |           DGM_ID              |
269da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
270da6c28aaSamw  *   |                           SOURCE_IP                           |
271da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
272da6c28aaSamw  *   |          SOURCE_PORT          |          DGM_LENGTH           |
273da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
274da6c28aaSamw  *   |         PACKET_OFFSET         |
275da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
276da6c28aaSamw  *
277da6c28aaSamw  *   MSG_TYPE values (in hexidecimal):
278da6c28aaSamw  *
279da6c28aaSamw  *           10 -  DIRECT_UNIQUE DATAGRAM
280da6c28aaSamw  *           11 -  DIRECT_GROUP DATAGRAM
281da6c28aaSamw  *           12 -  BROADCAST DATAGRAM
282da6c28aaSamw  *           13 -  DATAGRAM ERROR
283da6c28aaSamw  *           14 -  DATAGRAM QUERY REQUEST
284da6c28aaSamw  *           15 -  DATAGRAM POSITIVE QUERY RESPONSE
285da6c28aaSamw  *           16 -  DATAGRAM NEGATIVE QUERY RESPONSE
286da6c28aaSamw  *
287da6c28aaSamw  *   Bit definitions of the FLAGS field:
288da6c28aaSamw  *
289da6c28aaSamw  *     0   1   2   3   4   5   6   7
290da6c28aaSamw  *   +---+---+---+---+---+---+---+---+
291da6c28aaSamw  *   | 0 | 0 | 0 | 0 |  SNT  | F | M |
292da6c28aaSamw  *   +---+---+---+---+---+---+---+---+
293da6c28aaSamw  *
294da6c28aaSamw  *   Symbol     Bit(s)   Description
295da6c28aaSamw  *
296da6c28aaSamw  *   M               7   MORE flag, If set then more NetBIOS datagram
297da6c28aaSamw  *                       fragments follow.
298da6c28aaSamw  *
299da6c28aaSamw  *   F               6   FIRST packet flag,  If set then this is first
300da6c28aaSamw  *                       (and possibly only) fragment of NetBIOS
301da6c28aaSamw  *                       datagram
302da6c28aaSamw  *
303da6c28aaSamw  *   SNT           4,5   Source End-Node type:
304da6c28aaSamw  *                          00 = B node
305da6c28aaSamw  *                          01 = P node
306da6c28aaSamw  *                          10 = M node
307da6c28aaSamw  *                          11 = NBDD
308da6c28aaSamw  *   RESERVED      0-3   Reserved, must be zero (0)
309da6c28aaSamw  *      (But MS sets bit 3 in this field)
310da6c28aaSamw  *
311da6c28aaSamw  */
312da6c28aaSamw 
313da6c28aaSamw int
314da6c28aaSamw smb_netbios_datagram_send(struct name_entry *src, struct name_entry *dest,
315da6c28aaSamw     unsigned char *data, int length)
316da6c28aaSamw {
317*7f667e74Sjose borrego 	smb_inaddr_t ipaddr;
318da6c28aaSamw 	size_t count, srclen, destlen, sinlen;
319da6c28aaSamw 	struct addr_entry *addr;
320da6c28aaSamw 	struct sockaddr_in sin;
321da6c28aaSamw 	char *buffer;
322da6c28aaSamw 	char ha_source[NETBIOS_DOMAIN_NAME_MAX];
323da6c28aaSamw 	char ha_dest[NETBIOS_DOMAIN_NAME_MAX];
324da6c28aaSamw 
325da6c28aaSamw 	(void) smb_first_level_name_encode(src, (unsigned char *)ha_source,
326da6c28aaSamw 	    sizeof (ha_source));
327da6c28aaSamw 	srclen = strlen(ha_source) + 1;
328da6c28aaSamw 
329da6c28aaSamw 	(void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest,
330da6c28aaSamw 	    sizeof (ha_dest));
331da6c28aaSamw 	destlen = strlen(ha_dest) + 1;
332da6c28aaSamw 
333da6c28aaSamw 	/* give some extra room */
334da6c28aaSamw 	buffer = (char *)malloc(MAX_DATAGRAM_LENGTH * 4);
335da6c28aaSamw 	if (buffer == 0) {
336da6c28aaSamw 		syslog(LOG_ERR, "netbios: datagram send (resource shortage)");
337da6c28aaSamw 		return (-1);
338da6c28aaSamw 	}
339da6c28aaSamw 
340da6c28aaSamw 	buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE;
341da6c28aaSamw 	switch (smb_node_type) {
342da6c28aaSamw 	case 'B':
343da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST;
344da6c28aaSamw 		break;
345da6c28aaSamw 	case 'P':
346da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST;
347da6c28aaSamw 		break;
348da6c28aaSamw 	case 'M':
349da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST;
350da6c28aaSamw 		break;
351da6c28aaSamw 	case 'H':
352da6c28aaSamw 	default:
353da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST;
354da6c28aaSamw 		break;
355da6c28aaSamw 	}
356da6c28aaSamw 
357da6c28aaSamw 	datagram_id++;
358da6c28aaSamw 	BE_OUT16(&buffer[2], datagram_id);
359da6c28aaSamw 	(void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr,
360da6c28aaSamw 	    sizeof (uint32_t));
361da6c28aaSamw 	(void) memcpy(&buffer[8], &src->addr_list.sin.sin_port,
362da6c28aaSamw 	    sizeof (uint16_t));
363da6c28aaSamw 	BE_OUT16(&buffer[10], length + srclen + destlen);
364da6c28aaSamw 	BE_OUT16(&buffer[12], 0);
365da6c28aaSamw 
366da6c28aaSamw 	bcopy(ha_source, &buffer[14], srclen);
367da6c28aaSamw 	bcopy(ha_dest, &buffer[14 + srclen], destlen);
368da6c28aaSamw 	bcopy(data, &buffer[14 + srclen + destlen], length);
369da6c28aaSamw 	count = &buffer[14 + srclen + destlen + length] - buffer;
370da6c28aaSamw 
371da6c28aaSamw 	bzero(&sin, sizeof (sin));
372da6c28aaSamw 	sin.sin_family = AF_INET;
373da6c28aaSamw 	sinlen = sizeof (sin);
374da6c28aaSamw 	addr = &dest->addr_list;
375da6c28aaSamw 	do {
376*7f667e74Sjose borrego 		ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
377*7f667e74Sjose borrego 		ipaddr.a_family = AF_INET;
378da6c28aaSamw 		/* Don't send anything to myself... */
379*7f667e74Sjose borrego 		if (smb_nic_exists(&ipaddr, B_FALSE))
380da6c28aaSamw 			goto next;
381da6c28aaSamw 
382*7f667e74Sjose borrego 		sin.sin_addr.s_addr = ipaddr.a_ipv4;
383da6c28aaSamw 		sin.sin_port = addr->sin.sin_port;
384da6c28aaSamw 		(void) sendto(datagram_sock, buffer, count, 0,
385da6c28aaSamw 		    (struct sockaddr *)&sin, sinlen);
386da6c28aaSamw 
387da6c28aaSamw next:		addr = addr->forw;
388da6c28aaSamw 	} while (addr != &dest->addr_list);
389da6c28aaSamw 	free(buffer);
390da6c28aaSamw 	return (0);
391da6c28aaSamw }
392da6c28aaSamw 
393da6c28aaSamw 
394da6c28aaSamw int
395da6c28aaSamw smb_netbios_datagram_send_to_net(struct name_entry *src,
396da6c28aaSamw     struct name_entry *dest, char *data, int length)
397da6c28aaSamw {
398*7f667e74Sjose borrego 	smb_inaddr_t ipaddr;
399da6c28aaSamw 	size_t count, srclen, destlen, sinlen;
400da6c28aaSamw 	struct addr_entry *addr;
401da6c28aaSamw 	struct sockaddr_in sin;
402da6c28aaSamw 	char *buffer;
403da6c28aaSamw 	char ha_source[NETBIOS_DOMAIN_NAME_MAX];
404da6c28aaSamw 	char ha_dest[NETBIOS_DOMAIN_NAME_MAX];
405da6c28aaSamw 
406da6c28aaSamw 	(void) smb_first_level_name_encode(src, (unsigned char *)ha_source,
407da6c28aaSamw 	    sizeof (ha_source));
408da6c28aaSamw 	srclen = strlen(ha_source) + 1;
409da6c28aaSamw 
410da6c28aaSamw 	(void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest,
411da6c28aaSamw 	    sizeof (ha_dest));
412da6c28aaSamw 	destlen = strlen(ha_dest) + 1;
413da6c28aaSamw 
414da6c28aaSamw 	/* give some extra room */
415da6c28aaSamw 	buffer = (char *)malloc(MAX_DATAGRAM_LENGTH * 4);
416da6c28aaSamw 	if (buffer == 0) {
417da6c28aaSamw 		syslog(LOG_ERR, "netbios: datagram send (resource shortage)");
418da6c28aaSamw 		return (-1);
419da6c28aaSamw 	}
420da6c28aaSamw 
421da6c28aaSamw 	buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE;
422da6c28aaSamw 	switch (smb_node_type) {
423da6c28aaSamw 	case 'B':
424da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST;
425da6c28aaSamw 		break;
426da6c28aaSamw 	case 'P':
427da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST;
428da6c28aaSamw 		break;
429da6c28aaSamw 	case 'M':
430da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST;
431da6c28aaSamw 		break;
432da6c28aaSamw 	case 'H':
433da6c28aaSamw 	default:
434da6c28aaSamw 		buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST;
435da6c28aaSamw 		break;
436da6c28aaSamw 	}
437da6c28aaSamw 
438da6c28aaSamw 	datagram_id++;
439da6c28aaSamw 	BE_OUT16(&buffer[2], datagram_id);
440da6c28aaSamw 	(void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr,
441da6c28aaSamw 	    sizeof (uint32_t));
442da6c28aaSamw 	(void) memcpy(&buffer[8], &src->addr_list.sin.sin_port,
443da6c28aaSamw 	    sizeof (uint16_t));
444da6c28aaSamw 	BE_OUT16(&buffer[10], length + srclen + destlen);
445da6c28aaSamw 	BE_OUT16(&buffer[12], 0);
446da6c28aaSamw 
447da6c28aaSamw 	bcopy(ha_source, &buffer[14], srclen);
448da6c28aaSamw 	bcopy(ha_dest, &buffer[14 + srclen], destlen);
449da6c28aaSamw 	bcopy(data, &buffer[14 + srclen + destlen], length);
450da6c28aaSamw 	count = &buffer[14 + srclen + destlen + length] - buffer;
451da6c28aaSamw 
452da6c28aaSamw 	bzero(&sin, sizeof (sin));
453da6c28aaSamw 	sin.sin_family = AF_INET;
454da6c28aaSamw 	sinlen = sizeof (sin);
455da6c28aaSamw 	addr = &dest->addr_list;
456da6c28aaSamw 	do {
457*7f667e74Sjose borrego 		ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
458*7f667e74Sjose borrego 		ipaddr.a_family = AF_INET;
459*7f667e74Sjose borrego 		if (smb_nic_exists(&ipaddr, B_FALSE))
460da6c28aaSamw 			goto next;
4617b59d02dSjb 
462*7f667e74Sjose borrego 		sin.sin_addr.s_addr = ipaddr.a_ipv4;
463da6c28aaSamw 		sin.sin_port = addr->sin.sin_port;
464da6c28aaSamw 		(void) sendto(datagram_sock, buffer, count, 0,
465da6c28aaSamw 		    (struct sockaddr *)&sin, sinlen);
466da6c28aaSamw 
467da6c28aaSamw next:		addr = addr->forw;
468da6c28aaSamw 	} while (addr != &dest->addr_list);
469da6c28aaSamw 	free(buffer);
470da6c28aaSamw 	return (0);
471da6c28aaSamw }
472da6c28aaSamw 
473da6c28aaSamw 
474da6c28aaSamw int
475da6c28aaSamw smb_datagram_decode(struct datagram *datagram, int bytes)
476da6c28aaSamw {
477da6c28aaSamw 	unsigned char *ha_src;
478da6c28aaSamw 	unsigned char *ha_dest;
479da6c28aaSamw 	unsigned char *data;
480da6c28aaSamw 
481da6c28aaSamw 	if (bytes < DATAGRAM_HEADER_LENGTH) {
482da6c28aaSamw 		syslog(LOG_ERR, "NbtDatagramDecode[%d]: too small packet",
483da6c28aaSamw 		    bytes);
484da6c28aaSamw 		return (-1);
485da6c28aaSamw 	}
486da6c28aaSamw 
487da6c28aaSamw 	ha_src = &datagram->rawbuf[DATAGRAM_HEADER_LENGTH];
488da6c28aaSamw 	ha_dest = ha_src + strlen((char *)ha_src) + 1;
489da6c28aaSamw 	data = ha_dest + strlen((char *)ha_dest) + 1;
490da6c28aaSamw 
491da6c28aaSamw 	bzero(&datagram->src, sizeof (struct name_entry));
492da6c28aaSamw 	bzero(&datagram->dest, sizeof (struct name_entry));
493da6c28aaSamw 
494da6c28aaSamw 	datagram->rawbytes = bytes;
495da6c28aaSamw 	datagram->packet_type = datagram->rawbuf[0];
496da6c28aaSamw 	datagram->flags = datagram->rawbuf[1];
497da6c28aaSamw 	datagram->datagram_id = BE_IN16(&datagram->rawbuf[2]);
498da6c28aaSamw 
499da6c28aaSamw 	datagram->src.addr_list.sinlen = sizeof (struct sockaddr_in);
500da6c28aaSamw 	(void) memcpy(&datagram->src.addr_list.sin.sin_addr.s_addr,
501da6c28aaSamw 	    &datagram->rawbuf[4], sizeof (uint32_t));
502da6c28aaSamw 	(void) memcpy(&datagram->src.addr_list.sin.sin_port,
503da6c28aaSamw 	    &datagram->rawbuf[8], sizeof (uint16_t));
504da6c28aaSamw 	datagram->src.addr_list.forw = datagram->src.addr_list.back =
505da6c28aaSamw 	    &datagram->src.addr_list;
506da6c28aaSamw 
507da6c28aaSamw 	datagram->data = data;
508da6c28aaSamw 	datagram->data_length = BE_IN16(&datagram->rawbuf[10]);
509da6c28aaSamw 	datagram->offset = BE_IN16(&datagram->rawbuf[12]);
510da6c28aaSamw 
511da6c28aaSamw 	if (smb_first_level_name_decode(ha_src, &datagram->src) < 0) {
512da6c28aaSamw 		syslog(LOG_DEBUG, "NbtDatagram[%s]: invalid calling name",
513da6c28aaSamw 		    inet_ntoa(datagram->src.addr_list.sin.sin_addr));
514da6c28aaSamw 		syslog(LOG_DEBUG, "Calling name: <%02X>%32.32s",
515da6c28aaSamw 		    ha_src[0], &ha_src[1]);
516da6c28aaSamw 	}
517da6c28aaSamw 
518da6c28aaSamw 	datagram->dest.addr_list.forw = datagram->dest.addr_list.back =
519da6c28aaSamw 	    &datagram->dest.addr_list;
520da6c28aaSamw 
521da6c28aaSamw 	if (smb_first_level_name_decode(ha_dest, &datagram->dest) < 0) {
522da6c28aaSamw 		syslog(LOG_DEBUG, "NbtDatagram[%s]: invalid called name",
523da6c28aaSamw 		    inet_ntoa(datagram->src.addr_list.sin.sin_addr));
524da6c28aaSamw 		syslog(LOG_DEBUG, "Called name: <%02X>%32.32s", ha_dest[0],
525da6c28aaSamw 		    &ha_dest[1]);
526da6c28aaSamw 	}
527da6c28aaSamw 
528da6c28aaSamw 	return (0);
529da6c28aaSamw }
530da6c28aaSamw 
531da6c28aaSamw 
532da6c28aaSamw /*
533da6c28aaSamw  * Function: int smb_netbios_process_BPM_datagram(unsigned char *packet,
534da6c28aaSamw  *		struct addr_entry *addr)
535da6c28aaSamw  *
536da6c28aaSamw  * Description from rfc1002:
537da6c28aaSamw  *
538da6c28aaSamw  *  5.3.3.  RECEPTION OF NetBIOS DATAGRAMS BY ALL NODES
539da6c28aaSamw  *
540da6c28aaSamw  *   The following algorithm discards out of order NetBIOS Datagram
541da6c28aaSamw  *   fragments.  An implementation which reassembles out of order
542da6c28aaSamw  *   NetBIOS Datagram fragments conforms to this specification.  The
543da6c28aaSamw  *   fragment discard timer is initialized to the value FRAGMENT_TIMEOUT.
544da6c28aaSamw  *   This value should be user configurable.  The default value is
545da6c28aaSamw  *   given in Section 6, "Defined Constants and Variables".
546da6c28aaSamw  *
547da6c28aaSamw  *   PROCEDURE datagram_packet(packet)
548da6c28aaSamw  *
549da6c28aaSamw  *   (*
550da6c28aaSamw  *    * processing initiated by datagram packet reception
551da6c28aaSamw  *    * on B, P and M nodes
552da6c28aaSamw  *    *)
553da6c28aaSamw  *   BEGIN
554da6c28aaSamw  *        (*
555da6c28aaSamw  *         * if this node is a P node, ignore
556da6c28aaSamw  *         * broadcast packets.
557da6c28aaSamw  *         *)
558da6c28aaSamw  *
559da6c28aaSamw  *        IF this is a P node AND incoming packet is
560da6c28aaSamw  *             a broadcast packet THEN
561da6c28aaSamw  *        BEGIN
562da6c28aaSamw  *             discard packet;
563da6c28aaSamw  *        END
564da6c28aaSamw  *
565da6c28aaSamw  *        CASE packet type OF
566da6c28aaSamw  *
567da6c28aaSamw  *           DATAGRAM SERVICE:
568da6c28aaSamw  *           BEGIN
569da6c28aaSamw  *             IF FIRST bit in FLAGS is set THEN
570da6c28aaSamw  *             BEGIN
571da6c28aaSamw  *                  IF MORE bit in FLAGS is set THEN
572da6c28aaSamw  *                  BEGIN
573da6c28aaSamw  *                       Save 1st UDP packet of the Datagram;
574da6c28aaSamw  *                       Set this Datagrams fragment discard
575da6c28aaSamw  *                         timer to FRAGMENT_TIMEOUT;
576da6c28aaSamw  *                       return;
577da6c28aaSamw  *                  END
578da6c28aaSamw  *                  ELSE
579da6c28aaSamw  *                       Datagram is composed of a single
580da6c28aaSamw  *                         UDP packet;
581da6c28aaSamw  *             END
582da6c28aaSamw  *             ELSE
583da6c28aaSamw  *             BEGIN
584da6c28aaSamw  *                  (* Have the second fragment of a Datagram *)
585da6c28aaSamw  *
586da6c28aaSamw  *                  Search for 1st fragment by source IP address
587da6c28aaSamw  *                     and DGM_ID;
588da6c28aaSamw  *                  IF found 1st fragment THEN
589da6c28aaSamw  *                       Process both UDP packets;
590da6c28aaSamw  *                  ELSE
591da6c28aaSamw  *                  BEGIN
592da6c28aaSamw  *                       discard 2nd fragment UDP packet;
593da6c28aaSamw  *                       return;
594da6c28aaSamw  *                  END
595da6c28aaSamw  *             END
596da6c28aaSamw  *
597da6c28aaSamw  *             IF DESTINATION_NAME is '*' THEN
598da6c28aaSamw  *             BEGIN
599da6c28aaSamw  *                  (* NetBIOS broadcast *)
600da6c28aaSamw  *
601da6c28aaSamw  *                  deliver USER_DATA from UDP packet(s) to all
602da6c28aaSamw  *                       outstanding receive broadcast
603da6c28aaSamw  *                       datagram requests;
604da6c28aaSamw  *                  return;
605da6c28aaSamw  *             END
606da6c28aaSamw  *             ELSE
607da6c28aaSamw  *             BEGIN (* non-broadcast *)
608da6c28aaSamw  *                  (* Datagram for Unique or Group Name *)
609da6c28aaSamw  *
610da6c28aaSamw  *                  IF DESTINATION_NAME is not present in the
611da6c28aaSamw  *                     local name table THEN
612da6c28aaSamw  *                  BEGIN
613da6c28aaSamw  *                       (* destination not present *)
614da6c28aaSamw  *                       build DATAGRAM ERROR packet, clear
615da6c28aaSamw  *                            FIRST and MORE bit, put in
616da6c28aaSamw  *                            this nodes IP and PORT, set
617da6c28aaSamw  *                            ERROR_CODE;
618da6c28aaSamw  *                       send DATAGRAM ERROR packet to
619da6c28aaSamw  *                            source IP address and port
620da6c28aaSamw  *                            of UDP;
621da6c28aaSamw  *                       discard UDP packet(s);
622da6c28aaSamw  *                       return;
623da6c28aaSamw  *                  END
624da6c28aaSamw  *                  ELSE
625da6c28aaSamw  *                  BEGIN (* good *)
626da6c28aaSamw  *                       (*
627da6c28aaSamw  *                        * Replicate received NetBIOS datagram for
628da6c28aaSamw  *                        * each recipient
629da6c28aaSamw  *                        *)
630da6c28aaSamw  *                       FOR EACH pending NetBIOS users receive
631da6c28aaSamw  *                            datagram operation
632da6c28aaSamw  *                       BEGIN
633da6c28aaSamw  *                            IF source name of operation
634da6c28aaSamw  *                               matches destination name
635da6c28aaSamw  *                               of packet THEN
636da6c28aaSamw  *                            BEGIN
637da6c28aaSamw  *                               deliver USER_DATA from UDP
638da6c28aaSamw  *                                 packet(s);
639da6c28aaSamw  *                            END
640da6c28aaSamw  *                       END (* for each *)
641da6c28aaSamw  *                       return;
642da6c28aaSamw  *                  END (* good *)
643da6c28aaSamw  *             END (* non-broadcast *)
644da6c28aaSamw  *            END (* datagram service *)
645da6c28aaSamw  *
646da6c28aaSamw  *           DATAGRAM ERROR:
647da6c28aaSamw  *           BEGIN
648da6c28aaSamw  *                (*
649da6c28aaSamw  *                 * name service returned incorrect information
650da6c28aaSamw  *                 *)
651da6c28aaSamw  *
652da6c28aaSamw  *                inform local name service that incorrect
653da6c28aaSamw  *                  information was provided;
654da6c28aaSamw  *
655da6c28aaSamw  *                IF this is a P or M node THEN
656da6c28aaSamw  *                BEGIN
657da6c28aaSamw  *                     (*
658da6c28aaSamw  *                      * tell NetBIOS Name Server that it may
659da6c28aaSamw  *                      * have given incorrect information
660da6c28aaSamw  *                      *)
661da6c28aaSamw  *
662da6c28aaSamw  *                     send NAME RELEASE REQUEST with name
663da6c28aaSamw  *                       and incorrect IP address to NetBIOS
664da6c28aaSamw  *                       Name Server;
665da6c28aaSamw  *                END
666da6c28aaSamw  *           END (* datagram error *)
667da6c28aaSamw  *
668da6c28aaSamw  *        END (* case *)
669da6c28aaSamw  *   END
670da6c28aaSamw  */
671da6c28aaSamw 
672da6c28aaSamw static struct datagram *
673da6c28aaSamw smb_netbios_datagram_getq(struct datagram *datagram)
674da6c28aaSamw {
675da6c28aaSamw 	struct datagram *prev = 0;
676da6c28aaSamw 
677da6c28aaSamw 	(void) mutex_lock(&smb_dgq_mtx);
678da6c28aaSamw 	for (prev = smb_datagram_queue.forw;
679da6c28aaSamw 	    prev != (struct datagram *)((uintptr_t)&smb_datagram_queue);
680da6c28aaSamw 	    prev = prev->forw) {
681da6c28aaSamw 		if (prev->src.addr_list.sin.sin_addr.s_addr ==
682da6c28aaSamw 		    datagram->src.addr_list.sin.sin_addr.s_addr) {
683da6c28aaSamw 			/* Something waiting */
684da6c28aaSamw 			QUEUE_CLIP(prev);
685da6c28aaSamw 			(void) mutex_unlock(&smb_dgq_mtx);
686da6c28aaSamw 			bcopy(datagram->data, &prev->data[prev->data_length],
687da6c28aaSamw 			    datagram->data_length);
688da6c28aaSamw 			prev->data_length += datagram->data_length;
689da6c28aaSamw 			free(datagram);
690da6c28aaSamw 			return (prev);
691da6c28aaSamw 		}
692da6c28aaSamw 	}
693da6c28aaSamw 	(void) mutex_unlock(&smb_dgq_mtx);
694da6c28aaSamw 
695da6c28aaSamw 	return (0);
696da6c28aaSamw }
697da6c28aaSamw 
698da6c28aaSamw static void
699da6c28aaSamw smb_netbios_BPM_datagram(struct datagram *datagram)
700da6c28aaSamw {
701da6c28aaSamw 	struct name_entry *entry = 0;
702da6c28aaSamw 	struct datagram *qpacket = 0;
703da6c28aaSamw 	pthread_t browser_dispatch;
704da6c28aaSamw 
705da6c28aaSamw 	switch (datagram->packet_type) {
706da6c28aaSamw 	case DATAGRAM_TYPE_BROADCAST :
707da6c28aaSamw 		if (smb_node_type == 'P') {
708da6c28aaSamw 			/*
709da6c28aaSamw 			 * if this node is a P node, ignore
710da6c28aaSamw 			 * broadcast packets.
711da6c28aaSamw 			 */
712da6c28aaSamw 			break;
713da6c28aaSamw 		}
714da6c28aaSamw 		/* FALLTHROUGH */
715da6c28aaSamw 
716da6c28aaSamw 	case DATAGRAM_TYPE_DIRECT_UNIQUE :
717da6c28aaSamw 	case DATAGRAM_TYPE_DIRECT_GROUP :
718da6c28aaSamw 		if ((datagram->flags & DATAGRAM_FLAGS_FIRST) != 0) {
719da6c28aaSamw 			if (datagram->flags & DATAGRAM_FLAGS_MORE) {
720da6c28aaSamw 				/* Save 1st UDP packet of the Datagram */
721da6c28aaSamw 				datagram->discard_timer = FRAGMENT_TIMEOUT;
722da6c28aaSamw 				(void) mutex_lock(&smb_dgq_mtx);
723da6c28aaSamw 				QUEUE_INSERT_TAIL(&smb_datagram_queue, datagram)
724da6c28aaSamw 				(void) mutex_unlock(&smb_dgq_mtx);
725da6c28aaSamw 				return;
726da6c28aaSamw 			}
727da6c28aaSamw 			/* process datagram */
728da6c28aaSamw 		} else {
729da6c28aaSamw 			qpacket = smb_netbios_datagram_getq(datagram);
730da6c28aaSamw 			if (qpacket) {
731da6c28aaSamw 				datagram = qpacket;
732da6c28aaSamw 				goto process_datagram;
733da6c28aaSamw 			}
734da6c28aaSamw 			break;
735da6c28aaSamw 		}
736da6c28aaSamw 
737da6c28aaSamw process_datagram:
738da6c28aaSamw 		entry = 0;
739da6c28aaSamw 		if ((strcmp((char *)datagram->dest.name, "*") == 0) ||
740da6c28aaSamw 		    ((entry =
741da6c28aaSamw 		    smb_netbios_cache_lookup(&datagram->dest)) != 0)) {
742da6c28aaSamw 			if (entry) {
743da6c28aaSamw 				int is_local = IS_LOCAL(entry->attributes);
744da6c28aaSamw 				smb_netbios_cache_unlock_entry(entry);
745da6c28aaSamw 
746da6c28aaSamw 				if (is_local) {
747da6c28aaSamw 					(void) pthread_create(&browser_dispatch,
748da6c28aaSamw 					    0, smb_browser_dispatch,
749da6c28aaSamw 					    (void *)datagram);
750da6c28aaSamw 					(void) pthread_detach(browser_dispatch);
751da6c28aaSamw 					return;
752da6c28aaSamw 				}
753da6c28aaSamw 			}
754da6c28aaSamw 
755da6c28aaSamw 			datagram->rawbuf[0] = DATAGRAM_TYPE_ERROR_DATAGRAM;
756da6c28aaSamw 			datagram->rawbuf[1] &= DATAGRAM_FLAGS_SRC_TYPE;
757da6c28aaSamw 
758da6c28aaSamw 			(void) memcpy(&datagram->rawbuf[4],
759da6c28aaSamw 			    &datagram->src.addr_list.sin.sin_addr.s_addr,
760da6c28aaSamw 			    sizeof (uint32_t));
761da6c28aaSamw 			BE_OUT16(&datagram->rawbuf[8], DGM_SRVC_UDP_PORT);
762da6c28aaSamw 
763da6c28aaSamw 			(void) sendto(datagram_sock, datagram->rawbuf,
764da6c28aaSamw 			    datagram->rawbytes, 0,
765da6c28aaSamw 			    (struct sockaddr *)&datagram->src.addr_list.sin,
766da6c28aaSamw 			    datagram->src.addr_list.sinlen);
767da6c28aaSamw 		}
768da6c28aaSamw 		break;
769da6c28aaSamw 
770da6c28aaSamw 	case DATAGRAM_TYPE_ERROR_DATAGRAM :
771da6c28aaSamw 		break;
772da6c28aaSamw 	}
773da6c28aaSamw 	free(datagram);
774da6c28aaSamw }
775da6c28aaSamw 
776da6c28aaSamw 
777da6c28aaSamw /*
778da6c28aaSamw  * smb_netbios_process_NBDD_datagram
779da6c28aaSamw  *
780da6c28aaSamw  * Description from rfc1002:
781da6c28aaSamw  *
782da6c28aaSamw  *
783da6c28aaSamw  *  5.3.4.  PROTOCOLS FOR THE NBDD
784da6c28aaSamw  *
785da6c28aaSamw  *   The key to NetBIOS Datagram forwarding service is the packet
786da6c28aaSamw  *   delivered to the destination end node must have the same NetBIOS
787da6c28aaSamw  *   header as if the source end node sent the packet directly to the
788da6c28aaSamw  *   destination end node.  Consequently, the NBDD does not reassemble
789da6c28aaSamw  *   NetBIOS Datagrams.  It forwards the UDP packet as is.
790da6c28aaSamw  *
791da6c28aaSamw  *   PROCEDURE  datagram_packet(packet)
792da6c28aaSamw  *
793da6c28aaSamw  *   (*
794da6c28aaSamw  *    * processing initiated by a incoming datagram service
795da6c28aaSamw  *    * packet on a NBDD node.
796da6c28aaSamw  *    *)
797da6c28aaSamw  *
798da6c28aaSamw  *   BEGIN
799da6c28aaSamw  *        CASE packet type OF
800da6c28aaSamw  *
801da6c28aaSamw  *           DATAGRAM SERVICE:
802da6c28aaSamw  *           BEGIN
803da6c28aaSamw  *                IF packet was sent as a directed
804da6c28aaSamw  *                   NetBIOS datagram THEN
805da6c28aaSamw  *                BEGIN
806da6c28aaSamw  *                  (*
807da6c28aaSamw  *                   * provide group forwarding service
808da6c28aaSamw  *                   *
809da6c28aaSamw  *                   * Forward datagram to each member of the
810da6c28aaSamw  *                   * group.  Can forward via:
811da6c28aaSamw  *                   *   1) get list of group members and send
812da6c28aaSamw  *                   *   the DATAGRAM SERVICE packet unicast
813da6c28aaSamw  *                   *   to each
814da6c28aaSamw  *                   *   2) use Group Multicast, if available
815da6c28aaSamw  *                   *   3) combination of 1) and 2)
816da6c28aaSamw  *                   *)
817da6c28aaSamw  *
818da6c28aaSamw  *                  ...
819da6c28aaSamw  *
820da6c28aaSamw  *                END
821da6c28aaSamw  *
822da6c28aaSamw  *                ELSE
823da6c28aaSamw  *                BEGIN
824da6c28aaSamw  *                  (*
825da6c28aaSamw  *                   * provide broadcast forwarding service
826da6c28aaSamw  *                   *
827da6c28aaSamw  *                   * Forward datagram to every node in the
828da6c28aaSamw  *                   * NetBIOS scope.  Can forward via:
829da6c28aaSamw  *                   *   1) get list of group members and send
830da6c28aaSamw  *                   *   the DATAGRAM SERVICE packet unicast
831da6c28aaSamw  *                   *   to each
832da6c28aaSamw  *                   *   2) use Group Multicast, if available
833da6c28aaSamw  *                   *   3) combination of 1) and 2)
834da6c28aaSamw  *                   *)
835da6c28aaSamw  *
836da6c28aaSamw  *                  ...
837da6c28aaSamw  *
838da6c28aaSamw  *                END
839da6c28aaSamw  *           END (* datagram service *)
840da6c28aaSamw  *
841da6c28aaSamw  *           DATAGRAM ERROR:
842da6c28aaSamw  *           BEGIN
843da6c28aaSamw  *             (*
844da6c28aaSamw  *              * Should never receive these because Datagrams
845da6c28aaSamw  *              * forwarded have source end node IP address and
846da6c28aaSamw  *              * port in NetBIOS header.
847da6c28aaSamw  *              *)
848da6c28aaSamw  *
849da6c28aaSamw  *             send DELETE NAME REQUEST with incorrect name and
850da6c28aaSamw  *                  IP address to NetBIOS Name Server;
851da6c28aaSamw  *
852da6c28aaSamw  *           END (* datagram error *)
853da6c28aaSamw  *
854da6c28aaSamw  *           DATAGRAM QUERY REQUEST:
855da6c28aaSamw  *           BEGIN
856da6c28aaSamw  *             IF can send packet to DESTINATION_NAME THEN
857da6c28aaSamw  *             BEGIN
858da6c28aaSamw  *                  (*
859da6c28aaSamw  *                   * NBDD is able to relay Datagrams for
860da6c28aaSamw  *                   * this name
861da6c28aaSamw  *                   *)
862da6c28aaSamw  *
863da6c28aaSamw  *                  send POSITIVE DATAGRAM QUERY RESPONSE to
864da6c28aaSamw  *                    REQUEST source IP address and UDP port
865da6c28aaSamw  *                    with requests DGM_ID;
866da6c28aaSamw  *             END
867da6c28aaSamw  *             ELSE
868da6c28aaSamw  *             BEGIN
869da6c28aaSamw  *                  (*
870da6c28aaSamw  *                   * NBDD is NOT able to relay Datagrams for
871da6c28aaSamw  *                   * this name
872da6c28aaSamw  *                   *)
873da6c28aaSamw  *
874da6c28aaSamw  *                  send NEGATIVE DATAGRAM QUERY RESPONSE to
875da6c28aaSamw  *                    REQUEST source IP address and UDP port
876da6c28aaSamw  *
877da6c28aaSamw  *                    with requests DGM_ID;
878da6c28aaSamw  *             END
879da6c28aaSamw  *           END (* datagram query request *)
880da6c28aaSamw  *
881da6c28aaSamw  *        END (* case *)
882da6c28aaSamw  *   END (* procedure *)
883da6c28aaSamw  */
884da6c28aaSamw 
885da6c28aaSamw 
886da6c28aaSamw /*
887da6c28aaSamw  * Function: int smb_netbios_datagram_service_daemon(void)
888da6c28aaSamw  *
889da6c28aaSamw  * Description:
890da6c28aaSamw  *
891da6c28aaSamw  * 4.4.  DATAGRAM SERVICE PACKETS
892da6c28aaSamw  *
893da6c28aaSamw  * 4.4.1.  NetBIOS DATAGRAM HEADER
894da6c28aaSamw  *
895da6c28aaSamw  *                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
896da6c28aaSamw  *    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
897da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
898da6c28aaSamw  *   |   MSG_TYPE    |     FLAGS     |           DGM_ID              |
899da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
900da6c28aaSamw  *   |                           SOURCE_IP                           |
901da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
902da6c28aaSamw  *   |          SOURCE_PORT          |          DGM_LENGTH           |
903da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
904da6c28aaSamw  *   |         PACKET_OFFSET         |
905da6c28aaSamw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
906da6c28aaSamw  *
907da6c28aaSamw  *   MSG_TYPE values (in hexidecimal):
908da6c28aaSamw  *
909da6c28aaSamw  *           10 -  DIRECT_UNIQUE DATAGRAM
910da6c28aaSamw  *           11 -  DIRECT_GROUP DATAGRAM
911da6c28aaSamw  *           12 -  BROADCAST DATAGRAM
912da6c28aaSamw  *           13 -  DATAGRAM ERROR
913da6c28aaSamw  *           14 -  DATAGRAM QUERY REQUEST
914da6c28aaSamw  *           15 -  DATAGRAM POSITIVE QUERY RESPONSE
915da6c28aaSamw  *           16 -  DATAGRAM NEGATIVE QUERY RESPONSE
916da6c28aaSamw  *
917da6c28aaSamw  *   Bit definitions of the FLAGS field:
918da6c28aaSamw  *
919da6c28aaSamw  *     0   1   2   3   4   5   6   7
920da6c28aaSamw  *   +---+---+---+---+---+---+---+---+
921da6c28aaSamw  *   | 0 | 0 | 0 | 0 |  SNT  | F | M |
922da6c28aaSamw  *   +---+---+---+---+---+---+---+---+
923da6c28aaSamw  *
924da6c28aaSamw  *   Symbol     Bit(s)   Description
925da6c28aaSamw  *
926da6c28aaSamw  *   M               7   MORE flag, If set then more NetBIOS datagram
927da6c28aaSamw  *                       fragments follow.
928da6c28aaSamw  *
929da6c28aaSamw  *   F               6   FIRST packet flag,  If set then this is first
930da6c28aaSamw  *                       (and possibly only) fragment of NetBIOS
931da6c28aaSamw  *                       datagram
932da6c28aaSamw  *
933da6c28aaSamw  *   SNT           4,5   Source End-Node type:
934da6c28aaSamw  *                          00 = B node
935da6c28aaSamw  *                          01 = P node
936da6c28aaSamw  *                          10 = M node
937da6c28aaSamw  *                          11 = NBDD
938da6c28aaSamw  *   RESERVED      0-3   Reserved, must be zero (0)
939da6c28aaSamw  *
940da6c28aaSamw  * Inputs:
941da6c28aaSamw  *	Nothing
942da6c28aaSamw  *
943da6c28aaSamw  * Returns:
944da6c28aaSamw  *	int	-> Description
945da6c28aaSamw  */
946da6c28aaSamw 
947da6c28aaSamw /*ARGSUSED*/
948da6c28aaSamw void *
949da6c28aaSamw smb_netbios_datagram_service_daemon(void *arg)
950da6c28aaSamw {
951da6c28aaSamw 	struct sockaddr_in 	sin;
952da6c28aaSamw 	struct datagram 	*datagram;
953da6c28aaSamw 	int			bytes, flag = 1;
954*7f667e74Sjose borrego 	smb_inaddr_t 		ipaddr;
955da6c28aaSamw 
956da6c28aaSamw 	(void) mutex_lock(&smb_dgq_mtx);
957da6c28aaSamw 	bzero(&smb_datagram_queue, sizeof (smb_datagram_queue));
958da6c28aaSamw 	smb_datagram_queue.forw = smb_datagram_queue.back =
959da6c28aaSamw 	    (struct datagram *)((uintptr_t)&smb_datagram_queue);
960da6c28aaSamw 	(void) mutex_unlock(&smb_dgq_mtx);
961da6c28aaSamw 
962da6c28aaSamw 	if ((datagram_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
963da6c28aaSamw 		syslog(LOG_ERR,
964da6c28aaSamw 		    "smbd: Could not create AF_INET, SOCK_DGRAM, socket");
965da6c28aaSamw 		smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_FAILED, 1);
966da6c28aaSamw 		return (0);
967da6c28aaSamw 	}
968da6c28aaSamw 
969da6c28aaSamw 	bzero(&sin, sizeof (sin));
970da6c28aaSamw 	sin.sin_family = AF_INET;
971da6c28aaSamw 	sin.sin_port = htons(DGM_SRVC_UDP_PORT);
972da6c28aaSamw 	if (bind(datagram_sock, (struct sockaddr *)&sin, sizeof (sin)) != 0) {
973da6c28aaSamw 		syslog(LOG_ERR, "smbd: Bind to name service port %d failed",
974da6c28aaSamw 		    DGM_SRVC_UDP_PORT);
975da6c28aaSamw 		(void) close(datagram_sock);
976da6c28aaSamw 		smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_FAILED, 1);
977da6c28aaSamw 		return (0);
978da6c28aaSamw 	}
979da6c28aaSamw 	(void) setsockopt(datagram_sock, SOL_SOCKET, SO_BROADCAST, &flag,
980da6c28aaSamw 	    sizeof (flag));
981da6c28aaSamw 
982da6c28aaSamw 	smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_RUNNING, 1);
983da6c28aaSamw 
984da6c28aaSamw 	while (((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) ||
985da6c28aaSamw 	    (nb_status.state & NETBIOS_BROWSER_RUNNING)) {
986da6c28aaSamw 		if ((datagram = (struct datagram *)
987da6c28aaSamw 		    malloc(sizeof (struct datagram))) == 0) {
988da6c28aaSamw 			/* Sleep for 10 sec and try again */
989da6c28aaSamw 			(void) sleep(10);
990da6c28aaSamw 			continue;
991da6c28aaSamw 		}
992da6c28aaSamw 
993da6c28aaSamw ignore:		bzero(&datagram->inaddr, sizeof (struct addr_entry));
994da6c28aaSamw 		datagram->inaddr.sinlen = sizeof (datagram->inaddr.sin);
995da6c28aaSamw 		datagram->inaddr.forw = datagram->inaddr.back =
996da6c28aaSamw 		    &datagram->inaddr;
997da6c28aaSamw 
998da6c28aaSamw 		if ((bytes = recvfrom(datagram_sock, datagram->rawbuf,
999da6c28aaSamw 		    MAX_DATAGRAM_LENGTH, 0,
1000da6c28aaSamw 		    (struct sockaddr *)&datagram->inaddr.sin,
1001da6c28aaSamw 		    &datagram->inaddr.sinlen)) < 0) {
1002da6c28aaSamw 			syslog(LOG_ERR,
1003da6c28aaSamw 			    "smbd: NETBIOS datagram - recvfrom failed");
1004da6c28aaSamw 			smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_FAILED, 1);
1005da6c28aaSamw 			break;
1006da6c28aaSamw 		}
1007da6c28aaSamw 
1008da6c28aaSamw 		/* Ignore any incoming packets from myself... */
1009*7f667e74Sjose borrego 		ipaddr.a_ipv4 = datagram->inaddr.sin.sin_addr.s_addr;
1010*7f667e74Sjose borrego 		ipaddr.a_family = AF_INET;
1011*7f667e74Sjose borrego 		if (smb_nic_exists(&ipaddr, B_FALSE)) {
1012da6c28aaSamw 			goto ignore;
1013da6c28aaSamw 		}
10147b59d02dSjb 
1015da6c28aaSamw 		if (smb_datagram_decode(datagram, bytes) < 0)
1016da6c28aaSamw 			goto ignore;
1017da6c28aaSamw 
1018da6c28aaSamw 	/*
1019da6c28aaSamw 	 * This code was doing the wrong thing with responses from a
1020da6c28aaSamw 	 * Windows2000 PDC because both DATAGRAM_FLAGS_H_NODE and
1021da6c28aaSamw 	 * DATAGRAM_FLAGS_NBDD are defined to be the same value (see
1022da6c28aaSamw 	 * netbios.h). Since the Windows2000 PDC wants to be an H-Node,
1023da6c28aaSamw 	 * we need to handle all messages via smb_netbios_BPM_datagram.
1024da6c28aaSamw 	 *
1025da6c28aaSamw 	 *	if ((datagram->flags & DATAGRAM_FLAGS_SRC_TYPE) ==
1026da6c28aaSamw 	 *	    DATAGRAM_FLAGS_NBDD)
1027da6c28aaSamw 	 *		smb_netbios_NBDD_datagram(datagram);
1028da6c28aaSamw 	 *	else
1029da6c28aaSamw 	 *		smb_netbios_BPM_datagram(datagram);
1030da6c28aaSamw 	 */
1031da6c28aaSamw 
1032da6c28aaSamw 		smb_netbios_BPM_datagram(datagram);
1033da6c28aaSamw 	}
1034da6c28aaSamw 
1035da6c28aaSamw 	smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_RUNNING, 0);
1036da6c28aaSamw 
1037da6c28aaSamw 	(void) mutex_lock(&nb_status.mtx);
1038da6c28aaSamw 	while (nb_status.state & NETBIOS_BROWSER_RUNNING)
1039da6c28aaSamw 		(void) cond_wait(&nb_status.cv, &nb_status.mtx);
1040da6c28aaSamw 	(void) mutex_unlock(&nb_status.mtx);
1041da6c28aaSamw 
1042da6c28aaSamw 	(void) close(datagram_sock);
1043da6c28aaSamw 	smb_netbios_datagram_fini();
1044da6c28aaSamw 	syslog(LOG_DEBUG, "smbd: Netbios Datagram Service is down\n");
1045da6c28aaSamw 	return (0);
1046da6c28aaSamw }
1047da6c28aaSamw 
1048da6c28aaSamw static char
1049da6c28aaSamw /* LINTED - E_STATIC_UNUSED */
1050da6c28aaSamw nb_fmt_flags(unsigned char flags)
1051da6c28aaSamw {
1052da6c28aaSamw 	switch (flags & DATAGRAM_FLAGS_SRC_TYPE) {
1053da6c28aaSamw 	case DATAGRAM_FLAGS_B_NODE:	return ('B');
1054da6c28aaSamw 	case DATAGRAM_FLAGS_P_NODE:	return ('P');
1055da6c28aaSamw 	case DATAGRAM_FLAGS_M_NODE:	return ('M');
1056da6c28aaSamw 	case DATAGRAM_FLAGS_H_NODE:	return ('H');
1057da6c28aaSamw 	default:	return ('?');
1058da6c28aaSamw 	}
1059da6c28aaSamw }
1060