summaryrefslogtreecommitdiffstats
path: root/drivers/ide/ide-iops.c
AgeCommit message (Expand)Author
2016-12-24Replace <asm/uaccess.h> with <linux/uaccess.h> globallyLinus Torvalds
2010-01-19ide: add SATA cable detection supportBartlomiej Zolnierkiewicz
2009-09-15ide: fixup for fujitsu diskWu Zhangjin
2009-08-07ide: fix races in handling of user-space SET XFER commandsBartlomiej Zolnierkiewicz
2009-08-07ide: allow ide_dev_read_id() to be called from the IRQ contextBartlomiej Zolnierkiewicz
2009-06-24ide: add QUANTUM FIREBALLct20 30 with firmware APL.090 to ivb_list[]Bartlomiej Zolnierkiewicz
2009-06-24ide: relax DMA info validity checkingBartlomiej Zolnierkiewicz
2009-06-07ide: add IDE_DFLAG_NIEN_QUIRK device flagBartlomiej Zolnierkiewicz
2009-06-07ide: respect quirk_drives[] list on all controllersBartlomiej Zolnierkiewicz
2009-06-07ide: remove superfluous SELECT_MASK() call from ide_driveid_update()Bartlomiej Zolnierkiewicz
2009-05-22ide: fix 40-wire cable detection for TSST SH-S202* ATAPI devices (v2)Bartlomiej Zolnierkiewicz
2009-04-08ide: refactor tf_read() methodSergei Shtylyov
2009-04-08ide: refactor tf_load() methodSergei Shtylyov
2009-04-08ide: replace IDE_TFLAG_* flags by IDE_VALID_*Sergei Shtylyov
2009-03-31ide: inline SELECT_DRIVE()Sergei Shtylyov
2009-03-31ide: turn selectproc() method into dev_select() method (take 5)Sergei Shtylyov
2009-03-31ide: rename IDE_TFLAG_IN_[HOB_]FEATURESergei Shtylyov
2009-03-31ide: turn set_irq() method into write_devctl() methodSergei Shtylyov
2009-03-31ide: add support for CFA specified transfer modes (take 3)Sergei Shtylyov
2009-03-31ide-iops: only clear DMA words on setting DMA modeSergei Shtylyov
2009-03-27ide: remove ide_execute_pkt_cmd() (v2)Bartlomiej Zolnierkiewicz
2009-03-27ide: add ->dma_timer_expiry method and remove ->dma_exec_cmd one (v2)Bartlomiej Zolnierkiewicz
2009-03-27ide: set hwif->expiry prior to calling [__]ide_set_handler()Bartlomiej Zolnierkiewicz
2009-03-27ide: remove ide_task_t typedefBartlomiej Zolnierkiewicz
2009-03-24ide: use try_to_identify() in ide_driveid_update()Bartlomiej Zolnierkiewicz
2009-03-24ide: clear drive IRQ after re-enabling local IRQs in ide_driveid_update()Bartlomiej Zolnierkiewicz
2009-03-24ide: sanitize SELECT_MASK() usage in ide_driveid_update()Bartlomiej Zolnierkiewicz
2009-03-24ide: shorten timeout value in ide_driveid_update()Bartlomiej Zolnierkiewicz
2009-03-24ide: propagate AltStatus workarounds to ide_driveid_update()Bartlomiej Zolnierkiewicz
2009-03-24ide: fix kmalloc() failure handling in ide_driveid_update()Bartlomiej Zolnierkiewicz
2009-03-24ide: move error handling code to ide-eh.c (v2)Bartlomiej Zolnierkiewicz
2009-03-24ide: checkpatch.pl fixes for ide-iops.cBartlomiej Zolnierkiewicz
2009-03-24ide: fix comments in ide_config_drive_speed()Bartlomiej Zolnierkiewicz
2009-03-24ide: fix printk() levels in [atapi_]reset_pollfunc()Bartlomiej Zolnierkiewicz
2009-03-24ide: move standard I/O code to ide-io-std.cBartlomiej Zolnierkiewicz
2009-03-24ide: move ide_read_bcount_and_ireason() to ide-atapi.cBartlomiej Zolnierkiewicz
2009-03-24ide: move drive_is_ready() to ide-io.cBartlomiej Zolnierkiewicz
2009-03-24ide: remove stale comments from drive_is_ready()Bartlomiej Zolnierkiewicz
2009-03-24ide: add ide_for_each_present_dev() iteratorBartlomiej Zolnierkiewicz
2009-03-05ide-iops: fix odd-length ATAPI PIO transfersSergei Shtylyov
2009-01-14ide: fix accidental LOCKDEP breakage caused by local_irq_set() removalBartlomiej Zolnierkiewicz
2009-01-06ide: move read_sff_dma_status() method to 'struct ide_dma_ops'Sergei Shtylyov
2009-01-06ide: add port and host iteratorsBartlomiej Zolnierkiewicz
2009-01-06ide: dynamic allocation of device structuresBartlomiej Zolnierkiewicz
2009-01-06ide: unexport ide_wait_not_busy()Bartlomiej Zolnierkiewicz
2009-01-06ide: remove local_irq_set() macroBartlomiej Zolnierkiewicz
2009-01-06ide: remove HWIF() macroBartlomiej Zolnierkiewicz
2009-01-06ide: merge ide_hwgroup_t with ide_hwif_t (v2)Bartlomiej Zolnierkiewicz
2008-12-29ide: replace the global ide_lock spinlock by per-hwgroup spinlocks (v2)Bartlomiej Zolnierkiewicz
2008-12-02ide: remove dead code from drive_is_ready()Bartlomiej Zolnierkiewicz
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
use nom::{
    bits, bytes::complete::take, error::FromExternalError, number::complete::be_u16,
    sequence::tuple, IResult, Parser,
};

use super::{
    connect_return::{mconnectreturn, MConnectReturnCode},
    errors::MPacketHeaderError,
    header::{mfixedheader, MPacketHeader, MPacketKind},
    identifier::{mpacketidentifier, MPacketIdentifier},
    qos::{mquality_of_service, MQualityOfService},
    strings::{mstring, MString},
    subscription_acks::{msubscriptionacks, MSubscriptionAcks},
    subscription_request::{msubscriptionrequests, MSubscriptionRequests},
    unsubscription_request::{munsubscriptionrequests, MUnsubscriptionRequests},
    will::MLastWill,
    MSResult,
};

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MPacket<'message> {
    Connect {
        protocol_name: MString<'message>,
        protocol_level: u8,
        clean_session: bool,
        will: Option<MLastWill<'message>>,
        username: Option<MString<'message>>,
        password: Option<&'message [u8]>,
        keep_alive: u16,
        client_id: MString<'message>,
    },
    Connack {
        session_present: bool,
        connect_return_code: MConnectReturnCode,
    },
    Publish {
        dup: bool,
        qos: MQualityOfService,
        retain: bool,
        topic_name: MString<'message>,
        id: Option<MPacketIdentifier>,
        payload: &'message [u8],
    },
    Puback {
        id: MPacketIdentifier,
    },
    Pubrec {
        id: MPacketIdentifier,
    },
    Pubrel {
        id: MPacketIdentifier,
    },
    Pubcomp {
        id: MPacketIdentifier,
    },
    Subscribe {
        id: MPacketIdentifier,
        subscriptions: MSubscriptionRequests<'message>,
    },
    Suback {
        id: MPacketIdentifier,
        subscription_acks: MSubscriptionAcks<'message>,
    },
    Unsubscribe {
        id: MPacketIdentifier,
        unsubscriptions: MUnsubscriptionRequests<'message>,
    },
    Unsuback {
        id: MPacketIdentifier,
    },
    Pingreq,
    Pingresp,
    Disconnect,
}

fn mpayload(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let (input, len) = be_u16(input)?;
    take(len)(input)
}

fn mpacketdata(fixed_header: MPacketHeader, input: &[u8]) -> IResult<&[u8], MPacket> {
    let (input, info) = match fixed_header.kind {
        MPacketKind::Connect => {
            let (input, protocol_name) = mstring(input)?;

            if &*protocol_name != "MQTT" {
                return Err(nom::Err::Error(nom::error::Error::from_external_error(
                    input,
                    nom::error::ErrorKind::MapRes,
                    MPacketHeaderError::InvalidProtocolName(protocol_name.to_string()),
                )));
            }

            let (input, protocol_level) = nom::number::complete::u8(input)?;

            if protocol_level != 4 {
                return Err(nom::Err::Error(nom::error::Error::from_external_error(
                    input,
                    nom::error::ErrorKind::MapRes,
                    MPacketHeaderError::InvalidProtocolLevel(protocol_level),
                )));
            }

            let (
                input,
                (
                    user_name_flag,
                    password_flag,
                    will_retain,
                    will_qos,
                    will_flag,
                    clean_session,
                    reserved,
                ),
            ): (_, (u8, u8, u8, _, u8, u8, u8)) =
                bits::<_, _, nom::error::Error<(&[u8], usize)>, _, _>(tuple((
                    nom::bits::complete::take(1usize),
                    nom::bits::complete::take(1usize),
                    nom::bits::complete::take(1usize),
                    nom::bits::complete::take(2usize),
                    nom::bits::complete::take(1usize),
                    nom::bits::complete::take(1usize),
                    nom::bits::complete::take(1usize),
                )))(input)?;

            if reserved != 0 {
                return Err(nom::Err::Error(nom::error::Error::from_external_error(
                    input,
                    nom::error::ErrorKind::MapRes,
                    MPacketHeaderError::ForbiddenReservedValue,
                )));
            }

            let (input, keep_alive) = be_u16(input)?;

            // Payload

            let (input, client_id) = mstring(input)?;

            let (input, will) = if will_flag == 1 {
                let (input, topic) = mstring(input)?;
                let (input, payload) = mpayload(input)?;
                let retain = will_retain != 0;

                (
                    input,
                    Some(MLastWill {
                        topic,
                        payload,
                        retain,
                        qos: mquality_of_service(will_qos).map_err(|e| {
                            nom::Err::Error(nom::error::Error::from_external_error(
                                input,
                                nom::error::ErrorKind::MapRes,
                                e,
                            ))
                        })?,
                    }),
                )
            } else {
                (input, None)
            };

            let (input, username) = if user_name_flag == 1 {
                mstring.map(Some).parse(input)?
            } else {
                (input, None)
            };

            let (input, password) = if password_flag == 1 {
                mpayload.map(Some).parse(input)?
            } else {
                (input, None)
            };

            (
                input,
                MPacket::Connect {
                    protocol_name,
                    protocol_level,
                    clean_session: clean_session == 1,
                    will,
                    username,
                    password,
                    client_id,
                    keep_alive,
                },
            )
        }
        MPacketKind::Connack => {
            let (input, (reserved, session_present)): (_, (u8, u8)) =
                bits::<_, _, nom::error::Error<(&[u8], usize)>, _, _>(tuple((
                    nom::bits::complete::take(7usize),
                    nom::bits::complete::take(1usize),
                )))(input)?;

            if reserved != 0 {
                return Err(nom::Err::Error(nom::error::Error::from_external_error(
                    input,
                    nom::error::ErrorKind::MapRes,
                    MPacketHeaderError::ForbiddenReservedValue,
                )));
            }

            let (input, connect_return_code) = mconnectreturn(input)?;

            (
                input,
                MPacket::Connack {
                    session_present: session_present == 1,
                    connect_return_code,
                },
            )
        }
        MPacketKind::Publish { dup, qos, retain } => {
            let variable_header_start = input;

            let (input, topic_name) = mstring(input)?;

            let (input, id) = if qos != MQualityOfService::AtMostOnce {
                let (input, id) = mpacketidentifier(input)?;

                (input, Some(id))
            } else {
                (input, None)
            };

            if dup && qos == MQualityOfService::AtMostOnce {
                return Err(nom::Err::Error(nom::error::Error::from_external_error(
                    input,
                    nom::error::ErrorKind::MapRes,
                    MPacketHeaderError::InvalidDupFlag,
                )));
            }

            let variable_header_end = input;
            let variable_header_len = variable_header_start.len() - variable_header_end.len();