+#define AC_DATA_READ 0
+#define AC_DATA_WRITE 1
+#define AC_DATA_INC 2
+#define AC_DATA_DEC_TRANS_REST 3
+#define AC_KEYA_READ 0
+#define AC_KEYA_WRITE 1
+#define AC_KEYB_READ 2
+#define AC_KEYB_WRITE 3
+#define AC_AC_READ 4
+#define AC_AC_WRITE 5
+
+#define AUTHKEYA 0
+#define AUTHKEYB 1
+#define AUTHKEYNONE 0xff
+
+
+static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
+ uint8_t sector_trailer[16];
+ emlGetMem(sector_trailer, blockNo, 1);
+ uint8_t AC = ((sector_trailer[7] >> 5) & 0x04)
+ | ((sector_trailer[8] >> 2) & 0x02)
+ | ((sector_trailer[8] >> 7) & 0x01);
+ switch (action) {
+ case AC_KEYA_READ: {
+ return false;
+ break;
+ }
+ case AC_KEYA_WRITE: {
+ return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01))
+ || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03)));
+ break;
+ }
+ case AC_KEYB_READ: {
+ return (keytype == AUTHKEYA && (AC == 0x00 || AC == 0x02 || AC == 0x01));
+ break;
+ }
+ case AC_KEYB_WRITE: {
+ return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x04))
+ || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03)));
+ break;
+ }
+ case AC_AC_READ: {
+ return ((keytype == AUTHKEYA)
+ || (keytype == AUTHKEYB && !(AC == 0x00 || AC == 0x02 || AC == 0x01)));
+ break;
+ }
+ case AC_AC_WRITE: {
+ return ((keytype == AUTHKEYA && (AC == 0x01))
+ || (keytype == AUTHKEYB && (AC == 0x03 || AC == 0x05)));
+ break;
+ }
+ default: return false;
+ }
+}
+
+
+static bool IsDataAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action)
+{
+ uint8_t sector_trailer[16];
+ emlGetMem(sector_trailer, SectorTrailer(blockNo), 1);
+
+ uint8_t sector_block;
+ if (blockNo < 32*4) {
+ sector_block = blockNo & 0x03;
+ } else {
+ sector_block = (blockNo & 0x0f) / 5;
+ }
+
+ uint8_t AC;
+ switch (sector_block) {
+ case 0x00: {
+ AC = ((sector_trailer[7] >> 2) & 0x04)
+ | ((sector_trailer[8] << 1) & 0x02)
+ | ((sector_trailer[8] >> 4) & 0x01);
+ break;
+ }
+ case 0x01: {
+ AC = ((sector_trailer[7] >> 3) & 0x04)
+ | ((sector_trailer[8] >> 0) & 0x02)
+ | ((sector_trailer[8] >> 5) & 0x01);
+ break;
+ }
+ case 0x02: {
+ AC = ((sector_trailer[7] >> 4) & 0x04)
+ | ((sector_trailer[8] >> 1) & 0x02)
+ | ((sector_trailer[8] >> 6) & 0x01);
+ break;
+ }
+ default:
+ return false;
+ }
+
+ switch (action) {
+ case AC_DATA_READ: {
+ return ((keytype == AUTHKEYA && !(AC == 0x03 || AC == 0x05 || AC == 0x07))
+ || (keytype == AUTHKEYB && !(AC == 0x07)));
+ break;
+ }
+ case AC_DATA_WRITE: {
+ return ((keytype == AUTHKEYA && (AC == 0x00))
+ || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03)));
+ break;
+ }
+ case AC_DATA_INC: {
+ return ((keytype == AUTHKEYA && (AC == 0x00))
+ || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06)));
+ break;
+ }
+ case AC_DATA_DEC_TRANS_REST: {
+ return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x06 || AC == 0x01))
+ || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06 || AC == 0x01)));
+ break;
+ }
+ }
+
+ return false;
+}
+
+
+static bool IsAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
+ if (IsSectorTrailer(blockNo)) {
+ return IsTrailerAccessAllowed(blockNo, keytype, action);
+ } else {
+ return IsDataAccessAllowed(blockNo, keytype, action);
+ }
+}