/** * Handle virtual function event * * @v netdev Network device * @v evt Admin queue event descriptor * @v buf Admin queue event data buffer */ void intelxlvf_admin_event ( struct net_device *netdev, struct intelxl_admin_descriptor *evt, union intelxl_admin_buffer *buf ) { struct intelxl_nic *intelxl = netdev->priv; unsigned int vopcode = le32_to_cpu ( evt->vopcode ); /* Record command response if applicable */ if ( vopcode == intelxl->vopcode ) { memcpy ( &intelxl->vbuf, buf, sizeof ( intelxl->vbuf ) ); intelxl->vopcode = 0; intelxl->vret = le32_to_cpu ( evt->vret ); if ( intelxl->vret != 0 ) { DBGC ( intelxl, "INTELXL %p admin VF command %#x " "error %d\n", intelxl, vopcode, intelxl->vret ); DBGC_HDA ( intelxl, virt_to_bus ( evt ), evt, sizeof ( *evt ) ); DBGC_HDA ( intelxl, virt_to_bus ( buf ), buf, le16_to_cpu ( evt->len ) ); } return; } /* Handle unsolicited events */ switch ( vopcode ) { case INTELXL_ADMIN_VF_STATUS: intelxlvf_admin_status ( netdev, &buf->stat ); break; default: DBGC ( intelxl, "INTELXL %p unrecognised VF event %#x:\n", intelxl, vopcode ); DBGC_HDA ( intelxl, 0, evt, sizeof ( *evt ) ); DBGC_HDA ( intelxl, 0, buf, le16_to_cpu ( evt->len ) ); break; } }
/** * Parse OCSP certificate ID * * @v ocsp OCSP check * @v raw ASN.1 cursor * @ret rc Return status code */ static int ocsp_parse_cert_id ( struct ocsp_check *ocsp, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; struct asn1_algorithm *algorithm; int rc; /* Check certID algorithm */ memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_SEQUENCE ); if ( ( rc = asn1_digest_algorithm ( &cursor, &algorithm ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" certID unknown algorithm: %s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } if ( algorithm->digest != &ocsp_digest_algorithm ) { DBGC ( ocsp, "OCSP %p \"%s\" certID wrong algorithm %s\n", ocsp, x509_name ( ocsp->cert ), algorithm->digest->name ); return -EACCES_CERT_MISMATCH; } /* Check remaining certID fields */ asn1_skip ( &cursor, ASN1_SEQUENCE ); if ( asn1_compare ( &cursor, &ocsp->request.cert_id_tail ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n", ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, ocsp->request.cert_id_tail.data, ocsp->request.cert_id_tail.len ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return -EACCES_CERT_MISMATCH; } return 0; }
/** * Report NTLM variable-length data test result * * @v msg Message header * @v msg_len Length of message * @v data Variable-length data descriptor * @v expected Expected message header * @v expected_data Expected variable-length data descriptor * @v field Field name * @v file Test code file * @v line Test code line */ static void ntlm_data_okx ( struct ntlm_header *msg, size_t msg_len, struct ntlm_data *data, struct ntlm_header *expected, struct ntlm_data *expected_data, const char *field, const char *file, unsigned int line ) { size_t offset; size_t len; void *raw; void *expected_raw; /* Verify data lies within message */ okx ( data->len == data->max_len, file, line ); offset = le32_to_cpu ( data->offset ); len = le16_to_cpu ( data->len ); okx ( offset <= msg_len, file, line ); okx ( len <= ( msg_len - offset ), file, line ); /* Verify content matches expected content */ raw = ( ( ( void * ) msg ) + offset ); expected_raw = ( ( ( void * ) expected ) + le32_to_cpu ( expected_data->offset ) ); DBGC ( msg, "NTLM %s expected:\n", field ); DBGC_HDA ( msg, 0, expected_raw, le16_to_cpu ( expected_data->len ) ); DBGC ( msg, "NTLM %s actual:\n", field ); DBGC_HDA ( msg, 0, raw, len ); okx ( data->len == expected_data->len, file, line ); okx ( memcmp ( raw, expected_raw, len ) == 0, file, line ); }
/** * Update the HMAC_DRBG key * * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state * @v data Provided data * @v len Length of provided data * @v single Single byte used in concatenation * * This function carries out the operation * * K = HMAC ( K, V || single || provided_data ) * * as used by hmac_drbg_update() */ static void hmac_drbg_update_key ( struct digest_algorithm *hash, struct hmac_drbg_state *state, const void *data, size_t len, const uint8_t single ) { uint8_t context[ hash->ctxsize ]; size_t out_len = hash->digestsize; DBGC ( state, "HMAC_DRBG_%s %p provided data :\n", hash->name, state ); DBGC_HDA ( state, 0, data, len ); /* Sanity checks */ assert ( hash != NULL ); assert ( state != NULL ); assert ( ( data != NULL ) || ( len == 0 ) ); assert ( ( single == 0x00 ) || ( single == 0x01 ) ); /* K = HMAC ( K, V || single || provided_data ) */ hmac_init ( hash, context, state->key, &out_len ); assert ( out_len == hash->digestsize ); hmac_update ( hash, context, state->value, out_len ); hmac_update ( hash, context, &single, sizeof ( single ) ); hmac_update ( hash, context, data, len ); hmac_final ( hash, context, state->key, &out_len, state->key ); assert ( out_len == hash->digestsize ); DBGC ( state, "HMAC_DRBG_%s %p K = HMAC ( K, V || %#02x || " "provided_data ) :\n", hash->name, state, single ); DBGC_HDA ( state, 0, state->key, out_len ); }
/** * Complete interrupt transfer * * @v ep USB endpoint * @v iobuf I/O buffer * @v rc Completion status code */ static void acm_intr_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { struct acm_device *acm = container_of ( ep, struct acm_device, usbnet.intr ); struct rndis_device *rndis = acm->rndis; struct usb_setup_packet *message; /* Profile completions */ profile_start ( &acm_intr_profiler ); /* Ignore packets cancelled when the endpoint closes */ if ( ! ep->open ) goto ignore; /* Drop packets with errors */ if ( rc != 0 ) { DBGC ( acm, "ACM %p interrupt failed: %s\n", acm, strerror ( rc ) ); DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) ); goto error; } /* Extract message header */ if ( iob_len ( iobuf ) < sizeof ( *message ) ) { DBGC ( acm, "ACM %p underlength interrupt:\n", acm ); DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EINVAL; goto error; } message = iobuf->data; /* Parse message header */ switch ( message->request ) { case cpu_to_le16 ( CDC_RESPONSE_AVAILABLE ) : case cpu_to_le16 ( 0x0001 ) : /* qemu seems to use this value */ acm->responded = 1; break; default: DBGC ( acm, "ACM %p unrecognised interrupt:\n", acm ); DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) ); rc = -ENOTSUP; goto error; } /* Free I/O buffer */ free_iob ( iobuf ); profile_stop ( &acm_intr_profiler ); return; error: rndis_rx_err ( rndis, iob_disown ( iobuf ), rc ); ignore: free_iob ( iobuf ); return; }
/** * Complete bulk IN transfer * * @v ep USB endpoint * @v iobuf I/O buffer * @v rc Completion status code */ static void smsc95xx_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { struct smsc95xx_device *smsc95xx = container_of ( ep, struct smsc95xx_device, usbnet.in ); struct net_device *netdev = smsc95xx->netdev; struct smsc95xx_rx_header *header; /* Profile completions */ profile_start ( &smsc95xx_in_profiler ); /* Ignore packets cancelled when the endpoint closes */ if ( ! ep->open ) { free_iob ( iobuf ); return; } /* Record USB errors against the network device */ if ( rc != 0 ) { DBGC ( smsc95xx, "SMSC95XX %p bulk IN failed: %s\n", smsc95xx, strerror ( rc ) ); goto err; } /* Sanity check */ if ( iob_len ( iobuf ) < ( sizeof ( *header ) + 4 /* CRC */ ) ) { DBGC ( smsc95xx, "SMSC95XX %p underlength bulk IN\n", smsc95xx ); DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EINVAL; goto err; } /* Strip header and CRC */ header = iobuf->data; iob_pull ( iobuf, sizeof ( *header ) ); iob_unput ( iobuf, 4 /* CRC */ ); /* Check for errors */ if ( header->command & cpu_to_le32 ( SMSC95XX_RX_RUNT | SMSC95XX_RX_LATE | SMSC95XX_RX_CRC ) ) { DBGC ( smsc95xx, "SMSC95XX %p receive error (%08x):\n", smsc95xx, le32_to_cpu ( header->command ) ); DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EIO; goto err; } /* Hand off to network stack */ netdev_rx ( netdev, iob_disown ( iobuf ) ); profile_stop ( &smsc95xx_in_profiler ); return; err: /* Hand off to network stack */ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc ); }
/** * Complete bulk IN transfer * * @v ep USB endpoint * @v iobuf I/O buffer * @v rc Completion status code */ static void dm96xx_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device, usbnet.in ); struct net_device *netdev = dm96xx->netdev; struct dm96xx_rx_header *header; /* Ignore packets cancelled when the endpoint closes */ if ( ! ep->open ) { free_iob ( iobuf ); return; } /* Record USB errors against the network device */ if ( rc != 0 ) { DBGC ( dm96xx, "DM96XX %p bulk IN failed: %s\n", dm96xx, strerror ( rc ) ); goto err; } /* Sanity check */ if ( iob_len ( iobuf ) < ( sizeof ( *header ) + 4 /* CRC */ ) ) { DBGC ( dm96xx, "DM96XX %p underlength bulk IN\n", dm96xx ); DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EINVAL; goto err; } /* Strip header and CRC */ header = iobuf->data; iob_pull ( iobuf, sizeof ( *header ) ); iob_unput ( iobuf, 4 /* CRC */ ); /* Check status */ if ( header->rsr & ~DM96XX_RSR_MF ) { DBGC ( dm96xx, "DM96XX %p receive error %02x:\n", dm96xx, header->rsr ); DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EIO; goto err; } /* Hand off to network stack */ netdev_rx ( netdev, iob_disown ( iobuf ) ); return; err: /* Hand off to network stack */ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc ); }
/** * Reseed HMAC_DRBG * * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state * @v entropy Entropy input * @v entropy_len Length of entropy input * @v additional Additional input * @v additional_len Length of additional input * * This is the HMAC_DRBG_Reseed_algorithm function defined in ANS X9.82 * Part 3-2007 Section 10.2.2.2.4 (NIST SP 800-90 Section 10.1.2.4). * * The key, value and reseed counter are updated in-place within the * HMAC_DRBG internal state. */ void hmac_drbg_reseed ( struct digest_algorithm *hash, struct hmac_drbg_state *state, const void *entropy, size_t entropy_len, const void *additional, size_t additional_len ) { uint8_t seed_material[ entropy_len + additional_len ]; DBGC ( state, "HMAC_DRBG_%s %p (re)seed\n", hash->name, state ); /* Sanity checks */ assert ( hash != NULL ); assert ( state != NULL ); assert ( entropy != NULL ); assert ( ( additional != NULL ) || ( additional_len == 0 ) ); /* 1. seed_material = entropy_input || additional_input */ memcpy ( seed_material, entropy, entropy_len ); memcpy ( ( seed_material + entropy_len ), additional, additional_len ); DBGC ( state, "HMAC_DRBG_%s %p seed material :\n", hash->name, state ); DBGC_HDA ( state, 0, seed_material, sizeof ( seed_material ) ); /* 2. ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V ) */ hmac_drbg_update ( hash, state, seed_material, sizeof ( seed_material ) ); /* 3. reseed_counter = 1 */ state->reseed_counter = 1; /* 4. Return V, Key and reseed_counter as the new_working_state */ }
/** * Identify autoboot device * */ void efi_set_autoboot ( void ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; union { EFI_SIMPLE_NETWORK_PROTOCOL *snp; void *interface; } snp; EFI_SIMPLE_NETWORK_MODE *mode; EFI_STATUS efirc; /* Look for an SNP instance on the image's device handle */ if ( ( efirc = bs->OpenProtocol ( efi_loaded_image->DeviceHandle, &efi_simple_network_protocol_guid, &snp.interface, efi_image_handle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ DBGC ( efi_loaded_image, "EFI found no autoboot device\n" ); return; } /* Record autoboot device */ mode = snp.snp->Mode; set_autoboot_ll_addr ( &mode->CurrentAddress, mode->HwAddressSize ); DBGC ( efi_loaded_image, "EFI found autoboot link-layer address:\n" ); DBGC_HDA ( efi_loaded_image, 0, &mode->CurrentAddress, mode->HwAddressSize ); /* Close protocol */ bs->CloseProtocol ( efi_loaded_image->DeviceHandle, &efi_simple_network_protocol_guid, efi_image_handle, NULL ); }
/** * Fill in all variable portions of sBFT * * @v srp SRP device * @ret rc Return status code */ int sbft_fill_data ( struct srp_device *srp ) { struct sbft_scsi_subtable *sbft_scsi = &sbftab.scsi; struct sbft_srp_subtable *sbft_srp = &sbftab.srp; struct sbft_ib_subtable *sbft_ib = &sbftab.ib; struct ib_srp_parameters *ib_params; struct segoff rm_sbftab = { .segment = rm_ds, .offset = __from_data16 ( &sbftab ), }; /* Fill in the SCSI subtable */ memcpy ( &sbft_scsi->lun, &srp->lun, sizeof ( sbft_scsi->lun ) ); /* Fill in the SRP subtable */ memcpy ( &sbft_srp->port_ids, &srp->port_ids, sizeof ( sbft_srp->port_ids ) ); /* Fill in the IB subtable */ assert ( srp->transport == &ib_srp_transport ); ib_params = ib_srp_params ( srp ); memcpy ( &sbft_ib->sgid, &ib_params->sgid, sizeof ( sbft_ib->sgid ) ); memcpy ( &sbft_ib->dgid, &ib_params->dgid, sizeof ( sbft_ib->dgid ) ); memcpy ( &sbft_ib->service_id, &ib_params->service_id, sizeof ( sbft_ib->service_id ) ); sbft_ib->pkey = ib_params->pkey; /* Update checksum */ acpi_fix_checksum ( &sbftab.table.acpi ); DBGC ( &sbftab, "SRP Boot Firmware Table at %04x:%04x:\n", rm_sbftab.segment, rm_sbftab.offset ); DBGC_HDA ( &sbftab, rm_sbftab, &sbftab, sizeof ( sbftab ) ); return 0; }
/** * Get queue configuration * * @v intel Intel device * @v vlan_thing VLAN hand-waving thing to fill in * @ret rc Return status code */ static int intelxvf_mbox_queues ( struct intel_nic *intel, int *vlan_thing ) { union intelvf_msg msg; int rc; /* Send queue configuration message */ memset ( &msg, 0, sizeof ( msg ) ); msg.hdr = INTELVF_MSG_TYPE_GET_QUEUES; if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) { DBGC ( intel, "INTEL %p get queue configuration failed: %s\n", intel, strerror ( rc ) ); return rc; } /* Check response */ if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) !=INTELVF_MSG_TYPE_GET_QUEUES){ DBGC ( intel, "INTEL %p get queue configuration unexpected " "response:\n", intel ); DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) ); return -EPROTO; } /* Check that we were allowed to get the queue configuration */ if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) { DBGC ( intel, "INTEL %p get queue configuration refused\n", intel ); return -EPERM; } /* Extract VLAN hand-waving thing */ *vlan_thing = msg.queues.vlan_thing; return 0; }
/** * Send negotiate API version message * * @v intel Intel device * @v version Requested version * @ret rc Return status code */ static int intelxvf_mbox_version ( struct intel_nic *intel, unsigned int version ) { union intelvf_msg msg; int rc; /* Send set MTU message */ memset ( &msg, 0, sizeof ( msg ) ); msg.hdr = INTELXVF_MSG_TYPE_VERSION; msg.version.version = version; if ( ( rc = intelvf_mbox_msg ( intel, &msg ) ) != 0 ) { DBGC ( intel, "INTEL %p negotiate API version failed: %s\n", intel, strerror ( rc ) ); return rc; } /* Check response */ if ( ( msg.hdr & INTELVF_MSG_TYPE_MASK ) != INTELXVF_MSG_TYPE_VERSION ){ DBGC ( intel, "INTEL %p negotiate API version unexpected " "response:\n", intel ); DBGC_HDA ( intel, 0, &msg, sizeof ( msg ) ); return -EPROTO; } /* Check that this version is supported */ if ( ! ( msg.hdr & INTELVF_MSG_ACK ) ) { DBGC ( intel, "INTEL %p negotiate API version failed\n", intel ); return -EPERM; } return 0; }
/** * Parse OCSP response status * * @v ocsp OCSP check * @v raw ASN.1 cursor * @ret rc Return status code */ static int ocsp_parse_response_status ( struct ocsp_check *ocsp, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; uint8_t status; int rc; /* Enter responseStatus */ memcpy ( &cursor, raw, sizeof ( cursor ) ); if ( ( rc = asn1_enter ( &cursor, ASN1_ENUMERATED ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not locate responseStatus: " "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); return rc; } /* Extract response status */ if ( cursor.len != sizeof ( status ) ) { DBGC ( ocsp, "OCSP %p \"%s\" invalid status:\n", ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return -EINVAL; } memcpy ( &status, cursor.data, sizeof ( status ) ); /* Check response status */ if ( status != OCSP_STATUS_SUCCESSFUL ) { DBGC ( ocsp, "OCSP %p \"%s\" response status %d\n", ocsp, x509_name ( ocsp->cert ), status ); return EPROTO_STATUS ( status ); } return 0; }
/** * Parse OCSP certificate ID * * @v ocsp OCSP check * @v raw ASN.1 cursor * @ret rc Return status code */ static int ocsp_parse_cert_id ( struct ocsp_check *ocsp, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; /* Check certID matches request */ memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_shrink_any ( &cursor ); if ( asn1_compare ( &cursor, &ocsp->request.cert_id ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n", ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, ocsp->request.cert_id.data, ocsp->request.cert_id.len ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return -EACCES_CERT_MISMATCH; } return 0; }
/** * Complete interrupt transfer * * @v ep USB endpoint * @v iobuf I/O buffer * @v rc Completion status code */ static void smsc95xx_intr_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { struct smsc95xx_device *smsc95xx = container_of ( ep, struct smsc95xx_device, usbnet.intr ); struct net_device *netdev = smsc95xx->netdev; struct smsc95xx_interrupt *intr; /* Profile completions */ profile_start ( &smsc95xx_intr_profiler ); /* Ignore packets cancelled when the endpoint closes */ if ( ! ep->open ) goto done; /* Record USB errors against the network device */ if ( rc != 0 ) { DBGC ( smsc95xx, "SMSC95XX %p interrupt failed: %s\n", smsc95xx, strerror ( rc ) ); DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) ); netdev_rx_err ( netdev, NULL, rc ); goto done; } /* Extract interrupt data */ if ( iob_len ( iobuf ) != sizeof ( *intr ) ) { DBGC ( smsc95xx, "SMSC95XX %p malformed interrupt\n", smsc95xx ); DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) ); netdev_rx_err ( netdev, NULL, rc ); goto done; } intr = iobuf->data; /* Record interrupt status */ smsc95xx->int_sts = le32_to_cpu ( intr->int_sts ); profile_stop ( &smsc95xx_intr_profiler ); done: /* Free I/O buffer */ free_iob ( iobuf ); }
/** * Parse OCSP certificates * * @v ocsp OCSP check * @v raw ASN.1 cursor * @ret rc Return status code */ static int ocsp_parse_certs ( struct ocsp_check *ocsp, const struct asn1_cursor *raw ) { struct ocsp_response *response = &ocsp->response; struct asn1_cursor cursor; struct x509_certificate *cert; int rc; /* Enter certs */ memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); asn1_enter ( &cursor, ASN1_SEQUENCE ); /* Parse certificate, if present. The data structure permits * multiple certificates, but the protocol requires that the * OCSP signing certificate must either be the issuer itself, * or must be directly issued by the issuer (see RFC2560 * section 4.2.2.2 "Authorized Responders"). We therefore * need to identify only the single certificate matching the * Responder ID. */ while ( cursor.len ) { /* Parse certificate */ if ( ( rc = x509_certificate ( cursor.data, cursor.len, &cert ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not parse " "certificate: %s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return rc; } /* Use if this certificate matches the responder ID */ if ( response->responder.compare ( ocsp, cert ) == 0 ) { response->signer = cert; DBGC2 ( ocsp, "OCSP %p \"%s\" response is signed by ", ocsp, x509_name ( ocsp->cert ) ); DBGC2 ( ocsp, "\"%s\"\n", x509_name ( response->signer ) ); return 0; } /* Otherwise, discard this certificate */ x509_put ( cert ); asn1_skip_any ( &cursor ); } DBGC ( ocsp, "OCSP %p \"%s\" missing responder certificate\n", ocsp, x509_name ( ocsp->cert ) ); return -EACCES_NO_RESPONDER; }
/** * Complete interrupt transfer * * @v ep USB endpoint * @v iobuf I/O buffer * @v rc Completion status code */ static void dm96xx_intr_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device, usbnet.intr ); struct net_device *netdev = dm96xx->netdev; struct dm96xx_interrupt *intr; size_t len = iob_len ( iobuf ); /* Ignore packets cancelled when the endpoint closes */ if ( ! ep->open ) goto done; /* Record USB errors against the network device */ if ( rc != 0 ) { DBGC ( dm96xx, "DM96XX %p interrupt failed: %s\n", dm96xx, strerror ( rc ) ); DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); netdev_rx_err ( netdev, NULL, rc ); goto done; } /* Extract message header */ if ( len < sizeof ( *intr ) ) { DBGC ( dm96xx, "DM96XX %p underlength interrupt:\n", dm96xx ); DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); netdev_rx_err ( netdev, NULL, -EINVAL ); goto done; } intr = iobuf->data; /* Update link status */ dm96xx_link_nsr ( dm96xx, intr->nsr ); done: /* Free I/O buffer */ free_iob ( iobuf ); }
/** * Handle SRP SCSI response * * @v srp SRP device * @v iobuf I/O buffer * @ret rc Returns status code */ static int srp_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) { struct srp_rsp *rsp = iobuf->data; int rc; DBGC2 ( srp, "SRP %p RX SCSI response tag %08x%08x\n", srp, ntohl ( rsp->tag.dwords[0] ), ntohl ( rsp->tag.dwords[1] ) ); /* Sanity check */ if ( iob_len ( iobuf ) < sizeof ( *rsp ) ) { DBGC ( srp, "SRP %p RX SCSI response too short (%zd bytes)\n", srp, iob_len ( iobuf ) ); rc = -EINVAL; goto out; } /* Report SCSI errors */ if ( rsp->status != 0 ) { DBGC ( srp, "SRP %p response status %02x\n", srp, rsp->status ); if ( srp_rsp_sense_data ( rsp ) ) { DBGC ( srp, "SRP %p sense data:\n", srp ); DBGC_HDA ( srp, 0, srp_rsp_sense_data ( rsp ), srp_rsp_sense_data_len ( rsp ) ); } } if ( rsp->valid & ( SRP_RSP_VALID_DOUNDER | SRP_RSP_VALID_DOOVER ) ) { DBGC ( srp, "SRP %p response data-out %srun by %#x bytes\n", srp, ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? "under" : "over" ), ntohl ( rsp->data_out_residual_count ) ); } if ( rsp->valid & ( SRP_RSP_VALID_DIUNDER | SRP_RSP_VALID_DIOVER ) ) { DBGC ( srp, "SRP %p response data-in %srun by %#x bytes\n", srp, ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? "under" : "over" ), ntohl ( rsp->data_in_residual_count ) ); } srp->command->status = rsp->status; /* Mark SCSI command as complete */ srp_scsi_done ( srp, 0 ); rc = 0; out: free_iob ( iobuf ); return rc; }
/** * Receive control packet * * @v acm USB RNDIS device * @ret rc Return status code */ static int acm_control_receive ( struct acm_device *acm ) { struct rndis_device *rndis = acm->rndis; struct usb_device *usb = acm->usb; struct io_buffer *iobuf; struct rndis_header *header; size_t mtu = ACM_RESPONSE_MTU; size_t len; int rc; /* Allocate I/O buffer */ iobuf = alloc_iob ( mtu ); if ( ! iobuf ) { rc = -ENOMEM; goto err_alloc; } /* Get encapsulated response */ if ( ( rc = cdc_get_encapsulated_response ( usb, acm->usbnet.comms, iobuf->data, mtu ) ) != 0 ){ DBGC ( acm, "ACM %p could not get encapsulated response: %s\n", acm, strerror ( rc ) ); goto err_get_response; } /* Fix up buffer length */ header = iobuf->data; len = le32_to_cpu ( header->len ); if ( len > mtu ) { DBGC ( acm, "ACM %p overlength encapsulated response\n", acm ); DBGC_HDA ( acm, 0, iobuf->data, mtu ); rc = -EPROTO; goto err_len; } iob_put ( iobuf, len ); /* Hand off to RNDIS */ rndis_rx ( rndis, iob_disown ( iobuf ) ); return 0; err_len: err_get_response: free_iob ( iobuf ); err_alloc: return rc; }
/** * Handle status change event * * @v netdev Network device * @v stat Status change event */ static void intelxlvf_admin_status ( struct net_device *netdev, struct intelxl_admin_vf_status_buffer *stat ) { struct intelxl_nic *intelxl = netdev->priv; /* Handle event */ switch ( stat->event ) { case cpu_to_le32 ( INTELXL_ADMIN_VF_STATUS_LINK ): intelxlvf_admin_link ( netdev, &stat->data.link ); break; default: DBGC ( intelxl, "INTELXL %p unrecognised status change " "event %#x:\n", intelxl, le32_to_cpu ( stat->event ) ); DBGC_HDA ( intelxl, 0, stat, sizeof ( *stat ) ); break; } }
/** * Parse OCSP response type * * @v ocsp OCSP check * @v raw ASN.1 cursor * @ret rc Return status code */ static int ocsp_parse_response_type ( struct ocsp_check *ocsp, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; /* Enter responseType */ memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_OID ); /* Check responseType is "basic" */ if ( asn1_compare ( &oid_basic_response_type_cursor, &cursor ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" response type not supported:\n", ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return -ENOTSUP_RESPONSE_TYPE; } return 0; }
/** * Update the HMAC_DRBG value * * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state * @v data Provided data * @v len Length of provided data * @v single Single byte used in concatenation * * This function carries out the operation * * V = HMAC ( K, V ) * * as used by hmac_drbg_update() and hmac_drbg_generate() */ static void hmac_drbg_update_value ( struct digest_algorithm *hash, struct hmac_drbg_state *state ) { uint8_t context[ hash->ctxsize ]; size_t out_len = hash->digestsize; /* Sanity checks */ assert ( hash != NULL ); assert ( state != NULL ); /* V = HMAC ( K, V ) */ hmac_init ( hash, context, state->key, &out_len ); assert ( out_len == hash->digestsize ); hmac_update ( hash, context, state->value, out_len ); hmac_final ( hash, context, state->key, &out_len, state->value ); assert ( out_len == hash->digestsize ); DBGC ( state, "HMAC_DRBG_%s %p V = HMAC ( K, V ) :\n", hash->name, state ); DBGC_HDA ( state, 0, state->value, out_len ); }
/** * Initialise root certificate * * The list of trusted root certificates can be specified at build * time using the TRUST= build parameter. If no certificates are * specified, then the default iPXE root CA certificate is trusted. * * If no certificates were explicitly specified, then we allow the * list of trusted root certificate fingerprints to be overridden * using the "trust" setting, but only at the point of iPXE * initialisation. This prevents untrusted sources of settings * (e.g. DHCP) from subverting the chain of trust, while allowing * trustworthy sources (e.g. VMware GuestInfo or non-volatile stored * options) to specify the trusted root certificate without requiring * a rebuild. */ static void rootcert_init ( void ) { void *external = NULL; int len; int rc; /* Allow trusted root certificates to be overridden only if * not explicitly specified at build time. */ if ( ALLOW_TRUST_OVERRIDE ) { /* Fetch copy of "trust" setting, if it exists. This * memory will never be freed. */ len = fetch_setting_copy ( NULL, &trust_setting, &external ); if ( len < 0 ) { rc = len; DBGC ( &root_certificates, "ROOTCERT cannot fetch " "trusted root certificate fingerprints: %s\n", strerror ( rc ) ); /* No way to prevent startup; fail safe by * trusting no certificates. */ root_certificates.count = 0; return; } /* Use certificates from "trust" setting, if present */ if ( external ) { root_certificates.fingerprints = external; root_certificates.count = ( len / FINGERPRINT_LEN ); } } DBGC ( &root_certificates, "ROOTCERT using %d %s certificate(s):\n", root_certificates.count, ( external ? "external" : "built-in" )); DBGC_HDA ( &root_certificates, 0, root_certificates.fingerprints, ( root_certificates.count * FINGERPRINT_LEN ) ); }
/** * Locate ACPI table * * @v rsdt ACPI root system description table * @v signature Requested table signature * @v index Requested index of table with this signature * @ret table Table, or UNULL if not found */ userptr_t acpi_find ( userptr_t rsdt, uint32_t signature, unsigned int index ) { struct acpi_header acpi; struct acpi_rsdt *rsdtab; typeof ( rsdtab->entry[0] ) entry; userptr_t table; size_t len; unsigned int count; unsigned int i; /* Read RSDT header */ copy_from_user ( &acpi, rsdt, 0, sizeof ( acpi ) ); if ( acpi.signature != cpu_to_le32 ( RSDT_SIGNATURE ) ) { DBGC ( rsdt, "RSDT %#08lx has invalid signature:\n", user_to_phys ( rsdt, 0 ) ); DBGC_HDA ( rsdt, user_to_phys ( rsdt, 0 ), &acpi, sizeof ( acpi ) ); return UNULL; } len = le32_to_cpu ( acpi.length ); if ( len < sizeof ( rsdtab->acpi ) ) { DBGC ( rsdt, "RSDT %#08lx has invalid length:\n", user_to_phys ( rsdt, 0 ) ); DBGC_HDA ( rsdt, user_to_phys ( rsdt, 0 ), &acpi, sizeof ( acpi ) ); return UNULL; } /* Calculate number of entries */ count = ( ( len - sizeof ( rsdtab->acpi ) ) / sizeof ( entry ) ); /* Search through entries */ for ( i = 0 ; i < count ; i++ ) { /* Get table address */ copy_from_user ( &entry, rsdt, offsetof ( typeof ( *rsdtab ), entry[i] ), sizeof ( entry ) ); /* Read table header */ table = phys_to_user ( entry ); copy_from_user ( &acpi.signature, table, 0, sizeof ( acpi.signature ) ); /* Check table signature */ if ( acpi.signature != cpu_to_le32 ( signature ) ) continue; /* Check index */ if ( index-- ) continue; DBGC ( rsdt, "RSDT %#08lx found %s at %08lx\n", user_to_phys ( rsdt, 0 ), acpi_name ( signature ), user_to_phys ( table, 0 ) ); return table; } DBGC ( rsdt, "RSDT %#08lx could not find %s\n", user_to_phys ( rsdt, 0 ), acpi_name ( signature ) ); return UNULL; }
/** * Receive Fibre Channel ELS frame * * @v els Fibre Channel ELS transaction * @v iobuf I/O buffer * @v meta Data transfer metadata * @ret rc Return status code */ static int fc_els_rx ( struct fc_els *els, struct io_buffer *iobuf, struct xfer_metadata *meta ) { struct fc_els_frame_common *frame = iobuf->data; struct sockaddr_fc *src = ( ( struct sockaddr_fc * ) meta->src ); struct sockaddr_fc *dest = ( ( struct sockaddr_fc * ) meta->dest ); size_t len = iob_len ( iobuf ); int rc; /* Sanity check */ if ( len < sizeof ( *frame ) ) { DBGC ( els, FCELS_FMT " received underlength frame:\n", FCELS_ARGS ( els ) ); DBGC_HDA ( els, 0, frame, len ); rc = -EINVAL; goto done; } if ( ! src ) { DBGC ( els, FCELS_FMT " received frame missing source " "address:\n", FCELS_ARGS ( els ) ); rc = -EINVAL; goto done; } if ( ! dest ) { DBGC ( els, FCELS_FMT " received frame missing destination " "address:\n", FCELS_ARGS ( els ) ); rc = -EINVAL; goto done; } /* Check for rejection responses */ if ( fc_els_is_request ( els ) && ( frame->command != FC_ELS_LS_ACC ) ) { DBGC ( els, FCELS_FMT " rejected:\n", FCELS_ARGS ( els ) ); DBGC_HDA ( els, 0, frame, len ); rc = -EACCES; goto done; } /* Update port IDs */ memcpy ( &els->port_id, &dest->sfc_port_id, sizeof ( els->port_id ) ); memcpy ( &els->peer_port_id, &src->sfc_port_id, sizeof ( els->peer_port_id ) ); /* Determine handler, if necessary */ if ( ! els->handler ) els->handler = fc_els_detect ( els, frame, len ); if ( ! els->handler ) els->handler = &fc_els_unknown_handler; DBGC2 ( els, FCELS_FMT " received:\n", FCELS_ARGS ( els ) ); DBGC2_HDA ( els, 0, frame, len ); /* Handle received frame */ if ( ( rc = els->handler->rx ( els, frame, len ) ) != 0 ) { DBGC ( els, FCELS_FMT " could not handle received frame: " "%s\n", FCELS_ARGS ( els ), strerror ( rc ) ); DBGC_HDA ( els, 0, frame, len ); goto done; } done: /* Free I/O buffer */ free_iob ( iobuf ); /* Close transaction */ fc_els_close ( els, rc ); return rc; }
/** * Parse OCSP responses * * @v ocsp OCSP check * @v raw ASN.1 cursor * @ret rc Return status code */ static int ocsp_parse_responses ( struct ocsp_check *ocsp, const struct asn1_cursor *raw ) { struct ocsp_response *response = &ocsp->response; struct asn1_cursor cursor; int rc; /* Enter responses */ memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_SEQUENCE ); /* Enter first singleResponse */ asn1_enter ( &cursor, ASN1_SEQUENCE ); /* Parse certID */ if ( ( rc = ocsp_parse_cert_id ( ocsp, &cursor ) ) != 0 ) return rc; asn1_skip_any ( &cursor ); /* Check certStatus */ if ( asn1_type ( &cursor ) != ASN1_IMPLICIT_TAG ( 0 ) ) { DBGC ( ocsp, "OCSP %p \"%s\" non-good certStatus:\n", ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return -EACCES_CERT_STATUS; } asn1_skip_any ( &cursor ); /* Parse thisUpdate */ if ( ( rc = asn1_generalized_time ( &cursor, &response->this_update ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not parse thisUpdate: %s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" this update was at time %lld\n", ocsp, x509_name ( ocsp->cert ), response->this_update ); asn1_skip_any ( &cursor ); /* Parse nextUpdate, if present */ if ( asn1_type ( &cursor ) == ASN1_EXPLICIT_TAG ( 0 ) ) { asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); if ( ( rc = asn1_generalized_time ( &cursor, &response->next_update ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not parse " "nextUpdate: %s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" next update is at time %lld\n", ocsp, x509_name ( ocsp->cert ), response->next_update ); } else { /* If no nextUpdate is present, this indicates that * "newer revocation information is available all the * time". Actually, this indicates that there is no * point to performing the OCSP check, since an * attacker could replay the response at any future * time and it would still be valid. */ DBGC ( ocsp, "OCSP %p \"%s\" responder is a moron\n", ocsp, x509_name ( ocsp->cert ) ); response->next_update = time ( NULL ); } return 0; }
/** * Generate pseudorandom bits using HMAC_DRBG * * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state * @v additional Additional input * @v additional_len Length of additional input * @v data Output buffer * @v len Length of output buffer * @ret rc Return status code * * This is the HMAC_DRBG_Generate_algorithm function defined in ANS X9.82 * Part 3-2007 Section 10.2.2.2.5 (NIST SP 800-90 Section 10.1.2.5). * * Requests must be for an integral number of bytes. * * The key, value and reseed counter are updated in-place within the * HMAC_DRBG internal state. * * Note that the only permitted error is "reseed required". */ int hmac_drbg_generate ( struct digest_algorithm *hash, struct hmac_drbg_state *state, const void *additional, size_t additional_len, void *data, size_t len ) { size_t out_len = hash->digestsize; void *orig_data = data; size_t orig_len = len; size_t frag_len; DBGC ( state, "HMAC_DRBG_%s %p generate\n", hash->name, state ); /* Sanity checks */ assert ( hash != NULL ); assert ( state != NULL ); assert ( data != NULL ); assert ( ( additional != NULL ) || ( additional_len == 0 ) ); /* 1. If reseed_counter > reseed_interval, then return an * indication that a reseed is required */ if ( state->reseed_counter > HMAC_DRBG_RESEED_INTERVAL ) { DBGC ( state, "HMAC_DRBG_%s %p reseed interval exceeded\n", hash->name, state ); return -ESTALE; } /* 2. If additional_input != Null, then * ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V ) */ if ( additional_len ) hmac_drbg_update ( hash, state, additional, additional_len ); /* 3. temp = Null * 4. While ( len ( temp ) < requested_number_of_bits ) do: */ while ( len ) { /* 4.1 V = HMAC ( Key, V ) */ hmac_drbg_update_value ( hash, state ); /* 4.2. temp = temp || V * 5. returned_bits = Leftmost requested_number_of_bits * of temp */ frag_len = len; if ( frag_len > out_len ) frag_len = out_len; memcpy ( data, state->value, frag_len ); data += frag_len; len -= frag_len; } /* 6. ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V ) */ hmac_drbg_update ( hash, state, additional, additional_len ); /* 7. reseed_counter = reseed_counter + 1 */ state->reseed_counter++; DBGC ( state, "HMAC_DRBG_%s %p generated :\n", hash->name, state ); DBGC_HDA ( state, 0, orig_data, orig_len ); /* 8. Return SUCCESS, returned_bits, and the new values of * Key, V and reseed_counter as the new_working_state */ return 0; }
/** * Distribute entropy throughout a buffer * * @v hash Underlying hash algorithm * @v input Input data * @v input_len Length of input data, in bytes * @v output Output buffer * @v output_len Length of output buffer, in bytes * * This is the Hash_df function defined in ANS X9.82 Part 3-2007 * Section 10.5.2 (NIST SP 800-90 Section 10.4.1). * * The number of bits requested is implicit in the length of the * output buffer. Requests must be for an integral number of bytes. * * The output buffer is filled incrementally with each iteration of * the central loop, rather than constructing an overall "temp" and * then taking the leftmost(no_of_bits_to_return) bits. * * There is no way for the Hash_df function to fail. The returned * status SUCCESS is implicit. */ void hash_df ( struct digest_algorithm *hash, const void *input, size_t input_len, void *output, size_t output_len ) { uint8_t context[hash->ctxsize]; uint8_t digest[hash->digestsize]; size_t frag_len; struct { uint8_t pad[3]; uint8_t counter; uint32_t no_of_bits_to_return; } __attribute__ (( packed )) prefix; void *temp; size_t remaining; DBGC ( &hash_df, "HASH_DF input:\n" ); DBGC_HDA ( &hash_df, 0, input, input_len ); /* Sanity checks */ assert ( input != NULL ); assert ( output != NULL ); /* 1. temp = the Null string * 2. len = ceil ( no_of_bits_to_return / outlen ) * * (Nothing to do. We fill the output buffer incrementally, * rather than constructing the complete "temp" in-memory. * "len" is implicit in the number of iterations required to * fill the output buffer, and so is not calculated * explicitly.) */ /* 3. counter = an 8-bit binary value representing the integer "1" */ prefix.counter = 1; /* 4. For i = 1 to len do */ for ( temp = output, remaining = output_len ; remaining > 0 ; ) { /* Comment: in step 5.1 (sic), no_of_bits_to_return is * used as a 32-bit string. * * 4.1 temp = temp || Hash ( counter || no_of_bits_to_return * || input_string ) */ prefix.no_of_bits_to_return = htonl ( output_len * 8 ); digest_init ( hash, context ); digest_update ( hash, context, &prefix.counter, ( sizeof ( prefix ) - offsetof ( typeof ( prefix ), counter ) ) ); digest_update ( hash, context, input, input_len ); digest_final ( hash, context, digest ); /* 4.2 counter = counter + 1 */ prefix.counter++; /* 5. requested_bits = Leftmost ( no_of_bits_to_return ) * of temp * * (We fill the output buffer incrementally.) */ frag_len = sizeof ( digest ); if ( frag_len > remaining ) frag_len = remaining; memcpy ( temp, digest, frag_len ); temp += frag_len; remaining -= frag_len; } /* 6. Return SUCCESS and requested_bits */ DBGC ( &hash_df, "HASH_DF output:\n" ); DBGC_HDA ( &hash_df, 0, output, output_len ); return; }