#ifndef _SMB_NETBIOS_H_
#define _SMB_NETBIOS_H_
#include <stdio.h>
#include <synch.h>
#include <pthread.h>
#include <strings.h>
#include <netinet/in.h>
#include <smbsrv/libsmbns.h>
#include <smbsrv/smbinfo.h>
#include <smbsrv/netbios.h>
#define QUEUE_INSERT_TAIL(q, e) \
((e)->back) = (void *)((q)->back); \
((e)->forw) = (void *)(q); \
((q)->back->forw) = (void *)(e); \
((q)->back) = (void *)(e);
#define QUEUE_CLIP(e) \
(e)->forw->back = (e)->back; \
(e)->back->forw = (e)->forw; \
(e)->forw = 0; \
(e)->back = 0;
typedef enum {
NETBIOS_EVENT_START = 0,
NETBIOS_EVENT_STOP,
NETBIOS_EVENT_RESET,
NETBIOS_EVENT_NS_START,
NETBIOS_EVENT_NS_STOP,
NETBIOS_EVENT_DGM_START,
NETBIOS_EVENT_DGM_STOP,
NETBIOS_EVENT_BROWSER_START,
NETBIOS_EVENT_BROWSER_STOP,
NETBIOS_EVENT_TIMER_START,
NETBIOS_EVENT_TIMER_STOP,
NETBIOS_EVENT_ERROR,
NETBIOS_EVENT_DUMP
} netbios_event_t;
typedef enum {
NETBIOS_STATE_INIT = 0,
NETBIOS_STATE_RUNNING,
NETBIOS_STATE_CLOSING,
NETBIOS_STATE_ERROR
} netbios_state_t;
typedef struct {
pthread_t s_tid;
boolean_t s_up;
} netbios_svc_t;
typedef struct {
mutex_t nbs_mtx;
cond_t nbs_cv;
netbios_svc_t nbs_ns;
netbios_svc_t nbs_dgm;
netbios_svc_t nbs_browser;
netbios_svc_t nbs_timer;
netbios_state_t nbs_state;
uint32_t nbs_errors;
char *nbs_last_event;
} netbios_service_t;
extern char smb_node_type;
#define SMB_NODETYPE_B 'B'
#define SMB_NODETYPE_P 'P'
#define SMB_NODETYPE_M 'M'
#define SMB_NODETYPE_H 'H'
#define ADDR_FLAG_INVALID 0x0000
#define ADDR_FLAG_VALID 0x0001
typedef struct addr_entry {
struct addr_entry *forw;
struct addr_entry *back;
uint32_t attributes;
uint32_t conflict_timer;
uint32_t refresh_ttl;
uint32_t ttl;
struct sockaddr_in sin;
int sinlen;
uint32_t flags;
} addr_entry_t;
typedef struct name_entry {
struct name_entry *forw;
struct name_entry *back;
unsigned char name[NETBIOS_NAME_SZ];
unsigned char scope[NETBIOS_DOMAIN_NAME_MAX];
unsigned short attributes;
struct addr_entry addr_list;
mutex_t mtx;
} name_entry_t;
struct name_question {
struct name_entry *name;
unsigned question_type;
unsigned question_class;
};
struct resource_record {
struct name_entry *name;
unsigned short rr_type;
unsigned short rr_class;
uint32_t ttl;
unsigned short rdlength;
unsigned char *rdata;
};
struct name_packet {
unsigned short name_trn_id;
unsigned short info;
unsigned qdcount;
unsigned ancount;
unsigned nscount;
unsigned arcount;
struct name_question *question;
struct resource_record *answer;
struct resource_record *authority;
struct resource_record *additional;
unsigned char block_data[4];
};
#define NAME_OPCODE_R 0x8000
#define NAME_OPCODE_OPCODE_MASK 0x7800
#define NAME_OPCODE_QUERY 0x0000
#define NAME_OPCODE_REGISTRATION 0x2800
#define NAME_OPCODE_RELEASE 0x3000
#define NAME_OPCODE_WACK 0x3800
#define NAME_OPCODE_REFRESH 0x4000
#define NAME_OPCODE_MULTIHOME 0x7800
#define NAME_NM_FLAGS_AA 0x0400
#define NAME_NM_FLAGS_TC 0x0200
#define NAME_NM_FLAGS_RD 0x0100
#define NAME_NM_FLAGS_RA 0x0080
#define NAME_NM_FLAGS_x2 0x0040
#define NAME_NM_FLAGS_x1 0x0020
#define NAME_NM_FLAGS_B 0x0010
#define NAME_RCODE_MASK 0x000f
#define RCODE_FMT_ERR 0x0001
#define RCODE_SRV_ERR 0x0002
#define RCODE_NAM_ERR 0x0003
#define RCODE_IMP_ERR 0x0004
#define RCODE_RFS_ERR 0x0005
#define RCODE_ACT_ERR 0x0006
#define RCODE_CFT_ERR 0x0007
#define NM_FLAGS_UNICAST 0
#define NM_FLAGS_BROADCAST NAME_NM_FLAGS_B
#define PACKET_TYPE(x) ((x) & (NAME_OPCODE_R | NAME_OPCODE_OPCODE_MASK | \
NAME_NM_FLAGS_AA | NAME_NM_FLAGS_RD))
#define RCODE(x) ((x) & NAME_RCODE_MASK)
#define POSITIVE_RESPONSE(x) (RCODE(x) == 0)
#define NEGATIVE_RESPONSE(x) (RCODE(x) != 0)
#define END_NODE_CHALLENGE_REGISTRATION_REQUEST \
(NAME_OPCODE_REGISTRATION | NAME_NM_FLAGS_AA | NAME_NM_FLAGS_RD)
#define END_NODE_CHALLENGE_NAME_REGISTRATION_RESPONSE \
(NAME_OPCODE_R | END_NODE_CHALLENGE_REGISTRATION_REQUEST)
#define NAME_QUERY_REQUEST \
(NAME_OPCODE_QUERY | NAME_NM_FLAGS_RD)
#define NAME_QUERY_RESPONSE \
(NAME_OPCODE_R | NAME_QUERY_REQUEST | \
NAME_NM_FLAGS_AA | NAME_NM_FLAGS_RD)
#define NODE_STATUS_REQUEST \
(NAME_OPCODE_QUERY)
#define NODE_STATUS_RESPONSE \
(NAME_OPCODE_R | NODE_STATUS_REQUEST | NAME_NM_FLAGS_AA)
#define REDIRECT_NAME_QUERY_RESPONSE \
(NAME_OPCODE_R | NAME_QUERY_REQUEST | NAME_NM_FLAGS_RD)
#define NAME_REFRESH_REQUEST \
(NAME_OPCODE_REFRESH)
#define NAME_REGISTRATION_REQUEST \
(NAME_OPCODE_REGISTRATION | NAME_NM_FLAGS_RD)
#define NAME_MULTIHOME_REGISTRATION_REQUEST \
(NAME_OPCODE_MULTIHOME | NAME_NM_FLAGS_RD)
#define NAME_REGISTRATION_RESPONSE \
(NAME_OPCODE_R | NAME_REGISTRATION_REQUEST | NAME_NM_FLAGS_AA)
#define NAME_RELEASE_REQUEST \
(NAME_OPCODE_RELEASE)
#define NAME_RELEASE_RESPONSE \
(NAME_OPCODE_R | NAME_RELEASE_REQUEST | NAME_NM_FLAGS_AA)
#define WACK_RESPONSE \
(NAME_OPCODE_R | NAME_OPCODE_WACK | NAME_NM_FLAGS_AA)
#define NAME_QUESTION_TYPE_NB 0x0020
#define NAME_QUESTION_TYPE_NBSTAT 0x0021
#define NAME_QUESTION_CLASS_IN 0x0001
#define NAME_RR_TYPE_A 0x0001
#define NAME_RR_TYPE_NS 0x0002
#define NAME_RR_TYPE_NULL 0x000A
#define NAME_RR_TYPE_NB 0x0020
#define NAME_RR_TYPE_NBSTAT 0x0021
#define NAME_RR_CLASS_IN 0x0001
#define NAME_NB_FLAGS_ONT_MASK (3<<13)
#define NAME_NB_FLAGS_ONT_B (0<<13)
#define NAME_NB_FLAGS_ONT_P (1<<13)
#define NAME_NB_FLAGS_ONT_M (2<<13)
#define NAME_NB_FLAGS_ONT_resv (3<<13)
#define NAME_NB_FLAGS_G (1<<15)
#define UNICAST 0
#define BROADCAST 1
#define POINTCAST 2
#define NAME_ATTR_UNIQUE 0x0000
#define NAME_ATTR_GROUP 0x8000
#define NAME_ATTR_OWNER_NODE_TYPE 0x6000
#define NAME_ATTR_OWNER_TYPE_BNODE 0x0000
#define NAME_ATTR_OWNER_TYPE_PNODE 0x2000
#define NAME_ATTR_OWNER_TYPE_MNODE 0x4000
#define NAME_ATTR_OWNER_TYPE_HNODE 0x6000
#define NAME_ATTR_DEREGISTER 0x1000
#define NAME_ATTR_CONFLICT 0x0800
#define NAME_ATTR_ACTIVE_NAME 0x0400
#define NAME_ATTR_PERMANENT 0x0200
#define NAME_ATTR_RESERVED 0x01FF
#define NAME_ATTR_LOCAL 0x0001
#define NODE_TYPE(x) ((x) & NAME_ATTR_OWNER_NODE_TYPE))
#define IS_BNODE(x) (NODE_TYPE(x) == NAME_ATTR_OWNER_TYPE_BNODE)
#define IS_PNODE(x) (NODE_TYPE(x) == NAME_ATTR_OWNER_TYPE_PNODE)
#define IS_MNODE(x) (NODE_TYPE(x) == NAME_ATTR_OWNER_TYPE_MNODE)
#define IS_HNODE(x) (NODE_TYPE(x) == NAME_ATTR_OWNER_TYPE_HNODE)
#define IS_UNIQUE(x) (((x) & NAME_ATTR_GROUP) == 0)
#define IS_GROUP(x) (((x) & NAME_ATTR_GROUP) != 0)
#define IS_PERMANENT(x) (((x) & NAME_ATTR_PERMANENT) != 0)
#define IS_CONFLICTING(x) (((x) & NAME_ATTR_CONFLICT) != 0)
#define IS_ACTIVE(x) (((x) & NAME_ATTR_ACTIVE) != 0)
#define IS_DEGREGISTERED(x) (((x) & NAME_ATTR_ACTIVE) != 0)
#define IS_LOCAL(x) (((x) & NAME_ATTR_LOCAL) != 0)
#define IS_PUBLIC(x) (((x) & NAME_ATTR_LOCAL) == 0)
#define PUBLIC_BITS(x) ((x) & ~NAME_ATTR_RESERVED)
#define SAME_SCOPE(scope, e) (strcmp((scope), ((e)->scope)) == 0)
typedef struct {
unsigned char unit_id[6];
unsigned char jumpers;
unsigned char test_result;
unsigned short version_number;
unsigned short statistical_period;
unsigned short crc_errors;
unsigned short alignment_errors;
unsigned short collisions;
unsigned short send_aborts;
unsigned int good_sends;
unsigned int good_receives;
unsigned short retransmits;
unsigned short no_resource_conditions;
unsigned short free_command_blocks;
unsigned short total_command_blocks;
unsigned short max_total_command_blocks;
unsigned short pending_sessions;
unsigned short max_pending_sessions;
unsigned short total_possible_sessions;
unsigned short session_data_packet_size;
} node_status_response;
typedef struct {
unsigned char msg_type;
unsigned char flags;
unsigned short dgm_id;
uint32_t source_ip;
unsigned short source_port;
unsigned short dgm_length;
unsigned short packet_offset;
} datagram_header;
#define DATAGRAM_TYPE_DIRECT_UNIQUE 0x10
#define DATAGRAM_TYPE_DIRECT_GROUP 0x11
#define DATAGRAM_TYPE_BROADCAST 0x12
#define DATAGRAM_TYPE_ERROR_DATAGRAM 0x13
#define DATAGRAM_TYPE_QUERY_REQUEST 0x14
#define DATAGRAM_TYPE_POSITIVE_RESPONSE 0x15
#define DATAGRAM_TYPE_NEGATIVE_RESPONSE 0x16
#define DATAGRAM_FLAGS_MORE 0x01
#define DATAGRAM_FLAGS_FIRST 0x02
#define DATAGRAM_FLAGS_SRC_TYPE 0x0c
#define DATAGRAM_FLAGS_B_NODE 0x00
#define DATAGRAM_FLAGS_P_NODE 0x04
#define DATAGRAM_FLAGS_M_NODE 0x08
#define DATAGRAM_FLAGS_H_NODE 0x0C
#define DATAGRAM_FLAGS_NBDD 0x0c
#define DATAGRAM_FLAGS_RESERVED 0xf0
typedef struct {
datagram_header header;
unsigned char *source_name;
unsigned char *destination_name;
unsigned char *user_data;
} datagram_packet;
typedef struct {
unsigned char msg_type;
unsigned char flags;
unsigned short dgm_id;
uint32_t source_ip;
unsigned short source_port;
unsigned char error;
} datagram_error_packet;
typedef struct datagram_query_packet {
unsigned char msg_type;
unsigned char flags;
unsigned short dgm_id;
uint32_t source_ip;
unsigned short source_port;
unsigned char destination_name[MAX_NAME_LENGTH];
} datagram_query_packet;
typedef struct datagram {
struct datagram *forw;
struct datagram *back;
struct addr_entry inaddr;
int discard_timer;
unsigned char packet_type;
unsigned char flags;
unsigned short datagram_id;
struct name_entry src;
struct name_entry dest;
unsigned short offset;
unsigned short data_length;
unsigned char *data;
unsigned int rawbytes;
unsigned char rawbuf[MAX_DATAGRAM_LENGTH];
} datagram;
typedef struct datagram_queue {
struct datagram *forw;
struct datagram *back;
} datagram_queue;
typedef struct name_queue {
struct name_entry head;
mutex_t mtx;
} name_queue_t;
typedef struct nbcache_iter {
HT_ITERATOR nbc_hti;
struct name_entry *nbc_entry;
} nbcache_iter_t;
#define NETBIOS_EMPTY_NAME (unsigned char *)""
#define NETBIOS_NAME_IS_STAR(name) \
(bcmp(name, "*\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", NETBIOS_NAME_SZ) == 0)
void smb_netbios_event(netbios_event_t);
void smb_netbios_wait(netbios_event_t);
void smb_netbios_sleep(time_t);
boolean_t smb_netbios_running(void);
boolean_t smb_netbios_error(void);
int smb_netbios_cache_init(void);
void smb_netbios_cache_fini(void);
void smb_netbios_cache_dump(FILE *fp);
int smb_netbios_cache_count(void);
void smb_netbios_cache_clean(void);
void smb_netbios_cache_reset_ttl(void);
void smb_netbios_cache_delete_locals(name_queue_t *);
void smb_netbios_cache_refresh(name_queue_t *);
int smb_netbios_cache_insert(struct name_entry *name);
int smb_netbios_cache_insert_list(struct name_entry *name);
void smb_netbios_cache_delete(struct name_entry *name);
int smb_netbios_cache_delete_addr(struct name_entry *name);
struct name_entry *smb_netbios_cache_lookup(struct name_entry *name);
struct name_entry *smb_netbios_cache_lookup_addr(struct name_entry *name);
void smb_netbios_cache_update_entry(struct name_entry *, struct name_entry *);
void smb_netbios_cache_unlock_entry(struct name_entry *);
unsigned char *smb_netbios_cache_status(unsigned char *, int, unsigned char *);
int smb_netbios_cache_getfirst(nbcache_iter_t *);
int smb_netbios_cache_getnext(nbcache_iter_t *);
void smb_netbios_name_dump(FILE *fp, struct name_entry *entry);
void smb_netbios_name_logf(struct name_entry *entry);
void smb_netbios_name_freeaddrs(struct name_entry *entry);
struct name_entry *smb_netbios_name_dup(struct name_entry *, int);
void *smb_netbios_name_service(void *);
void smb_init_name_struct(unsigned char *, char, unsigned char *, uint32_t,
unsigned short, uint32_t, uint32_t, struct name_entry *);
struct name_entry *smb_name_find_name(struct name_entry *name);
int smb_name_add_name(struct name_entry *name);
int smb_name_delete_name(struct name_entry *name);
void smb_name_unlock_name(struct name_entry *name);
void smb_netbios_name_config(void);
void smb_netbios_name_unconfig(void);
void smb_netbios_name_tick(void);
int smb_first_level_name_encode(struct name_entry *, unsigned char *, int);
int smb_first_level_name_decode(unsigned char *, struct name_entry *);
void smb_encode_netbios_name(unsigned char *, char, unsigned char *,
struct name_entry *);
void *smb_netbios_datagram_service(void *);
int smb_netbios_datagram_send(struct name_entry *,
struct name_entry *, unsigned char *, int);
void smb_netbios_datagram_tick(void);
void *smb_browser_dispatch(void *arg);
void *smb_browser_service(void *);
int smb_browser_load_transact_header(unsigned char *, int, int, int, char *);
void smb_netlogon_receive(struct datagram *, char *, unsigned char *, int);
void smb_netlogon_request(struct name_entry *, char *);
#endif