package org.freertr.pack; import java.util.ArrayList; import java.util.List; import org.freertr.pipe.pipeSide; import org.freertr.util.bits; /** * internet small computer systems interface (rfc3720) packet * * @author matecsaba */ public class packIscsi { /** * create instance */ public packIscsi() { } /** * port number */ public final static int port = 3260; /** * size of header */ public final static int size = 48; /** * no operation */ public final static int opcCnop = 0x00; /** * scsi command */ public final static int opcCscsi = 0x01; /** * task management */ public final static int opcCtask = 0x02; /** * login */ public final static int opcClogin = 0x03; /** * text */ public final static int opcCtext = 0x04; /** * scsi data */ public final static int opcCdata = 0x05; /** * logout */ public final static int opcClogout = 0x06; /** * snack */ public final static int opcCsnack = 0x10; /** * no operation */ public final static int opcRnop = 0x20; /** * scsi response */ public final static int opcRscsi = 0x21; /** * task management */ public final static int opcRtask = 0x22; /** * login */ public final static int opcRlogin = 0x23; /** * text */ public final static int opcRtext = 0x24; /** * scsi data */ public final static int opcRdata = 0x25; /** * logout */ public final static int opcRlogout = 0x26; /** * ready to transfer */ public final static int opcRready = 0x31; /** * asynchronous message */ public final static int opcRasync = 0x32; /** * reject */ public final static int opcReject = 0x3f; /** * no more messages */ public final static int flgFinal = 0x80; /** * read, input data follows */ public final static int flgRead = 0x40; /** * write, output data follows */ public final static int flgWrite = 0x20; /** * packet data */ public packHolder pack; /** * pipeline to use */ public pipeSide pipe; /** * opcode value */ public int opcode; /** * flags value */ public int flags; /** * response code */ public int respon; /** * status value */ public int status; /** * immediate delivery */ public boolean immediately; /** * logical unit id */ public long lun; /** * initiator task tag */ public int taskTag; /** * target transfer tag */ public int xferTag; /** * buffer offset */ public int bufOfs; /** * referenced task tag */ public int taskRef; /** * referenced command sequence */ public int cmdRef; /** * snack tag */ public int snackTag; /** * transfer length */ public int xferLen; /** * command sequence number */ public int cmdSeq; /** * status sequence number */ public int statSeq; /** * ready to transfer sequence number */ public int r2tSeq; /** * command sequence maximum */ public int cmdMax; /** * data sequence number */ public int datSeq; /** * bidir residual count */ public int biRes; /** * residual count */ public int resid; /** * scsi data */ public byte[] scsi; /** * tlvs in packet */ public List text; /** * convert opcode to string * * @param i opcode * @return string */ public static String opcode2string(int i) { switch (i) { case opcCnop: return "noopReq"; case opcCscsi: return "scsiReq"; case opcCtask: return "taskReq"; case opcClogin: return "loginReq"; case opcCtext: return "textReq"; case opcCdata: return "dataReq"; case opcClogout: return "logoutReq"; case opcCsnack: return "snackReq"; case opcRnop: return "noopRep"; case opcRscsi: return "scsiRep"; case opcRtask: return "taskRep"; case opcRlogin: return "loginRep"; case opcRtext: return "textRep"; case opcRdata: return "dataRep"; case opcRlogout: return "logoutRep"; case opcRready: return "r2tRep"; case opcRasync: return "asyncRep"; case opcReject: return "reject"; default: return "unknown=" + i; } } /** * receive one packet * * @return false on success, true on error */ public boolean packRecv() { opcode = -1; pack.clear(); if (pack.pipeRecv(pipe, 0, size, 144) != size) { pipe.setClose(); return true; } opcode = pack.getByte(0); immediately = (opcode & 0x40) != 0; opcode &= 0x3f; int datSiz = pack.msbGetD(4); if ((datSiz >>> 24) != 0) { pipe.setClose(); return true; } if (datSiz < 1) { return false; } int pad = (datSiz & 3); if (pad != 0) { pad = 4 - pad; } datSiz += pad; if (pack.pipeRecv(pipe, size, datSiz, 144) != datSiz) { pipe.setClose(); return true; } pack.setDataSize(pack.dataSize() - pad); return false; } /** * send one packet */ public void packSend() { pack.merge2beg(); int datSiz = pack.dataSize(); pack.putByte(0, opcode); pack.msbPutD(4, datSiz); pack.putSkip(size); pack.merge2beg(); int pad = (datSiz & 3); if (pad != 0) { pad = 4 - pad; pack.putFill(0, pad, 0); pack.putSkip(pad); pack.merge2end(); } pack.pipeSend(pipe, 0, pack.dataSize(), 3); } /** * dump message * * @return string */ public String dumpHdr() { return "opc=" + opcode2string(opcode) + " flg=" + flags + " rsp=" + respon + " stt=" + status + " lun=" + lun + " task=" + taskTag + " snack=" + snackTag + " cmd=" + cmdSeq + " stat=" + statSeq + " scsi=" + bits.byteDump(scsi, 0, -1) + " xfer=" + xferLen + " cmdMax=" + cmdMax + " dat=" + datSeq + " birs=" + biRes + " rsid=" + resid + " tskRef=" + taskRef + " cmdRef=" + cmdRef + " xferTag=" + xferTag + " bufOfs=" + bufOfs + " r2t=" + r2tSeq; } /** * dump message * * @return string */ public String dumpTxt() { String s = ""; for (int i = 0; i < text.size(); i++) { s += " " + text.get(i); } return s; } /** * parse scsi request * * @return false on success, true on error */ public boolean parseScsiReq() { if (opcode != opcCscsi) { return true; } flags = pack.getByte(1); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); xferLen = pack.msbGetD(20); cmdSeq = pack.msbGetD(24); statSeq = pack.msbGetD(28); scsi = new byte[16]; pack.getCopy(scsi, 0, 32, scsi.length); pack.getSkip(size); return false; } /** * create scsi request */ public void createScsiReq() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcCscsi; pack.putByte(1, flags); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutD(20, xferLen); pack.msbPutD(24, cmdSeq); pack.msbPutD(28, statSeq); pack.putCopy(scsi, 0, 32, scsi.length); } /** * parse scsi response * * @return false on success, true on error */ public boolean parseScsiRep() { if (opcode != opcRscsi) { return true; } flags = pack.getByte(1); respon = pack.getByte(2); status = pack.getByte(3); taskTag = pack.msbGetD(16); snackTag = pack.msbGetD(20); statSeq = pack.msbGetD(24); cmdSeq = pack.msbGetD(28); cmdMax = pack.msbGetD(32); datSeq = pack.msbGetD(36); biRes = pack.msbGetD(40); resid = pack.msbGetD(44); pack.getSkip(size); return false; } /** * create scsi response */ public void createScsiRep() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcRscsi; pack.putByte(1, flags); pack.putByte(2, respon); pack.putByte(3, status); pack.msbPutD(16, taskTag); pack.msbPutD(20, snackTag); pack.msbPutD(24, statSeq); pack.msbPutD(28, cmdSeq); pack.msbPutD(32, cmdMax); pack.msbPutD(36, datSeq); pack.msbPutD(40, biRes); pack.msbPutD(44, resid); } /** * parse task request * * @return false on success, true on error */ public boolean parseTaskReq() { if (opcode != opcCtask) { return true; } flags = pack.getByte(1); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); taskRef = pack.msbGetD(20); cmdSeq = pack.msbGetD(24); statSeq = pack.msbGetD(28); cmdRef = pack.msbGetD(32); datSeq = pack.msbGetD(36); pack.getSkip(size); return false; } /** * create task request */ public void createTaskReq() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcCtask; pack.putByte(1, flags); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutD(20, taskRef); pack.msbPutD(24, cmdSeq); pack.msbPutD(28, statSeq); pack.msbPutD(32, cmdRef); pack.msbPutD(36, datSeq); } /** * parse task response * * @return false on success, true on error */ public boolean parseTaskRep() { if (opcode != opcRtask) { return true; } flags = pack.getByte(1); respon = pack.getByte(2); taskTag = pack.msbGetD(16); statSeq = pack.msbGetD(24); cmdSeq = pack.msbGetD(28); cmdMax = pack.msbGetD(32); pack.getSkip(size); return false; } /** * create task response */ public void createTaskRep() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcRtask; pack.putByte(1, flags); pack.putByte(2, respon); pack.msbPutD(16, taskTag); pack.msbPutD(24, statSeq); pack.msbPutD(28, cmdSeq); pack.msbPutD(32, cmdMax); } /** * parse data request * * @return false on success, true on error */ public boolean parseDataReq() { if (opcode != opcCdata) { return true; } flags = pack.getByte(1); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); xferTag = pack.msbGetD(20); statSeq = pack.msbGetD(28); datSeq = pack.msbGetD(36); bufOfs = pack.msbGetD(40); pack.getSkip(size); return false; } /** * create data request */ public void createDataReq() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcCdata; pack.putByte(1, flags); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutD(20, xferTag); pack.msbPutD(28, statSeq); pack.msbPutD(36, datSeq); pack.msbPutD(40, bufOfs); } /** * parse data response * * @return false on success, true on error */ public boolean parseDataRep() { if (opcode != opcRdata) { return true; } flags = pack.getByte(1); status = pack.getByte(3); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); xferTag = pack.msbGetD(20); statSeq = pack.msbGetD(24); cmdSeq = pack.msbGetD(28); cmdMax = pack.msbGetD(32); datSeq = pack.msbGetD(36); bufOfs = pack.msbGetD(40); resid = pack.msbGetD(44); pack.getSkip(size); return false; } /** * create data response */ public void createDataRep() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcRdata; pack.putByte(1, flags); pack.putByte(3, status); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutD(20, xferTag); pack.msbPutD(24, statSeq); pack.msbPutD(28, cmdSeq); pack.msbPutD(32, cmdMax); pack.msbPutD(36, datSeq); pack.msbPutD(40, bufOfs); pack.msbPutD(44, resid); } /** * parse ready to transfer * * @return false on success, true on error */ public boolean parseR2t() { if (opcode != opcRready) { return true; } flags = pack.getByte(1); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); xferTag = pack.msbGetD(20); statSeq = pack.msbGetD(24); cmdSeq = pack.msbGetD(28); cmdMax = pack.msbGetD(32); r2tSeq = pack.msbGetD(36); bufOfs = pack.msbGetD(40); xferLen = pack.msbGetD(44); pack.getSkip(size); return false; } /** * create ready to transfer */ public void createR2t() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcRready; pack.putByte(1, flags); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutD(20, xferTag); pack.msbPutD(24, statSeq); pack.msbPutD(28, cmdSeq); pack.msbPutD(32, cmdMax); pack.msbPutD(36, r2tSeq); pack.msbPutD(40, bufOfs); pack.msbPutD(44, xferLen); } /** * parse async event * * @return false on success, true on error */ public boolean parseAsync() { if (opcode != opcRasync) { return true; } flags = pack.getByte(1); lun = pack.msbGetQ(8); statSeq = pack.msbGetD(24); cmdSeq = pack.msbGetD(28); cmdMax = pack.msbGetD(32); r2tSeq = pack.msbGetD(36); bufOfs = pack.msbGetD(40); pack.getSkip(size); return false; } /** * create async event */ public void createAsync() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcRasync; pack.putByte(1, flags); pack.msbPutQ(8, lun); pack.msbPutD(24, statSeq); pack.msbPutD(28, cmdSeq); pack.msbPutD(32, cmdMax); pack.msbPutD(36, r2tSeq); pack.msbPutD(40, bufOfs); } /** * parse text request * * @return false on success, true on error */ public boolean parseTextReq() { if (opcode != opcCtext) { return true; } flags = pack.getByte(1); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); xferTag = pack.msbGetD(20); cmdSeq = pack.msbGetD(24); statSeq = pack.msbGetD(28); pack.getSkip(size); return false; } /** * create text request */ public void createTextReq() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcCtext; pack.putByte(1, flags); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutD(20, xferTag); pack.msbPutD(24, cmdSeq); pack.msbPutD(28, statSeq); } /** * parse text response * * @return false on success, true on error */ public boolean parseTextRep() { if (opcode != opcRtext) { return true; } flags = pack.getByte(1); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); xferTag = pack.msbGetD(20); statSeq = pack.msbGetD(24); cmdSeq = pack.msbGetD(28); cmdMax = pack.msbGetD(32); pack.getSkip(size); return false; } /** * create text response */ public void createTextRep() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcRtext; pack.putByte(1, flags); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutD(20, xferTag); pack.msbPutD(24, statSeq); pack.msbPutD(28, cmdSeq); pack.msbPutD(32, cmdMax); } /** * parse login request * * @return false on success, true on error */ public boolean parseLoginReq() { if (opcode != opcClogin) { return true; } flags = pack.getByte(1); status = pack.getByte(2); respon = pack.getByte(3); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); xferTag = pack.msbGetW(20); cmdSeq = pack.msbGetD(24); statSeq = pack.msbGetD(28); pack.getSkip(size); return false; } /** * create login request */ public void createLoginReq() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcRlogin; pack.putByte(1, flags); pack.putByte(2, status); pack.putByte(3, respon); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutW(20, xferTag); pack.msbPutD(24, cmdSeq); pack.msbPutD(28, statSeq); } /** * parse login response * * @return false on success, true on error */ public boolean parseLoginRep() { if (opcode != opcRlogin) { return true; } flags = pack.getByte(1); status = pack.getByte(2); respon = pack.getByte(3); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); statSeq = pack.msbGetD(24); cmdSeq = pack.msbGetD(28); cmdMax = pack.msbGetD(32); resid = pack.msbGetD(36); pack.getSkip(size); return false; } /** * create login response */ public void createLoginRep() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcRlogin; pack.putByte(1, flags); pack.putByte(2, status); pack.putByte(3, respon); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutD(24, statSeq); pack.msbPutD(28, cmdSeq); pack.msbPutD(32, cmdMax); pack.msbPutD(36, resid); } /** * parse logout request * * @return false on success, true on error */ public boolean parseLogoutReq() { if (opcode != opcClogout) { return true; } flags = pack.getByte(1); taskTag = pack.msbGetD(16); xferTag = pack.msbGetW(20); cmdSeq = pack.msbGetD(24); statSeq = pack.msbGetD(28); pack.getSkip(size); return false; } /** * create logout request */ public void createLogoutReq() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcClogout; pack.putByte(1, flags); pack.msbPutD(16, taskTag); pack.msbPutW(20, xferTag); pack.msbPutD(24, cmdSeq); pack.msbPutD(28, statSeq); } /** * parse logout response * * @return false on success, true on error */ public boolean parseLogoutRep() { if (opcode != opcRlogout) { return true; } flags = pack.getByte(1); respon = pack.getByte(2); taskTag = pack.msbGetD(16); statSeq = pack.msbGetD(24); cmdSeq = pack.msbGetD(28); cmdMax = pack.msbGetD(32); resid = pack.msbGetW(40); biRes = pack.msbGetW(42); pack.getSkip(size); return false; } /** * create logout response */ public void createLogoutRep() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcRlogout; pack.putByte(1, flags); pack.putByte(2, respon); pack.msbPutD(16, taskTag); pack.msbPutD(24, statSeq); pack.msbPutD(28, cmdSeq); pack.msbPutD(32, cmdMax); pack.msbPutW(40, resid); pack.msbPutW(42, biRes); } /** * parse snack request * * @return false on success, true on error */ public boolean parseSnackReq() { if (opcode != opcCsnack) { return true; } flags = pack.getByte(1); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); snackTag = pack.msbGetD(20); statSeq = pack.msbGetD(28); xferTag = pack.msbGetD(40); xferLen = pack.msbGetD(44); pack.getSkip(size); return false; } /** * create snack request */ public void createSnackReq() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcCsnack; pack.putByte(1, flags); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutD(20, snackTag); pack.msbPutD(28, statSeq); pack.msbPutD(40, xferTag); pack.msbPutD(44, xferLen); } /** * parse reject * * @return false on success, true on error */ public boolean parseReject() { if (opcode != opcReject) { return true; } flags = pack.getByte(1); respon = pack.getByte(2); statSeq = pack.msbGetD(24); cmdSeq = pack.msbGetD(28); cmdMax = pack.msbGetD(32); datSeq = pack.msbGetD(36); pack.getSkip(size); return false; } /** * create reject */ public void createReject() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcReject; pack.putByte(1, flags); pack.putByte(2, respon); pack.msbPutD(16, -1); pack.msbPutD(24, statSeq); pack.msbPutD(28, cmdSeq); pack.msbPutD(32, cmdMax); pack.msbPutD(36, datSeq); } /** * parse noop request * * @return false on success, true on error */ public boolean parseNopReq() { if (opcode != opcCnop) { return true; } flags = pack.getByte(1); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); xferTag = pack.msbGetD(20); cmdSeq = pack.msbGetD(24); statSeq = pack.msbGetD(28); pack.getSkip(size); return false; } /** * create nop request */ public void createNopReq() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcCnop; pack.putByte(1, flags); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutD(20, xferTag); pack.msbPutD(24, cmdSeq); pack.msbPutD(28, statSeq); } /** * parse noop reply * * @return false on success, true on error */ public boolean parseNopRep() { if (opcode != opcRnop) { return true; } flags = pack.getByte(1); lun = pack.msbGetQ(8); taskTag = pack.msbGetD(16); xferTag = pack.msbGetD(20); statSeq = pack.msbGetD(24); cmdSeq = pack.msbGetD(28); cmdMax = pack.msbGetD(32); pack.getSkip(size); return false; } /** * create nop response */ public void createNopRep() { pack.merge2beg(); pack.putFill(0, size, 0); opcode = opcRnop; pack.putByte(1, flags); pack.msbPutQ(8, lun); pack.msbPutD(16, taskTag); pack.msbPutD(20, xferTag); pack.msbPutD(24, statSeq); pack.msbPutD(28, cmdSeq); pack.msbPutD(32, cmdMax); } /** * parse tlvs from packet */ public void parseText() { text = new ArrayList(); for (;;) { if (pack.dataSize() < 1) { return; } String s = pack.getAsciiZ(0, 1024, 0); text.add(s); pack.getSkip(s.length() + 1); } } /** * create tlvs to packet */ public void createText() { pack.clear(); for (int i = 0; i < text.size(); i++) { String s = text.get(i); pack.putAsciiZ(0, s.length() + 1, s, 0); pack.putSkip(s.length() + 1); } } /** * find text * * @param beg needed tlv * @return null if not found, value othervise */ public String findText(String beg) { beg = beg.toLowerCase(); for (int i = 0; i < text.size(); i++) { String s = text.get(i); int o = s.indexOf("="); if (o < 0) { continue; } String a = s.substring(0, o).trim().toLowerCase(); s = s.substring(o + 1, s.length()).trim(); if (a.equals(beg)) { return s; } } return null; } /** * clear text */ public void clearText() { text = new ArrayList(); } /** * add one text * * @param typ type * @param val value */ public void addText(String typ, String val) { text.add(typ + "=" + val); } /** * add one text if asked * * @param old old packet * @param typ type * @param val value */ public void addTextIf(packIscsi old, String typ, String val) { if (old.findText(typ) == null) { return; } addText(typ, val); } }