/** * Issue command with parameter block and data block * * @v nii NII NIC * @v op Operation * @v cpb Command parameter block, or NULL * @v cpb_len Command parameter block length * @v db Data block, or NULL * @v db_len Data block length * @ret stat Status flags, or negative status code */ static int nii_issue_cpb_db ( struct nii_nic *nii, unsigned int op, void *cpb, size_t cpb_len, void *db, size_t db_len ) { PXE_CDB cdb; /* Prepare command descriptor block */ memset ( &cdb, 0, sizeof ( cdb ) ); cdb.OpCode = NII_OPCODE ( op ); cdb.OpFlags = NII_OPFLAGS ( op ); cdb.CPBaddr = ( ( intptr_t ) cpb ); cdb.CPBsize = cpb_len; cdb.DBaddr = ( ( intptr_t ) db ); cdb.DBsize = db_len; cdb.IFnum = nii->nii->IfNum; /* Issue command */ DBGC2 ( nii, "NII %s issuing %02x:%04x ifnum %d%s%s\n", nii->dev.name, cdb.OpCode, cdb.OpFlags, cdb.IFnum, ( cpb ? " cpb" : "" ), ( db ? " db" : "" ) ); if ( cpb ) DBGC2_HD ( nii, cpb, cpb_len ); if ( db ) DBGC2_HD ( nii, db, db_len ); nii->issue ( ( intptr_t ) &cdb ); /* Check completion status */ if ( cdb.StatCode != PXE_STATCODE_SUCCESS ) return -cdb.StatCode; /* Return command-specific status flags */ return ( cdb.StatFlags & ~PXE_STATFLAGS_STATUS_MASK ); }
/** * Generate secure pseudo-random data using a single hash function * * @v tls TLS session * @v digest Hash function to use * @v secret Secret * @v secret_len Length of secret * @v out Output buffer * @v out_len Length of output buffer * @v seeds ( data, len ) pairs of seed data, terminated by NULL */ static void tls_p_hash_va ( struct tls_session *tls, struct digest_algorithm *digest, void *secret, size_t secret_len, void *out, size_t out_len, va_list seeds ) { uint8_t secret_copy[secret_len]; uint8_t digest_ctx[digest->ctxsize]; uint8_t digest_ctx_partial[digest->ctxsize]; uint8_t a[digest->digestsize]; uint8_t out_tmp[digest->digestsize]; size_t frag_len = digest->digestsize; va_list tmp; /* Copy the secret, in case HMAC modifies it */ memcpy ( secret_copy, secret, secret_len ); secret = secret_copy; DBGC2 ( tls, "TLS %p %s secret:\n", tls, digest->name ); DBGC2_HD ( tls, secret, secret_len ); /* Calculate A(1) */ hmac_init ( digest, digest_ctx, secret, &secret_len ); va_copy ( tmp, seeds ); tls_hmac_update_va ( digest, digest_ctx, tmp ); va_end ( tmp ); hmac_final ( digest, digest_ctx, secret, &secret_len, a ); DBGC2 ( tls, "TLS %p %s A(1):\n", tls, digest->name ); DBGC2_HD ( tls, &a, sizeof ( a ) ); /* Generate as much data as required */ while ( out_len ) { /* Calculate output portion */ hmac_init ( digest, digest_ctx, secret, &secret_len ); hmac_update ( digest, digest_ctx, a, sizeof ( a ) ); memcpy ( digest_ctx_partial, digest_ctx, digest->ctxsize ); va_copy ( tmp, seeds ); tls_hmac_update_va ( digest, digest_ctx, tmp ); va_end ( tmp ); hmac_final ( digest, digest_ctx, secret, &secret_len, out_tmp ); /* Copy output */ if ( frag_len > out_len ) frag_len = out_len; memcpy ( out, out_tmp, frag_len ); DBGC2 ( tls, "TLS %p %s output:\n", tls, digest->name ); DBGC2_HD ( tls, out, frag_len ); /* Calculate A(i) */ hmac_final ( digest, digest_ctx_partial, secret, &secret_len, a ); DBGC2 ( tls, "TLS %p %s A(n):\n", tls, digest->name ); DBGC2_HD ( tls, &a, sizeof ( a ) ); out += frag_len; out_len -= frag_len; } }