// 解読 SE_BUF *SeIkeDecrypt(void *data, UINT size, SE_IKE_CRYPTO_PARAM *cparam) { void *tmp; SE_BUF *b; // 引数チェック if (data == NULL || cparam == NULL) { return NULL; } if ((size % SE_DES_BLOCK_SIZE) != 0) { // ブロックサイズの整数倍でない return NULL; } tmp = SeMalloc(size); SeDes3Decrypt(tmp, data, size, cparam->DesKey, cparam->Iv); if (size >= SE_DES_BLOCK_SIZE) { SeCopy(cparam->NextIv, ((UCHAR *)data) + (size - SE_DES_BLOCK_SIZE), SE_DES_BLOCK_SIZE); } else { SeZero(cparam->NextIv, SE_DES_BLOCK_SIZE); } b = SeMemToBuf(tmp, size); SeFree(tmp); return b; }
static void GetPhysicalNicInfo (void *handle, struct nicinfo *info) { info->mtu = 1500; info->media_speed = 1000000000; SeCopy (info->mac_address, pro100_get_ctx()->mac_address, 6); }
// 暗号化 (パディングも実行する) SE_BUF *SeIkeEncryptWithPadding(void *data, UINT size, SE_IKE_CRYPTO_PARAM *cparam) { UINT total_size; UINT i; UCHAR n = 0; UCHAR *tmp; SE_BUF *ret; // 引数チェック if (data == NULL || cparam == NULL) { return NULL; } total_size = ((size / SE_DES_BLOCK_SIZE) + ((size % SE_DES_BLOCK_SIZE) == 0 ? 0 : 1)) * SE_DES_BLOCK_SIZE; if (total_size == 0) { total_size = SE_DES_BLOCK_SIZE; } tmp = SeMalloc(total_size); SeCopy(tmp, data, size); for (i = size;i < total_size;i++) { tmp[i] = ++n; } ret = SeIkeEncrypt(tmp, total_size, cparam); SeFree(tmp); return ret; }
static void GetVirtualNicInfo (SE_HANDLE nic_handle, SE_NICINFO *info) { info->MediaType = SE_MEDIA_TYPE_ETHERNET; info->Mtu = 1500; info->MediaSpeed = 1000000000; SeCopy(info->MacAddress, pro100_get_ctx()->mac_address, 6); }
// ETH の情報を取得 void SeEthGetInfo(SE_ETH *e, SE_NICINFO *info) { // 引数チェック if (e == NULL || info == NULL) { return; } SeCopy(info, &e->Info, sizeof(SE_ETH)); }
// 物理的にパケットを送信する void pro100_send_packet_to_line(PRO100_CTX *ctx, void *buf, UINT size) { volatile PRO100_OP_BLOCK *b; PRO100_OP_TRANSMIT *t; phys_t ptr; // 引数チェック if (ctx == NULL || buf == NULL || size == 0) { return; } // メモリ確保 b = pro100_alloc_page(&ptr); t = (PRO100_OP_TRANSMIT *)b; t->op_block.op = PRO100_CU_OP_TRANSMIT; t->op_block.transmit_flexible_mode = 0; t->op_block.transmit_raw_packet = 0; t->op_block.transmit_cid = 31; t->op_block.i = false; t->op_block.s = false; t->op_block.el = true; t->op_block.link_address = 0; t->tbd_array_address = 0xffffffff; t->data_bytes = size; t->threshold = 1; SeCopy(((UCHAR *)b) + sizeof(PRO100_OP_TRANSMIT) + (ctx->use_standard_txcb ? 0 : sizeof(PRO100_TBD) * 2), buf, size); if (false) { char tmp[8000]; SeBinToStrEx(tmp, sizeof(tmp), (void *)b, size + sizeof(PRO100_OP_TRANSMIT)); printf("%s\n\n", tmp); } pro100_init_cu_base_addr(ctx); pro100_wait_cu_ru_accepable(ctx); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, (UINT)ptr, 4); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_COMMAND_WORD_0, PRO100_MAKE_CU_RU_COMMAND(PRO100_CU_CMD_START, PRO100_RU_CMD_NOOP), 1); pro100_flush(ctx); //printf("1\n"); while (b->c == false); //printf("2\n"); pro100_free_page((void *)b, ptr); }
// 割り込みを発生させる void pro100_generate_int(PRO100_CTX *ctx) { PRO100_INT_BIT ib; // 引数チェック if (ctx == NULL) { return; } SeCopy(&ib, &ctx->int_mask_guest_set, sizeof(UINT)); if (ib.mask_all != 0) { return; } ib.si = 1; //printf("*"); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_COMMAND_WORD_1, *((UINT *)(void *)&ib), 1); }
// MAC アドレスをリストへ追加 void SeEthAddSenderMacList(SE_ETH *e, UCHAR *mac_address) { // 引数チェック if (e == NULL || mac_address == NULL) { return; } SeLock(e->SenderMacListLock); { UINT i; bool exists = false; for (i = 0;i < SE_LIST_NUM(e->SenderMacList);i++) { SE_ETH_SENDER_MAC *m = SE_LIST_DATA(e->SenderMacList, i); if (SeCmp(m->MacAddress, mac_address, SE_ETHERNET_MAC_ADDR_SIZE) == 0) { m->Expires = SeTick64() + (UINT64)SE_ETH_SENDER_MAC_EXPIRES; exists = true; } } if (exists == false) { SE_ETH_SENDER_MAC *m = SeZeroMalloc(sizeof(SE_ETH_SENDER_MAC)); m->Expires = SeTick64() + (UINT64)SE_ETH_SENDER_MAC_EXPIRES; SeCopy(m->MacAddress, mac_address, SE_ETHERNET_MAC_ADDR_SIZE); SeAdd(e->SenderMacList, m); } SeEthDeleteOldSenderMacList(e); } SeUnlock(e->SenderMacListLock); }
// ランダムな MAC アドレスの生成 void SeEthGenRandMacAddress(UCHAR *mac_address, void *key, UINT key_size) { UCHAR hash[SE_SHA1_HASH_SIZE]; // 引数チェック if (mac_address == NULL) { return; } if (key == NULL || key_size == 0) { SeRand(hash, sizeof(hash)); } else { SeSha1(hash, key, key_size); } SeCopy(mac_address, hash, SE_ETHERNET_MAC_ADDR_SIZE); mac_address[0] = 0x00; mac_address[1] = 0xAC; }
// ゲスト OS が開始したオペレーションを処理する void pro100_proc_guest_op(PRO100_CTX *ctx) { phys_t ptr; // 引数チェック if (ctx == NULL) { return; } if (ctx->guest_cu_started == false || ctx->guest_cu_current_pointer == 0) { return; } ptr = ctx->guest_cu_current_pointer; // 終端まで読み取る while (true) { PRO100_OP_BLOCK_MAX b; if (ctx->guest_cu_suspended) { // サスペンド中の場合、前回の最後のオペレーションの S ビットがクリア // されたかどうか検査する pro100_mem_read(&b, ptr, sizeof(b)); if (b.op_block.s) { // サスペンド継続中 break; } ptr = ctx->guest_cu_next_pointer; ctx->guest_cu_suspended = false; } pro100_mem_read(&b, ptr, sizeof(b)); if (b.op_block.op == PRO100_CU_OP_TRANSMIT) { // 送信処理 PRO100_OP_TRANSMIT *t = (PRO100_OP_TRANSMIT *)&b; if (false) { printf("flexible_mode=%u, raw_packet=%u, cid=%u, array=0x%x, thres=%u, tcount=%u, size=%u\n", t->op_block.transmit_flexible_mode, t->op_block.transmit_raw_packet, t->op_block.transmit_cid, t->tbd_array_address, t->threshold, t->tbd_count, t->data_bytes); } //printf("SEND\n"); if (false) { char tmp[4096]; SeBinToStrEx(tmp, sizeof(tmp), &b, 24); printf("%s\n", tmp); } if (true) { UCHAR buf[PRO100_MAX_PACKET_SIZE]; UINT packet_size = pro100_read_send_packet(ctx, ptr, buf); #ifdef PRO100_PASS_MODE pro100_write_recv_packet(ctx, buf, packet_size); #else // PRO100_PASS_MODE if (ctx->CallbackRecvVirtNic != NULL) { void *packet_data[1]; UINT packet_sizes[1]; packet_data[0] = buf; packet_sizes[0] = packet_size; ctx->CallbackRecvVirtNic(ctx, 1, packet_data, packet_sizes, ctx->CallbackRecvVirtNicParam); } #endif // PRO100_PASS_MODE } b.op_block.ok = b.op_block.c = true; b.op_block.transmit_overrun = false; pro100_mem_write(ptr, &b, sizeof(PRO100_OP_BLOCK) + sizeof(PRO100_OP_TRANSMIT)); if (b.op_block.i) { pro100_generate_int(ctx); } } else { // 送信以外の処理 UINT size = pro100_get_op_size(b.op_block.op, &b); //printf("0x%x: OP: %u Size=%u\n", (UINT)ptr, b.op_block.op, size); switch (b.op_block.op) { case PRO100_CU_OP_IA_SETUP: // IA Setup SeCopy(ctx->mac_address, ((UCHAR *)&b) + sizeof(PRO100_OP_BLOCK), 6); pro100_init_vpn_client(ctx); break; case PRO100_CU_OP_CONFIG: // Configure ctx->use_standard_txcb = ((((UCHAR *)&b)[sizeof(PRO100_OP_BLOCK) + 6] & 0x10) ? true : false); break; } pro100_exec_cu_op(ctx, &b, size); pro100_mem_write(ptr, &b, size); } if (b.op_block.el) { // 終了フラグ ctx->guest_cu_started = false; ctx->guest_cu_current_pointer = 0; ctx->guest_cu_suspended = false; //printf("EL\n"); pro100_generate_int(ctx); break; } if (b.op_block.s) { // サスペンドフラグ ctx->guest_cu_suspended = true; ctx->guest_cu_next_pointer = b.op_block.link_address; //printf("SUSPEND\n"); pro100_generate_int(ctx); break; } ptr = b.op_block.link_address; } if (ctx->guest_cu_started) { ctx->guest_cu_current_pointer = ptr; } }
// 送信しようとしているパケットを読み取る UINT pro100_read_send_packet(PRO100_CTX *ctx, phys_t addr, void *buf) { PRO100_OP_BLOCK_MAX b; PRO100_OP_TRANSMIT *t; UINT ret = 0; // 引数チェック if (ctx == NULL || addr == 0 || buf == NULL) { return 0; } // メモリから読み取る pro100_mem_read(&b, addr, sizeof(b)); t = (PRO100_OP_TRANSMIT *)&b; if (t->op_block.transmit_flexible_mode == 0) { // Simplified モード ret = t->data_bytes; if (ret > PRO100_MAX_PACKET_SIZE) { // パケットサイズが大きすぎる return 0; } // パケットデータのコピー SeCopy(buf, ((UCHAR *)&b) + sizeof(PRO100_OP_TRANSMIT), ret); return ret; } else { UINT num_tbd = t->tbd_count; PRO100_TBD *tbd_array = SeZeroMalloc(num_tbd * sizeof(PRO100_TBD)); UINT total_packet_size; UINT i; if (ctx->use_standard_txcb) { // Standard Flexible モード pro100_mem_read(tbd_array, (phys_t)t->tbd_array_address, num_tbd * sizeof(PRO100_TBD)); } else { // Extended Flexible モード: 最初の 2 個を末尾から読む UINT num_tbd_ex = num_tbd; if (num_tbd_ex >= 2) { num_tbd_ex = 2; } SeCopy(tbd_array, ((UCHAR *)&b) + sizeof(PRO100_OP_TRANSMIT), num_tbd_ex * sizeof(PRO100_TBD)); // 残りがある場合は TBD アレイアドレスから読み込む if ((num_tbd - num_tbd_ex) >= 1) { pro100_mem_read(((UCHAR *)tbd_array) + num_tbd_ex * sizeof(PRO100_TBD), (phys_t)t->tbd_array_address, (num_tbd - num_tbd_ex) * sizeof(PRO100_TBD)); } } // TBD アレイアドレスを用いてパケットを読み込む total_packet_size = 0; for (i = 0;i < num_tbd;i++) { PRO100_TBD *tbd = &tbd_array[i]; total_packet_size += tbd->size; } if (total_packet_size > PRO100_MAX_PACKET_SIZE) { // パケットサイズが大きすぎる ret = 0; } else { // パケットデータを読み込む UCHAR *current_ptr = buf; for (i = 0;i < num_tbd;i++) { PRO100_TBD *tbd = &tbd_array[i]; pro100_mem_read(current_ptr, (phys_t)tbd->data_address, tbd->size); current_ptr += tbd->size; } ret = total_packet_size; } SeFree(tbd_array); return ret; } }
// CU にオペレーションを実行させる void pro100_exec_cu_op(PRO100_CTX *ctx, PRO100_OP_BLOCK_MAX *op, UINT size) { volatile PRO100_OP_BLOCK *b; PRO100_OP_BLOCK *b2; phys_t ptr; bool src_el, src_s, src_i; UINT src_link_addr; bool timeouted; UINT64 start_tick; // 引数チェック if (ctx == NULL || op == NULL) { return; } // メモリ確保 b = pro100_alloc_page(&ptr); // 一時領域にコピー SeCopy((void *)b, op, size); // バックアップ src_el = b->el; src_s = b->s; src_i = b->i; src_link_addr = b->link_address; // フラグセット b->el = true; b->s = false; //b->ok = b->c = false; b->link_address = ptr; //b->i = false; pro100_init_cu_base_addr(ctx); pro100_wait_cu_ru_accepable(ctx); if (false) { char tmp[4096]; SeBinToStrEx(tmp, sizeof(tmp), (void *)b, size); printf("%s\n", tmp); } pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, (UINT)ptr, 4); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_COMMAND_WORD_0, PRO100_MAKE_CU_RU_COMMAND(PRO100_CU_CMD_START, PRO100_RU_CMD_NOOP), 1); pro100_flush(ctx); // NIC がコマンドを完了するまで待機 //printf("["); start_tick = SeTick64(); timeouted = true; while ((start_tick + 1000ULL) >= SeTick64()) { if (b->c) { timeouted = false; break; } } //printf("%u] ", b->c); //b->c = true; if (false) { UINT t = pro100_read(ctx, PRO100_CSR_OFFSET_SCB_STATUS_WORD_0, 1); PRO100_SCB_STATUS_WORD_BIT *b = (PRO100_SCB_STATUS_WORD_BIT *)(void *)&t; printf("STATUS CU=%u, RU=%u\n", b->cu_status, b->ru_status); } // 結果を書き戻す SeCopy(op, (void *)b, size); b2 = (PRO100_OP_BLOCK *)op; // バックアップを復元 b2->el = src_el; b2->s = src_s; b2->i = src_i; b2->link_address = src_link_addr; // メモリ解放 pro100_free_page((void *)b, ptr); if (timeouted && src_i) { //pro100_generate_int(ctx); } }
// パケットを受信したことにしてゲスト OS に渡す void pro100_write_recv_packet(PRO100_CTX *ctx, void *buf, UINT size) { PRO100_RFD rfd; phys_t ptr; // 引数チェック if (ctx == NULL || buf == NULL || size == 0) { return; } if (ctx->guest_rfd_current == 0) { // ゲスト OS が RFD のアドレスを指定していない return; } /* if (ctx->guest_ru_suspended) { // ゲスト OS によって RU がサスペンドされている return; }*/ // 現在の RFD バッファの内容をチェックする ptr = ctx->guest_rfd_current; pro100_mem_read(&rfd, ptr, sizeof(PRO100_RFD)); if (rfd.eof) { // EOF ビットが有効になっているためこの RFD にはデータを受信できない return; } // RFD にデータを書き込む rfd.status = 0; rfd.sf = rfd.h = 0; SeCopy(rfd.data, buf, size); rfd.recved_bytes = size; rfd.f = 1; rfd.ok = 1; rfd.c = 1; rfd.eof = 1; // ビットチェック if (rfd.el) { // これが最後の RFD である ctx->guest_rfd_current = ctx->guest_rfd_first = 0; } else { // 次の RFD のリンクアドレスを取得する ctx->guest_rfd_current = rfd.link_address; if (ctx->guest_rfd_current == 0xffffffff) { ctx->guest_rfd_current = 0; } if (rfd.s) { ctx->guest_ru_suspended = true; } } pro100_mem_write(ptr, &rfd, sizeof(PRO100_RFD)); // 割り込み発生 pro100_generate_int(ctx); }
// 提供システムコール: RSA 署名操作 bool crypt_sys_rsa_sign (void *key_data, UINT key_size, void *data, UINT data_size, void *sign, UINT *sign_buf_size) { SE_BUF *ret_buf; SE_KEY *key; SE_BUF *key_file_buf; SE_BUF *tmp_buf; // 引数チェック if (key_data == NULL || data == NULL || data_size == 0 || sign == NULL || sign_buf_size == NULL) { return false; } // 秘密鍵データのコピー key_file_buf = SeNewBuf(); SeWriteBuf(key_file_buf, key_data, key_size); tmp_buf = SeMemToBuf(key_file_buf->Buf, key_file_buf->Size); SeFreeBuf(key_file_buf); key = SeBufToKey(tmp_buf, true, true, NULL); if (key == NULL) { key = SeBufToKey(tmp_buf, true, false, NULL); } if (key == NULL) { chelp_printf("crypt.c: Loading Key Failed.\n"); SeFreeBuf(tmp_buf); *sign_buf_size = 0; return false; } SeFreeBuf(tmp_buf); ret_buf = SeRsaSignWithPadding(data, data_size, key); if (ret_buf == NULL) { chelp_printf("crypt.c: SeRsaSignWithPadding() Failed.\n"); SeFreeKey(key); *sign_buf_size = 0; return false; } if (*sign_buf_size < ret_buf->Size) { chelp_printf("crypt.c: Not Enough Buffer Space.\n"); *sign_buf_size = ret_buf->Size; SeFreeBuf(ret_buf); SeFreeKey(key); *sign_buf_size = ret_buf->Size; return false; } *sign_buf_size = ret_buf->Size; SeCopy(sign, ret_buf->Buf, ret_buf->Size); SeFreeBuf(ret_buf); SeFreeKey(key); return true; }