/* * Copyright (C) 2005 Alfresco, Inc. * * Licensed under the Mozilla Public License version 1.1 * with a permitted attribution clause. You may obtain a * copy of the License at * * http://www.alfresco.org/legal/license.txt * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific * language governing permissions and limitations under the * License. */ package org.alfresco.filesys.netbios; import org.alfresco.filesys.util.DataPacker; import org.alfresco.filesys.util.HexDump; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * NetBIOS Packet Class */ public class NetBIOSPacket { private static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.netbios"); // Minimum valid receive length public static final int MIN_RXLEN = 4; // NetBIOS opcodes public static final int NAME_QUERY = 0x00; public static final int NAME_REGISTER = 0x05; public static final int NAME_RELEASE = 0x06; public static final int WACK = 0x07; public static final int REFRESH = 0x08; public static final int NAME_REGISTER_MULTI = 0x0F; public static final int RESP_QUERY = 0x10; public static final int RESP_REGISTER = 0x15; public static final int RESP_RELEASE = 0x16; // NetBIOS opcode masks public static final int MASK_OPCODE = 0xF800; public static final int MASK_NMFLAGS = 0x07F0; public static final int MASK_RCODE = 0x000F; public static final int MASK_NOOPCODE = 0x07FF; public static final int MASK_NOFLAGS = 0xF80F; public static final int MASK_NORCODE = 0xFFF0; public static final int MASK_RESPONSE = 0x0010; // Flags bit values public static final int FLG_BROADCAST = 0x0001; public static final int FLG_RECURSION = 0x0008; public static final int FLG_RECURSDES = 0x0010; public static final int FLG_TRUNCATION = 0x0020; public static final int FLG_AUTHANSWER = 0x0040; // NetBIOS name lookup types public static final int NAME_TYPE_NB = 0x0020; public static final int NAME_TYPE_NBSTAT = 0x0021; // RFC NetBIOS encoded name length public static final int NAME_LEN = 32; // NetBIOS name classes public static final int NAME_CLASS_IN = 0x0001; // Bit shifts for opcode/flags values private static final int SHIFT_FLAGS = 4; private static final int SHIFT_OPCODE = 11; // Default NetBIOS buffer size to allocate public static final int DEFAULT_BUFSIZE = 1024; // NetBIOS packet offsets private static final int NB_TRANSID = 0; private static final int NB_OPCODE = 2; private static final int NB_QDCOUNT = 4; private static final int NB_ANCOUNT = 6; private static final int NB_NSCOUNT = 8; private static final int NB_ARCOUNT = 10; private static final int NB_DATA = 12; // NetBIOS name registration error reponse codes (RCODE field) public static final int FMT_ERR = 0x01; public static final int SRV_ERR = 0x02; public static final int IMP_ERR = 0x04; public static final int RFS_ERR = 0x05; public static final int ACT_ERR = 0x06; public static final int CFT_ERR = 0x07; // Name flags public static final int NAME_PERM = 0x02; public static final int NAME_ACTIVE = 0x04; public static final int NAME_CONFLICT = 0x08; public static final int NAME_DEREG = 0x10; public static final int NAME_GROUP = 0x80; // NetBIOS packet buffer private byte[] m_nbbuf; // Actual used packet length private int m_datalen; /** * Default constructor */ public NetBIOSPacket() { m_nbbuf = new byte[DEFAULT_BUFSIZE]; m_datalen = NB_DATA; } /** * Create a NetBIOS packet with the specified buffer. * * @param buf byte[] */ public NetBIOSPacket(byte[] buf) { m_nbbuf = buf; m_datalen = NB_DATA; } /** * Create a NetBIOS packet with the specified buffer size. * * @param siz int */ public NetBIOSPacket(int siz) { m_nbbuf = new byte[siz]; m_datalen = NB_DATA; } /** * Dump the packet structure to the console. * * @param sessPkt True if this is a NetBIOS session packet, else false. */ public void DumpPacket(boolean sessPkt) { // Display the transaction id logger.debug("NetBIOS Packet Dump :-"); // Detrmine the packet type if (sessPkt == true) { switch (getPacketType()) { // NetBIOS session request case RFCNetBIOSProtocol.SESSION_REQUEST: StringBuffer name = new StringBuffer(); for (int i = 0; i < 32; i++) name.append((char) m_nbbuf[39 + i]); logger.debug("Session request from " + NetBIOSSession.DecodeName(name.toString())); break; // NetBIOS message case RFCNetBIOSProtocol.SESSION_MESSAGE: break; } } else { // Display the packet type logger.debug(" Transaction Id : " + getTransactionId()); String opCode = null; switch (getOpcode()) { case NAME_QUERY: opCode = "QUERY"; break; case RESP_QUERY: opCode = "QUERY (Response)"; break; case NAME_REGISTER: opCode = "NAME REGISTER"; break; case RESP_REGISTER: opCode = "NAME REGISTER (Response)"; break; case NAME_RELEASE: opCode = "NAME RELEASE"; break; case RESP_RELEASE: opCode = "NAME RELEASE (Response)"; break; case WACK: opCode = "WACK"; break; case REFRESH: opCode = "REFRESH"; break; default: opCode = Integer.toHexString(getOpcode()); break; } logger.debug(" Opcode : " + opCode); // Display the flags logger.debug(" Flags : " + Integer.toHexString(getFlags())); // Display the name counts logger.debug(" QDCount : " + getQuestionCount()); logger.debug(" ANCount : " + getAnswerCount()); logger.debug(" NSCount : " + getNameServiceCount()); logger.debug(" ARCount : " + getAdditionalCount()); // Dump the question name, if there is one if (getQuestionCount() > 0) { // Get the encoded name string StringBuffer encName = new StringBuffer(); for (int i = 1; i <= 32; i++) encName.append((char) m_nbbuf[NB_DATA + i]); // Decode the name String name = NetBIOSSession.DecodeName(encName.toString()); logger.debug(" QName : " + name + " <" + NetBIOSName.TypeAsString(name.charAt(15)) + ">"); } } // Dump the raw data logger.debug("********** Raw NetBIOS Data Dump **********"); HexDump.Dump(getBuffer(), getLength(), 0); } /** * Get the additional byte count. * * @return int */ public final int getAdditionalCount() { return DataPacker.getShort(m_nbbuf, NB_ARCOUNT); } /** * Get the answer name details * * @return String */ public final String getAnswerName() { // Pack the encoded name into the NetBIOS packet return NetBIOSSession.DecodeName(m_nbbuf, NB_DATA + 1); } /** * Get the answer count. * * @return int */ public final int getAnswerCount() { return DataPacker.getShort(m_nbbuf, NB_ANCOUNT); } /** * Get the answer name list * * @return NetBIOSNameList */ public final NetBIOSNameList getAnswerNameList() { // Check if there are any answer names int cnt = getAnswerCount(); if (cnt == 0) return null; NetBIOSNameList nameList = new NetBIOSNameList(); int pos = NB_DATA; while (cnt-- > 0) { // Get a NetBIOS name from the buffer int nameLen = NetBIOSName.decodeNetBIOSNameLength(m_nbbuf, pos); NetBIOSName name = NetBIOSName.decodeNetBIOSName(m_nbbuf, pos); // Skip the type, class and TTL pos += nameLen; pos += 8; // Get the count of data bytes int dataCnt = DataPacker.getShort(m_nbbuf, pos); pos += 2; while (dataCnt > 0) { // Get the flags, check if the name is a unique or group name int flags = DataPacker.getShort(m_nbbuf, pos); pos += 2; if ((flags & NAME_GROUP) != 0) name.setGroup(true); // Get the IP address and add to the list of addresses for the current name byte[] ipaddr = new byte[4]; for (int i = 0; i < 4; i++) ipaddr[i] = m_nbbuf[pos++]; name.addIPAddress(ipaddr); // Update the data count dataCnt -= 6; } // Add the name to the name list nameList.addName(name); } // Return the name list return nameList; } /** * Get the answer name list from an adapter status reply * * @return NetBIOSNameList */ public final NetBIOSNameList getAdapterStatusNameList() { // Check if there are any answer names int cnt = getAnswerCount(); if (cnt == 0) return null; NetBIOSNameList nameList = new NetBIOSNameList(); int pos = NB_DATA; // Skip the initial name int nameLen = (int) (m_nbbuf[pos++] & 0xFF); pos += nameLen; pos = DataPacker.wordAlign(pos); pos += 8; // Get the count of data bytes and name count int dataCnt = DataPacker.getShort(m_nbbuf, pos); pos += 2; int nameCnt = (int) (m_nbbuf[pos++] & 0xFF); while (nameCnt > 0 && dataCnt > 0) { // Get the NetBIOS name/type NetBIOSName nbName = new NetBIOSName(m_nbbuf, pos); pos += 16; // Get the name type flags, check if this is a unique or group name int typ = DataPacker.getShort(m_nbbuf, pos); pos += 2; if ((typ & NAME_GROUP) != 0) nbName.setGroup(true); // Add the name to the list nameList.addName(nbName); // Update the data count and name count dataCnt -= 18; nameCnt--; } // Return the name list return nameList; } /** * Return the NetBIOS buffer. * * @return byte[] */ public final byte[] getBuffer() { return m_nbbuf; } /** * Get the flags from the received NetBIOS packet. * * @return int */ public final int getFlags() { int flags = DataPacker.getShort(m_nbbuf, NB_QDCOUNT) & MASK_NMFLAGS; flags = flags >> SHIFT_FLAGS; return flags; } /** * Return the NetBIOS header flags value. * * @return int */ public final int getHeaderFlags() { return m_nbbuf[1] & 0x00FF; } /** * Return the NetBIOS header data length value. * * @return int */ public final int getHeaderLength() { return DataPacker.getIntelShort(m_nbbuf, 2) & 0xFFFF; } /** * Return the NetBIOS header message type. * * @return int */ public final int getHeaderType() { return m_nbbuf[0] & 0x00FF; } /** * Return the received packet length. * * @return int */ public final int getLength() { return m_datalen; } /** * Return the name service count. * * @return int */ public final int getNameServiceCount() { return DataPacker.getShort(m_nbbuf, NB_NSCOUNT); } /** * Return the NetBIOS opcode. * * @return int */ public final int getOpcode() { int op = DataPacker.getShort(m_nbbuf, NB_OPCODE) & MASK_OPCODE; op = op >> SHIFT_OPCODE; return op; } /** * Return the NetBIOS packet type. * * @return int */ public final int getPacketType() { return (int) (m_nbbuf[0] & 0xFF); } /** * Return the question count. * * @return int */ public final int getQuestionCount() { return DataPacker.getShort(m_nbbuf, NB_QDCOUNT); } /** * Get the question name. */ public final String getQuestionName() { // Pack the encoded name into the NetBIOS packet return NetBIOSSession.DecodeName(m_nbbuf, NB_DATA + 1); } /** * Get the question name length. */ public final int getQuestionNameLength() { // Pack the encoded name into the NetBIOS packet return (int) m_nbbuf[NB_DATA] & 0xFF; } /** * Return the result code for the received packet. * * @return int */ public final int getResultCode() { int res = DataPacker.getShort(m_nbbuf, NB_OPCODE) & MASK_RCODE; return res; } /** * Return the NetBIOS transaction id. * * @return int */ public final int getTransactionId() { return DataPacker.getShort(m_nbbuf, NB_TRANSID); } /** * Determine if the received packet is a repsonse packet. * * @return boolean */ public final boolean isResponse() { if ((getOpcode() & MASK_RESPONSE) != 0) return true; return false; } /** * Set the additional byte count. * * @param cnt int */ public final void setAdditionalCount(int cnt) { DataPacker.putShort((short) cnt, m_nbbuf, NB_ARCOUNT); } /** * Set the answer byte count. * * @param cnt int */ public final void setAnswerCount(int cnt) { DataPacker.putShort((short) cnt, m_nbbuf, NB_ANCOUNT); } /** * Set the answer name. * * @param name java.lang.String * @param qtyp int * @param qcls int */ public final int setAnswerName(String name, char ntyp, int qtyp, int qcls) { // RFC encode the NetBIOS name string String encName = NetBIOSSession.ConvertName(name, ntyp); byte[] nameByts = encName.getBytes(); // Pack the encoded name into the NetBIOS packet int pos = NB_DATA; m_nbbuf[pos++] = (byte) NAME_LEN; for (int i = 0; i < 32; i++) m_nbbuf[pos++] = nameByts[i]; m_nbbuf[pos++] = 0x00; // Set the name type and class DataPacker.putShort((short) qtyp, m_nbbuf, pos); pos += 2; DataPacker.putShort((short) qcls, m_nbbuf, pos); pos += 2; // Set the packet length if (pos > m_datalen) setLength(pos); return pos; } /** * Set the flags. * * @param flg int */ public final void setFlags(int flg) { int val = DataPacker.getShort(m_nbbuf, NB_OPCODE) & MASK_NOFLAGS; val += (flg << SHIFT_FLAGS); DataPacker.putShort((short) val, m_nbbuf, NB_OPCODE); } /** * Set the NetBIOS packet header flags value. * * @param flg int */ public final void setHeaderFlags(int flg) { m_nbbuf[1] = (byte) (flg & 0x00FF); } /** * Set the NetBIOS packet data length in the packet header. * * @param len int */ public final void setHeaderLength(int len) { DataPacker.putIntelShort(len, m_nbbuf, 2); } /** * Set the NetBIOS packet type in the packet header. * * @param typ int */ public final void setHeaderType(int typ) { m_nbbuf[0] = (byte) (typ & 0x00FF); } /** * Set the IP address. * * @return int * @param off int * @param ipaddr byte[] */ public final int setIPAddress(int off, byte[] ipaddr) { // Pack the IP address for (int i = 0; i < 4; i++) m_nbbuf[off + i] = ipaddr[i]; // Set the packet length int pos = off + 4; if (pos > m_datalen) setLength(pos); // Return the new packet offset return pos; } /** * Set the packet data length. * * @param len int */ public final void setLength(int len) { m_datalen = len; } /** * Set the name registration flags. * * @return int * @param off int * @param flg int */ public final int setNameRegistrationFlags(int off, int flg) { // Set the name registration flags DataPacker.putShort((short) 0x0006, m_nbbuf, off); DataPacker.putShort((short) flg, m_nbbuf, off + 2); // Set the packet length int pos = off + 4; if (pos > m_datalen) setLength(pos); // Return the new packet offset return pos; } /** * Set the name service count. * * @param cnt int */ public final void setNameServiceCount(int cnt) { DataPacker.putShort((short) cnt, m_nbbuf, NB_NSCOUNT); } /** * Set the NetBIOS opcode. * * @param op int */ public final void setOpcode(int op) { int val = DataPacker.getShort(m_nbbuf, NB_OPCODE) & MASK_NOOPCODE; val = val + (op << SHIFT_OPCODE); DataPacker.putShort((short) val, m_nbbuf, NB_OPCODE); } /** * Set the question count. * * @param cnt int */ public final void setQuestionCount(int cnt) { DataPacker.putShort((short) cnt, m_nbbuf, NB_QDCOUNT); } /** * Set the question name. * * @param name NetBIOSName * @param qtyp int * @param qcls int * @return int */ public final int setQuestionName(NetBIOSName name, int qtyp, int qcls) { // Encode the NetBIOS name byte[] nameByts = name.encodeName(); // Pack the encoded name into the NetBIOS packet int pos = NB_DATA; System.arraycopy(nameByts, 0, m_nbbuf, pos, nameByts.length); pos += nameByts.length; // Set the name type and class DataPacker.putShort((short) qtyp, m_nbbuf, pos); pos += 2; DataPacker.putShort((short) qcls, m_nbbuf, pos); pos += 2; // Set the packet length if (pos > m_datalen) setLength(pos); return pos; } /** * Set the question name. * * @param name java.lang.String * @param qtyp int * @param qcls int */ public final int setQuestionName(String name, char ntyp, int qtyp, int qcls) { // RFC encode the NetBIOS name string String encName = NetBIOSSession.ConvertName(name, ntyp); byte[] nameByts = encName.getBytes(); // Pack the encoded name into the NetBIOS packet int pos = NB_DATA; m_nbbuf[pos++] = (byte) NAME_LEN; for (int i = 0; i < 32; i++) m_nbbuf[pos++] = nameByts[i]; m_nbbuf[pos++] = 0x00; // Set the name type and class DataPacker.putShort((short) qtyp, m_nbbuf, pos); pos += 2; DataPacker.putShort((short) qcls, m_nbbuf, pos); pos += 2; // Set the packet length if (pos > m_datalen) setLength(pos); return pos; } /** * Pack the resource data into the packet. * * @return int * @param off int * @param flg int * @param data byte[] * @param len int */ public final int setResourceData(int off, int flg, byte[] data, int len) { // Set the resource data type DataPacker.putShort((short) flg, m_nbbuf, off); // Pack the data int pos = off + 2; for (int i = 0; i < len; i++) m_nbbuf[pos++] = data[i]; // Set the packet length if (pos > m_datalen) setLength(pos); return pos; } /** * Set the resource data length in the NetBIOS packet. * * @return int * @param off int * @param len int */ public final int setResourceDataLength(int off, int len) { // Set the resource data length DataPacker.putShort((short) len, m_nbbuf, off); // Set the packet length int pos = off + 2; if (pos > m_datalen) setLength(pos); // Return the new packet offset return pos; } /** * Set the resource record. * * @param pktoff Packet offset to pack the resource record. * @param offset Offset to name. * @param qtyp int * @param qcls int */ public final int setResourceRecord(int pktoff, int rroff, int qtyp, int qcls) { // Pack the resource record details DataPacker.putShort((short) (0xC000 + rroff), m_nbbuf, pktoff); DataPacker.putShort((short) qtyp, m_nbbuf, pktoff + 2); DataPacker.putShort((short) qcls, m_nbbuf, pktoff + 4); // Set the packet length int pos = pktoff + 6; if (pos > m_datalen) setLength(pos); // Return the new packet offset return pos; } /** * Set the transaction id. * * @param id int */ public final void setTransactionId(int id) { DataPacker.putShort((short) id, m_nbbuf, NB_TRANSID); } /** * Set the time to live for the packet. * * @return int * @param off int * @param ttl int */ public final int setTTL(int off, int ttl) { // Set the time to live value for the packet DataPacker.putInt(ttl, m_nbbuf, off); // Set the packet length int pos = off + 4; if (pos > m_datalen) setLength(pos); // Return the new packet offset return pos; } /** * Return a packet type as a string * * @param typ int * @return String */ public final static String getTypeAsString(int typ) { // Return the NetBIOS packet type as a string String typStr = ""; switch (typ) { case RFCNetBIOSProtocol.SESSION_ACK: typStr = "SessionAck"; break; case RFCNetBIOSProtocol.SESSION_KEEPALIVE: typStr = "SessionKeepAlive"; break; case RFCNetBIOSProtocol.SESSION_MESSAGE: typStr = "SessionMessage"; break; case RFCNetBIOSProtocol.SESSION_REJECT: typStr = "SessionReject"; break; case RFCNetBIOSProtocol.SESSION_REQUEST: typStr = "SessionRequest"; break; case RFCNetBIOSProtocol.SESSION_RETARGET: typStr = "SessionRetarget"; break; default: typStr = "Unknown 0x" + Integer.toHexString(typ); break; } // Return the packet type string return typStr; } /** * Build a name query response packet for the specified NetBIOS name * * @param name NetBIOSName * @return int */ public final int buildNameQueryResponse(NetBIOSName name) { // Fill in the header setOpcode(NetBIOSPacket.RESP_QUERY); setFlags(NetBIOSPacket.FLG_RECURSDES + NetBIOSPacket.FLG_AUTHANSWER); setQuestionCount(0); setAnswerCount(1); setAdditionalCount(0); setNameServiceCount(0); int pos = setAnswerName(name.getName(), name.getType(), 0x20, 0x01); pos = setTTL(pos, 10000); pos = setResourceDataLength(pos, name.numberOfAddresses() * 6); // Pack the IP address(es) for this name for (int i = 0; i < name.numberOfAddresses(); i++) { // Get the current IP address byte[] ipaddr = name.getIPAddress(i); // Pack the NetBIOS flags and IP address DataPacker.putShort((short) 0x00, m_nbbuf, pos); pos += 2; for (int j = 0; j < 4; j++) m_nbbuf[pos++] = ipaddr[j]; } // Set the packet length, and return the length setLength(pos); return getLength(); } /** * Build an add name request packet for the specified NetBIOS name * * @param name NetBIOSName * @param addrIdx int * @param tranId int * @return int */ public final int buildAddNameRequest(NetBIOSName name, int addrIdx, int tranId) { // Initialize an add name NetBIOS packet setTransactionId(tranId); setOpcode(NetBIOSPacket.NAME_REGISTER); setFlags(NetBIOSPacket.FLG_BROADCAST + NetBIOSPacket.FLG_RECURSION); setQuestionCount(1); setAnswerCount(0); setNameServiceCount(0); setAdditionalCount(1); int pos = setQuestionName(name.getName(), name.getType(), 0x20, 0x01); pos = setResourceRecord(pos, 12, 0x20, 0x01); if (name.getTimeToLive() == 0) pos = setTTL(pos, NetBIOSName.DefaultTTL); else pos = setTTL(pos, name.getTimeToLive()); short flg = 0; if (name.isGroupName()) flg = (short) 0x8000; pos = setNameRegistrationFlags(pos, flg); pos = setIPAddress(pos, name.getIPAddress(addrIdx)); // Return the packet length setLength(pos); return pos; } /** * Build a refresh name request packet for the specified NetBIOS name * * @param name NetBIOSName * @param addrIdx int * @param tranId int * @return int */ public final int buildRefreshNameRequest(NetBIOSName name, int addrIdx, int tranId) { // Initialize an add name NetBIOS packet setTransactionId(tranId); setOpcode(NetBIOSPacket.REFRESH); setFlags(NetBIOSPacket.FLG_BROADCAST + NetBIOSPacket.FLG_RECURSION); setQuestionCount(1); setAnswerCount(0); setNameServiceCount(0); setAdditionalCount(1); int pos = setQuestionName(name.getName(), name.getType(), 0x20, 0x01); pos = setResourceRecord(pos, 12, 0x20, 0x01); if (name.getTimeToLive() == 0) pos = setTTL(pos, NetBIOSName.DefaultTTL); else pos = setTTL(pos, name.getTimeToLive()); short flg = 0; if (name.isGroupName()) flg = (short) 0x8000; pos = setNameRegistrationFlags(pos, flg); pos = setIPAddress(pos, name.getIPAddress(addrIdx)); // Return the packet length setLength(pos); return pos; } /** * Build a delete name request packet for the specified NetBIOS name * * @param name NetBIOSName * @param addrIdx int * @param tranId int * @return int */ public final int buildDeleteNameRequest(NetBIOSName name, int addrIdx, int tranId) { // Initialize a delete name NetBIOS packet setTransactionId(tranId); setOpcode(NetBIOSPacket.NAME_RELEASE); setFlags(NetBIOSPacket.FLG_BROADCAST + NetBIOSPacket.FLG_RECURSION); setQuestionCount(1); setAnswerCount(0); setNameServiceCount(0); setAdditionalCount(1); int pos = setQuestionName(name.getName(), name.getType(), 0x20, 0x01); pos = setResourceRecord(pos, 12, 0x20, 0x01); pos = setTTL(pos, 30000); short flg = 0; if (name.isGroupName()) flg = (short) 0x8000; pos = setNameRegistrationFlags(pos, flg); pos = setIPAddress(pos, name.getIPAddress(addrIdx)); // Return the packet length setLength(pos); return pos; } /** * Build a name quesy request packet for the specified NetBIOS name * * @param name NetBIOSName * @param tranId int * @return int */ public final int buildNameQueryRequest(NetBIOSName name, int tranId) { // Initialize a name query NetBIOS packet setTransactionId(tranId); setOpcode(NetBIOSPacket.NAME_QUERY); setFlags(NetBIOSSession.hasWINSServer() ? 0 : NetBIOSPacket.FLG_BROADCAST); setQuestionCount(1); return setQuestionName(name, NetBIOSPacket.NAME_TYPE_NB, NetBIOSPacket.NAME_CLASS_IN); } /** * Build a session setup request packet * * @param fromName NetBIOSName * @param toName NetBIOSName * @return int */ public final int buildSessionSetupRequest(NetBIOSName fromName, NetBIOSName toName) { // Initialize the session setup packet header m_nbbuf[0] = (byte) RFCNetBIOSProtocol.SESSION_REQUEST; m_nbbuf[1] = (byte) 0; // flags // Set the remote NetBIOS name int pos = 4; byte[] encToName = toName.encodeName(); System.arraycopy(encToName, 0, m_nbbuf, pos, encToName.length); pos += encToName.length; // Set the local NetBIOS name byte[] encFromName = fromName.encodeName(); System.arraycopy(encFromName, 0, m_nbbuf, pos, encFromName.length); pos += encFromName.length; // Set the packet length setLength(pos); // Set the length in the session request header DataPacker.putShort((short) (pos - RFCNetBIOSProtocol.HEADER_LEN), m_nbbuf, 2); // Return the packet length return pos; } }