// $Id: NetbiosSSN.h,v 1.6 2003/08/31 00:38:11 vern Exp $
//
// Copyright (c) 2001, 2002
//      The Regents of the University of California.  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that: (1) source code distributions
// retain the above copyright notice and this paragraph in its entirety, (2)
// distributions including binary code include the above copyright notice and
// this paragraph in its entirety in the documentation or other materials
// provided with the distribution, and (3) all advertising materials mentioning
// features or use of this software display the following acknowledgement:
// ``This product includes software developed by the University of California,
// Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
// the University nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#ifndef netbios_ssn_h
#define netbios_ssn_h

#include "UDP.h"
#include "TCP.h"


typedef enum {
	NETBIOS_SSN_MSG = 0x0,
	NETBIOS_SSN_REQ = 0x81,
	NETBIOS_SSN_POS_RESP = 0x82,
	NETBIOS_SSN_NEG_RESP = 0x83,
	NETBIOS_SSN_RETARG_RESP = 0x84,
	NETBIOS_SSN_KEEP_ALIVE = 0x85,
} NetbiosSSN_Opcode;

struct NetbiosSSN_RawMsgHdr {
	NetbiosSSN_RawMsgHdr(const u_char*& data, int& len);

	unsigned int type:8;
	unsigned int flags:8;
	unsigned int length:16;
};

class NetbiosSSN_Interpreter {
public:
	NetbiosSSN_Interpreter(Connection* conn);

	int ParseMessage(unsigned int type, unsigned int flags,
			const u_char* data, int len, int is_query);

	// Version used when data points to type/flags/length.
	int ParseMessage(const u_char* data, int len, int is_query);

	void Timeout()	{ }

	Connection* Conn() const		{ return conn; }
	TCP_Connection* TCP_Conn() const	{ return (TCP_Connection*) conn; }

protected:
	int ParseSessionMsg(const u_char* data, int len, int is_query);
	int ParseSessionReq(const u_char* data, int len, int is_query);
	int ParseSessionPosResp(const u_char* data, int len, int is_query);
	int ParseSessionNegResp(const u_char* data, int len, int is_query);
	int ParseRetArgResp(const u_char* data, int len, int is_query);
	int ParseKeepAlive(const u_char* data, int len, int is_query);

	int ParseSambaMsg(const u_char* data, int len, int is_query);

	void Event(EventHandlerPtr event, const u_char* data, int len);

	// Pass in name/length, returns in xname/xlen the converted
	// name/length.  Returns 0 on failure; xname may still be
	// allocated and hold partial results at that point.
	int ConvertName(const u_char* name, int name_len,
			u_char*& xname, int& xlen);

protected:
	Connection* conn;
};


typedef enum {
	NETBIOS_SSN_TYPE,	// looking for type field
	NETBIOS_SSN_FLAGS,	// looking for flag field
	NETBIOS_SSN_LEN_HI,	// looking for high-order byte of length
	NETBIOS_SSN_LEN_LO,	// looking for low-order byte of length
	NETBIOS_SSN_BUF,	// building up the message in the buffer
} NetbiosSSN_State;

// ### This should be merged with TCP_Endpoint_RPC, TCP_Endpoint_DNS.
class TCP_Endpoint_NetbiosSSN : public TCP_EndpointContents {
public:
	TCP_Endpoint_NetbiosSSN(NetbiosSSN_Interpreter* interp, int is_orig);
	~TCP_Endpoint_NetbiosSSN();

	void Flush();	// process any partially-received data

	NetbiosSSN_State State() const		{ return state; }

protected:
	void Deliver(double t, int seq, int len, u_char* data);

	NetbiosSSN_Interpreter* interp;

	unsigned int type;
	unsigned int flags;

	u_char* msg_buf;
	int buf_n;	// number of bytes in msg_buf
	int buf_len;	// size of msg_buf
	int msg_size;	// expected size of message

	NetbiosSSN_State state;
	int is_orig;
};

class TCP_NetbiosSSN : public TCP_Connection {
public:
	TCP_NetbiosSSN(NetSessions* s, HashKey* k, double t, const ConnID* id,
			const struct tcphdr* tp);
	~TCP_NetbiosSSN();
	void Done();

protected:
	void BuildEndpoints();

	void ConnectionClosed(TCP_Endpoint* endpoint,
				TCP_Endpoint* peer, int gen_event);

	NetbiosSSN_Interpreter* interp;
};

class UDP_NetbiosSSN : public UDP_Connection {
public:
	UDP_NetbiosSSN(NetSessions* s, HashKey* k, double t, const ConnID* id,
		const struct udphdr* up);
	~UDP_NetbiosSSN();
	void Done();

protected:
	int Request(double t, const u_char* data, int len);
	int Reply(double t, const u_char* data, int len);

	void ExpireTimer(double t);

	int IsReuse(double t, const u_char* pkt);

	NetbiosSSN_Interpreter* interp;
	int did_session_done;
};

#endif
