/** * Parses the work buffer to extract packets * * The work buffer should be filled in with a set of tuples (bh_hdrlen, frame, pad). * The pad extends each packet out to BPF_WORDALIGN. * * If the CCNxMessage PacketLength says it is larger than the read capture length (caplen), * then this is an invalid packet and it will be discarded. This error will result in a * ReadWorkBufferResult_TryAgain condition. * * struct bpf_hdr { * struct BPF_TIMEVAL bh_tstamp; // time stamp * bpf_u_int32 bh_caplen; // length of captured portion * bpf_u_int32 bh_datalen; // original length of packet * u_short bh_hdrlen; // length of bpf header (this struct plus alignment padding) * } * * @param [in] ether An allocated Darwin ethernet. * @param [in] readbuffer A user-provided read buffer. * * @retval ReadWorkBufferResult_Ok A frame was moved from workbuffer to readbuffer * @retval ReadWorkBufferResult_Empty There's not enough bytes in the workbuffer * @retval ReadWorkBufferResult_TryAgain (likely discard) caused this call to fail, but you should try again * * Example: * @code * <#example#> * @endcode */ static _ReadWorkBufferResult _darwinEthernet_ReadWorkBuffer(MetisGenericEther *ether, PARCEventBuffer *readbuffer) { _ReadWorkBufferResult result = ReadWorkBufferResult_Empty; // Make sure we have linear memory for the BPF header struct bpf_hdr *bpfHeader = (struct bpf_hdr *) parcEventBuffer_Pullup(ether->workBuffer, sizeof(struct bpf_hdr)); // make sure we have enough bytes to process the frame // bpfHeader may be NULL if there are not sizeof(struct bpf_hdr) bytes available. if (bpfHeader && parcEventBuffer_GetLength(ether->workBuffer) >= bpfHeader->bh_hdrlen + bpfHeader->bh_caplen) { // (0) Save the needed fields from the bpf header // (1) pop off the bpf header // (2) move the iovec from work buffer to readBuffer. // (3) remove any BPF_WORDALIGN padding to the start of the next packet // (0) Save the needed fields from the bpf header uint16_t hdrlen = bpfHeader->bh_hdrlen; uint32_t caplen = bpfHeader->bh_caplen; // (1) pop off the bpf header parcEventBuffer_Read(ether->workBuffer, NULL, hdrlen); // (1a) Determine the packet length from the fixed header and only transfer that many bytes uint16_t packetlen = _getFrameLengthFromWorkBuffer(ether); if (packetlen <= caplen) { // (2) move the iovec from work buffer to readBuffer. parcEventBuffer_ReadIntoBuffer(ether->workBuffer, readbuffer, packetlen); // (2a) drain off any trailer (i.e. FCS) parcEventBuffer_Read(ether->workBuffer, NULL, caplen - packetlen); result = ReadWorkBufferResult_Ok; } else { if (metisLogger_IsLoggable(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning)) { metisLogger_Log(ether->logger, MetisLoggerFacility_IO, PARCLogLevel_Warning, __func__, "%s reading fd %d discard packetlen %u greater than caplen %u", __func__, ether->etherSocket, packetlen, caplen); } // discard all of caplen parcEventBuffer_Read(ether->workBuffer, NULL, caplen); // tell the caller that this read failed, but they could try again. result = ReadWorkBufferResult_TryAgain; } // (3) remove any BPF_WORDALIGN padding to the start of the next packet size_t alignedLength = BPF_WORDALIGN(hdrlen + caplen); size_t pad = alignedLength - hdrlen - caplen; parcEventBuffer_Read(ether->workBuffer, NULL, pad); } return result; }
static void _resetParser(MetisHopByHopFragmenter *fragmenter) { // throw away the re-assembly buffer and reset state to Idle parcEventBuffer_Read(fragmenter->currentReceiveBuffer, NULL, UINT32_MAX); fragmenter->parserState = _ParserState_Idle; }
TransportMessage * rtaComponent_GetMessage(PARCEventQueue *queue) { PARCEventBuffer *in = parcEventBuffer_GetQueueBufferInput(queue); while (parcEventBuffer_GetLength(in) >= sizeof(TransportMessage *)) { ssize_t len; TransportMessage *tm; RtaConnection *conn; len = parcEventBuffer_Read(in, (void *)&tm, sizeof(&tm)); assertTrue(len == sizeof(TransportMessage *), "parcEventBuffer_Read returned error"); // Is the transport message for an open connection? conn = rtaConnection_GetFromTransport(tm); assertNotNull(conn, "%s GetInfo returnd null connection\n", __func__); if (DEBUG_OUTPUT) { printf("%s queue %-12s tm %p\n", __func__, rtaProtocolStack_GetQueueName(rtaConnection_GetStack(conn), queue), (void *) tm); } (void) rtaConnection_DecrementMessagesInQueue(conn); if (rtaConnection_GetState(conn) != CONN_CLOSED) { parcEventBuffer_Destroy(&in); return tm; } // it's a closed connection if (DEBUG_OUTPUT) { printf("%s clearing connection %p reference in transport\n", __func__, (void *) conn); } // should increment a drop counter (case 908) transportMessage_Destroy(&tm); } parcEventBuffer_Destroy(&in); return NULL; }