summaryrefslogtreecommitdiff
path: root/samples/rust/rust_random.rs
blob: 222d1170a1bcacb0424fa8f85bf9c3e9c37411c5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// SPDX-License-Identifier: GPL-2.0

//! Rust random device.
//!
//! Adapted from Alex Gaynor's original available at
//! <https://github.com/alex/just-use/blob/master/src/lib.rs>.

use kernel::{
    file::{self, File},
    io_buffer::{IoBufferReader, IoBufferWriter},
    prelude::*,
};

module_misc_device! {
    type: RandomFile,
    name: "rust_random",
    author: "Rust for Linux Contributors",
    description: "Just use /dev/urandom: Now with early-boot safety",
    license: "GPL",
}

struct RandomFile;

#[vtable]
impl file::Operations for RandomFile {
    fn open(_data: &(), _file: &File) -> Result {
        Ok(())
    }

    fn read(_this: (), file: &File, buf: &mut impl IoBufferWriter, _: u64) -> Result<usize> {
        let total_len = buf.len();
        let mut chunkbuf = [0; 256];

        while !buf.is_empty() {
            let len = chunkbuf.len().min(buf.len());
            let chunk = &mut chunkbuf[0..len];
            let blocking = (file.flags() & file::flags::O_NONBLOCK) == 0;

            if blocking {
                kernel::random::getrandom(chunk)?;
            } else {
                kernel::random::getrandom_nonblock(chunk)?;
            }
            buf.write_slice(chunk)?;
        }
        Ok(total_len)
    }

    fn write(_this: (), _file: &File, buf: &mut impl IoBufferReader, _: u64) -> Result<usize> {
        let total_len = buf.len();
        let mut chunkbuf = [0; 256];
        while !buf.is_empty() {
            let len = chunkbuf.len().min(buf.len());
            let chunk = &mut chunkbuf[0..len];
            buf.read_slice(chunk)?;
            kernel::random::add_randomness(chunk);
        }
        Ok(total_len)
    }
}