nl 0.2.4 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/Rakefile +7 -0
- data/lib/nl/async/dispatcher.rb +199 -0
- data/lib/nl/async/driver.rb +37 -0
- data/lib/nl/async/mailbox.rb +81 -0
- data/lib/nl/async/operation.rb +277 -0
- data/lib/nl/async.rb +13 -0
- data/lib/nl/attribute_set.rb +173 -0
- data/lib/nl/bitfield32.rb +86 -0
- data/lib/nl/blocking_transport.rb +131 -0
- data/lib/nl/connection.rb +61 -0
- data/lib/nl/datagram.rb +22 -0
- data/lib/nl/datatypes.rb +454 -0
- data/lib/nl/decoder.rb +13 -1
- data/lib/nl/endian.rb +10 -0
- data/lib/nl/error.rb +10 -0
- data/lib/nl/exchange.rb +124 -0
- data/lib/nl/family.rb +117 -23
- data/lib/nl/genl/client.rb +104 -0
- data/lib/nl/genl/protocol.rb +59 -0
- data/lib/nl/genl/wire.rb +94 -0
- data/lib/nl/genl.rb +60 -73
- data/lib/nl/notification.rb +112 -0
- data/lib/nl/notification_router.rb +92 -0
- data/lib/nl/raw/client.rb +83 -0
- data/lib/nl/raw/protocol.rb +112 -0
- data/lib/nl/raw/wire.rb +146 -0
- data/lib/nl/raw.rb +104 -0
- data/lib/nl/sequence_allocator.rb +34 -0
- data/lib/nl/socket.rb +15 -12
- data/lib/nl/structured_payload.rb +61 -0
- data/lib/nl/sub_message.rb +94 -0
- data/lib/nl/version.rb +1 -1
- data/lib/nl.rb +10 -12
- data/sig/generated/nl/async/dispatcher.rbs +53 -0
- data/sig/generated/nl/async/driver.rbs +21 -0
- data/sig/generated/nl/async/mailbox.rbs +32 -0
- data/sig/generated/nl/async/operation.rbs +123 -0
- data/sig/generated/nl/async.rbs +9 -0
- data/sig/generated/nl/attribute_set.rbs +50 -0
- data/sig/generated/nl/bitfield32.rbs +41 -0
- data/sig/generated/nl/blocking_transport.rbs +33 -0
- data/sig/generated/nl/connection.rbs +26 -0
- data/sig/generated/nl/datagram.rbs +11 -0
- data/sig/generated/nl/datatypes.rbs +181 -0
- data/sig/generated/nl/decoder.rbs +38 -0
- data/sig/generated/nl/encoder.rbs +29 -0
- data/sig/generated/nl/endian.rbs +28 -0
- data/sig/generated/nl/error.rbs +27 -0
- data/sig/generated/nl/exchange.rbs +75 -0
- data/sig/generated/nl/family.rbs +71 -0
- data/sig/generated/nl/genl/client.rbs +74 -0
- data/sig/generated/nl/genl/protocol.rbs +37 -0
- data/sig/generated/nl/genl/wire.rbs +113 -0
- data/sig/generated/nl/genl.rbs +50 -0
- data/sig/generated/nl/notification.rbs +53 -0
- data/sig/generated/nl/notification_router.rbs +30 -0
- data/sig/generated/nl/raw/client.rbs +50 -0
- data/sig/generated/nl/raw/protocol.rbs +122 -0
- data/sig/generated/nl/raw/wire.rbs +151 -0
- data/sig/generated/nl/raw.rbs +70 -0
- data/sig/generated/nl/sequence_allocator.rbs +15 -0
- data/sig/generated/nl/socket.rbs +40 -0
- data/sig/generated/nl/structured_payload.rbs +25 -0
- data/sig/generated/nl/sub_message.rbs +74 -0
- data/sig/generated/nl/version.rbs +5 -0
- data/sig/generated/nl.rbs +2 -0
- metadata +65 -9
- data/lib/nl/core.rb +0 -94
- data/lib/nl/protocols/genl.rb +0 -55
- data/lib/nl/protocols/raw.rb +0 -395
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nl
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kasumi Hanazuki
|
|
@@ -9,7 +9,8 @@ bindir: exe
|
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
|
-
description:
|
|
12
|
+
description: nl is a general-purpose Netlink implementation for building Ruby applications
|
|
13
|
+
that communicate with Linux kernel APIs or other userspace processes.
|
|
13
14
|
email:
|
|
14
15
|
- kasumi@rollingapple.net
|
|
15
16
|
executables: []
|
|
@@ -22,22 +23,77 @@ files:
|
|
|
22
23
|
- README.md
|
|
23
24
|
- Rakefile
|
|
24
25
|
- lib/nl.rb
|
|
25
|
-
- lib/nl/
|
|
26
|
+
- lib/nl/async.rb
|
|
27
|
+
- lib/nl/async/dispatcher.rb
|
|
28
|
+
- lib/nl/async/driver.rb
|
|
29
|
+
- lib/nl/async/mailbox.rb
|
|
30
|
+
- lib/nl/async/operation.rb
|
|
31
|
+
- lib/nl/attribute_set.rb
|
|
32
|
+
- lib/nl/bitfield32.rb
|
|
33
|
+
- lib/nl/blocking_transport.rb
|
|
34
|
+
- lib/nl/connection.rb
|
|
35
|
+
- lib/nl/datagram.rb
|
|
36
|
+
- lib/nl/datatypes.rb
|
|
26
37
|
- lib/nl/decoder.rb
|
|
27
38
|
- lib/nl/encoder.rb
|
|
28
39
|
- lib/nl/endian.rb
|
|
40
|
+
- lib/nl/error.rb
|
|
41
|
+
- lib/nl/exchange.rb
|
|
29
42
|
- lib/nl/family.rb
|
|
30
43
|
- lib/nl/genl.rb
|
|
31
|
-
- lib/nl/
|
|
32
|
-
- lib/nl/
|
|
44
|
+
- lib/nl/genl/client.rb
|
|
45
|
+
- lib/nl/genl/protocol.rb
|
|
46
|
+
- lib/nl/genl/wire.rb
|
|
47
|
+
- lib/nl/notification.rb
|
|
48
|
+
- lib/nl/notification_router.rb
|
|
49
|
+
- lib/nl/raw.rb
|
|
50
|
+
- lib/nl/raw/client.rb
|
|
51
|
+
- lib/nl/raw/protocol.rb
|
|
52
|
+
- lib/nl/raw/wire.rb
|
|
53
|
+
- lib/nl/sequence_allocator.rb
|
|
33
54
|
- lib/nl/socket.rb
|
|
55
|
+
- lib/nl/structured_payload.rb
|
|
56
|
+
- lib/nl/sub_message.rb
|
|
34
57
|
- lib/nl/version.rb
|
|
58
|
+
- sig/generated/nl.rbs
|
|
59
|
+
- sig/generated/nl/async.rbs
|
|
60
|
+
- sig/generated/nl/async/dispatcher.rbs
|
|
61
|
+
- sig/generated/nl/async/driver.rbs
|
|
62
|
+
- sig/generated/nl/async/mailbox.rbs
|
|
63
|
+
- sig/generated/nl/async/operation.rbs
|
|
64
|
+
- sig/generated/nl/attribute_set.rbs
|
|
65
|
+
- sig/generated/nl/bitfield32.rbs
|
|
66
|
+
- sig/generated/nl/blocking_transport.rbs
|
|
67
|
+
- sig/generated/nl/connection.rbs
|
|
68
|
+
- sig/generated/nl/datagram.rbs
|
|
69
|
+
- sig/generated/nl/datatypes.rbs
|
|
70
|
+
- sig/generated/nl/decoder.rbs
|
|
71
|
+
- sig/generated/nl/encoder.rbs
|
|
72
|
+
- sig/generated/nl/endian.rbs
|
|
73
|
+
- sig/generated/nl/error.rbs
|
|
74
|
+
- sig/generated/nl/exchange.rbs
|
|
75
|
+
- sig/generated/nl/family.rbs
|
|
76
|
+
- sig/generated/nl/genl.rbs
|
|
77
|
+
- sig/generated/nl/genl/client.rbs
|
|
78
|
+
- sig/generated/nl/genl/protocol.rbs
|
|
79
|
+
- sig/generated/nl/genl/wire.rbs
|
|
80
|
+
- sig/generated/nl/notification.rbs
|
|
81
|
+
- sig/generated/nl/notification_router.rbs
|
|
82
|
+
- sig/generated/nl/raw.rbs
|
|
83
|
+
- sig/generated/nl/raw/client.rbs
|
|
84
|
+
- sig/generated/nl/raw/protocol.rbs
|
|
85
|
+
- sig/generated/nl/raw/wire.rbs
|
|
86
|
+
- sig/generated/nl/sequence_allocator.rbs
|
|
87
|
+
- sig/generated/nl/socket.rbs
|
|
88
|
+
- sig/generated/nl/structured_payload.rbs
|
|
89
|
+
- sig/generated/nl/sub_message.rbs
|
|
90
|
+
- sig/generated/nl/version.rbs
|
|
35
91
|
homepage: https://github.com/hanazuki/nl
|
|
36
92
|
licenses:
|
|
37
93
|
- MIT
|
|
38
94
|
metadata:
|
|
39
95
|
homepage_uri: https://github.com/hanazuki/nl
|
|
40
|
-
source_code_uri: https://github.com/hanazuki/nl/tree/v0.
|
|
96
|
+
source_code_uri: https://github.com/hanazuki/nl/tree/v0.4.1
|
|
41
97
|
changelog_uri: https://github.com/hanazuki/nl/blob/master/CHANGELOG.md
|
|
42
98
|
rdoc_options: []
|
|
43
99
|
require_paths:
|
|
@@ -46,14 +102,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
46
102
|
requirements:
|
|
47
103
|
- - ">="
|
|
48
104
|
- !ruby/object:Gem::Version
|
|
49
|
-
version: '3.
|
|
105
|
+
version: '3.4'
|
|
50
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
107
|
requirements:
|
|
52
108
|
- - ">="
|
|
53
109
|
- !ruby/object:Gem::Version
|
|
54
110
|
version: '0'
|
|
55
111
|
requirements: []
|
|
56
|
-
rubygems_version: 4.0.
|
|
112
|
+
rubygems_version: 4.0.16
|
|
57
113
|
specification_version: 4
|
|
58
|
-
summary:
|
|
114
|
+
summary: Netlink protocol support for Ruby
|
|
59
115
|
test_files: []
|
data/lib/nl/core.rb
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# Data types and message handling
|
|
2
|
-
|
|
3
|
-
require_relative 'endian'
|
|
4
|
-
|
|
5
|
-
module Nl
|
|
6
|
-
module Core
|
|
7
|
-
module Constants
|
|
8
|
-
# From include/uapi/linux/netlink.h
|
|
9
|
-
NETLINK_ROUTE = 0
|
|
10
|
-
NETLINK_NETFILTER = 12
|
|
11
|
-
NETLINK_GENERIC = 16
|
|
12
|
-
|
|
13
|
-
NLM_F_REQUEST = 1
|
|
14
|
-
NLM_F_MULTI = 2
|
|
15
|
-
NLM_F_ACK = 4
|
|
16
|
-
NLM_F_ECHO = 8
|
|
17
|
-
NLM_F_DUMP_INTR = 16
|
|
18
|
-
NLM_F_DUMP_FILTERED = 32
|
|
19
|
-
NLM_F_ROOT = 0x100
|
|
20
|
-
NLM_F_MATCH = 0x200
|
|
21
|
-
NLM_F_ATOMIC = 0x400
|
|
22
|
-
NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH
|
|
23
|
-
NLM_F_REPLACE = 0x100
|
|
24
|
-
NLM_F_EXCL = 0x200
|
|
25
|
-
NLM_F_CREATE = 0x400
|
|
26
|
-
NLM_F_APPEND = 0x800
|
|
27
|
-
|
|
28
|
-
NLMSG_ALIGNTO = 4
|
|
29
|
-
NLMSG_HDRLEN = 16
|
|
30
|
-
|
|
31
|
-
NLMSG_NOOP = 0x1
|
|
32
|
-
NLMSG_ERROR = 0x2
|
|
33
|
-
NLMSG_DONE = 0x3
|
|
34
|
-
NLMSG_OVERRUN = 0x4
|
|
35
|
-
|
|
36
|
-
NLMSG_MIN_TYPE = 0x10
|
|
37
|
-
|
|
38
|
-
NLA_F_NESTED = 1 << 15
|
|
39
|
-
NLA_F_NET_BYTEORDER = 1 << 14
|
|
40
|
-
NLA_TYPE_MASK = ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
|
|
41
|
-
|
|
42
|
-
NLA_ALIGNTO = 4
|
|
43
|
-
NLA_HDRLEN = 4
|
|
44
|
-
end
|
|
45
|
-
include Constants
|
|
46
|
-
|
|
47
|
-
NlMsgHdr = Struct.new(:len, :type, :flags, :seq, :pid)
|
|
48
|
-
# Message header
|
|
49
|
-
class NlMsgHdr
|
|
50
|
-
FORMAT = Ractor.make_shareable([
|
|
51
|
-
Endian::Host::U32,
|
|
52
|
-
Endian::Host::U16,
|
|
53
|
-
Endian::Host::U16,
|
|
54
|
-
Endian::Host::U32,
|
|
55
|
-
Endian::Host::U32,
|
|
56
|
-
])
|
|
57
|
-
private_constant :FORMAT
|
|
58
|
-
|
|
59
|
-
def self.decode(decoder)
|
|
60
|
-
obj = new(*decoder.get_values(FORMAT))
|
|
61
|
-
decoder.align_to(Constants::NLMSG_ALIGNTO)
|
|
62
|
-
obj
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def encode(encoder)
|
|
66
|
-
encoder.reserve(Constants::NLMSG_HDRLEN)
|
|
67
|
-
encoder.put_values(FORMAT, to_a)
|
|
68
|
-
encoder.align_to(Constants::NLMSG_ALIGNTO)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
NlAttr = Struct.new(:len, :type)
|
|
73
|
-
# Attribute header
|
|
74
|
-
class NlAttr
|
|
75
|
-
FORMAT = Ractor.make_shareable([
|
|
76
|
-
Endian::Host::U16,
|
|
77
|
-
Endian::Host::U16,
|
|
78
|
-
])
|
|
79
|
-
private_constant :FORMAT
|
|
80
|
-
|
|
81
|
-
def self.decode(decoder)
|
|
82
|
-
obj = new(*decoder.get_values(FORMAT))
|
|
83
|
-
decoder.align_to(Constants::NLA_ALIGNTO)
|
|
84
|
-
obj
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def encode(encoder)
|
|
88
|
-
encoder.reserve(Constants::NLA_HDRLEN)
|
|
89
|
-
encoder.put_values(FORMAT, to_a)
|
|
90
|
-
encoder.align_to(Constants::NLA_ALIGNTO)
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|
data/lib/nl/protocols/genl.rb
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
module Nl
|
|
2
|
-
module Protocols
|
|
3
|
-
# The Generic Netlink protocol
|
|
4
|
-
class Genl < Raw
|
|
5
|
-
GenlMsgHdr = ::Struct.new(:cmd, :version, :reserved)
|
|
6
|
-
class GenlMsgHdr
|
|
7
|
-
FORMAT = Ractor.make_shareable([
|
|
8
|
-
Endian::Host::U8,
|
|
9
|
-
Endian::Host::U8,
|
|
10
|
-
Endian::Host::U16,
|
|
11
|
-
])
|
|
12
|
-
|
|
13
|
-
def self.decode(decoder)
|
|
14
|
-
new(*decoder.get_values(FORMAT))
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def encode(encoder)
|
|
18
|
-
encoder.put_values(FORMAT, to_a)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def initialize(name, family_id: nil)
|
|
23
|
-
super(name, Core::NETLINK_GENERIC)
|
|
24
|
-
@family_id = family_id || default_family_id(name)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def family_id
|
|
28
|
-
@family_id or raise NotImplementedError, "Genetlink family ID for '#{name}' must be resolved via nlctrl"
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def encode_message(encoder, message)
|
|
32
|
-
cmd = message.nlmsg_header.type
|
|
33
|
-
encoder.measure(Endian::Host::U16) do
|
|
34
|
-
message.nlmsg_header.type = family_id
|
|
35
|
-
message.nlmsg_header.encode(encoder)
|
|
36
|
-
message.nlmsg_header.type = cmd
|
|
37
|
-
GenlMsgHdr.new(cmd, 1, 0).encode(encoder)
|
|
38
|
-
message.fixed_header&.encode(encoder)
|
|
39
|
-
message.attributes.encode(encoder)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
class Message < Raw::Message
|
|
44
|
-
def self.decode(decoder, header)
|
|
45
|
-
genlhdr = GenlMsgHdr.decode(decoder)
|
|
46
|
-
super(decoder, header, type: genlhdr.cmd)
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
private def default_family_id(name)
|
|
51
|
-
Nl::Genl::GENL_ID_CTRL if name == 'nlctrl'
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
data/lib/nl/protocols/raw.rb
DELETED
|
@@ -1,395 +0,0 @@
|
|
|
1
|
-
require_relative '../encoder'
|
|
2
|
-
require_relative '../decoder'
|
|
3
|
-
|
|
4
|
-
module Nl
|
|
5
|
-
module Protocols
|
|
6
|
-
# The raw Netlink protocol
|
|
7
|
-
class Raw
|
|
8
|
-
class Done
|
|
9
|
-
end
|
|
10
|
-
class Ack
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
attr_reader :name, :protonum
|
|
14
|
-
|
|
15
|
-
def initialize(name, protonum)
|
|
16
|
-
@name = name
|
|
17
|
-
@protonum = protonum
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def encode_message(encoder, message)
|
|
21
|
-
message.encode(encoder)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def decode_message(decoder, message_class)
|
|
25
|
-
header = NlMsgHdr.decode(decoder)
|
|
26
|
-
decoder.limit(header.len - Core::NLMSG_HDRLEN) do
|
|
27
|
-
message_class.decode(decoder, header)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def send_message(socket, message)
|
|
32
|
-
seq_pid = socket.complete(message.nlmsg_header)
|
|
33
|
-
encoder = Encoder.new
|
|
34
|
-
encode_message(encoder, message)
|
|
35
|
-
socket.sendmsg(encoder.buffer.get_string, 0, Socket.sockaddr_nl(0, 0))
|
|
36
|
-
seq_pid
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def recv_message(socket, seq_pid, message_class)
|
|
40
|
-
data, = socket.recvmsg
|
|
41
|
-
|
|
42
|
-
decoder = Decoder.new(IO::Buffer.for(data))
|
|
43
|
-
while decoder.available?(Core::NLMSG_HDRLEN)
|
|
44
|
-
header = Core::NlMsgHdr.decode(decoder)
|
|
45
|
-
decoder.align_to(Core::NLMSG_ALIGNTO)
|
|
46
|
-
raise binding.irb unless [header.seq, header.pid] == seq_pid
|
|
47
|
-
if header.type < Core::NLMSG_MIN_TYPE
|
|
48
|
-
# Control messages
|
|
49
|
-
case header.type
|
|
50
|
-
when Core::NLMSG_ERROR
|
|
51
|
-
errno = decoder.get_value(Endian::Host::SINT)
|
|
52
|
-
if errno == 0
|
|
53
|
-
yield Ack.new
|
|
54
|
-
else
|
|
55
|
-
yield SystemCallError.new(-errno)
|
|
56
|
-
end
|
|
57
|
-
decoder.skip(header.len - Core::NLMSG_HDRLEN - 4)
|
|
58
|
-
when Core::NLMSG_DONE
|
|
59
|
-
yield Done.new
|
|
60
|
-
decoder.skip(header.len - Core::NLMSG_HDRLEN)
|
|
61
|
-
else
|
|
62
|
-
# just ignore NLMSG_NOOP and other unknown control messages
|
|
63
|
-
decoder.skip(header.len - Core::NLMSG_HDRLEN)
|
|
64
|
-
end
|
|
65
|
-
else
|
|
66
|
-
# Subsystem-specific messages
|
|
67
|
-
decoder.limit(header.len - Core::NLMSG_HDRLEN) do
|
|
68
|
-
decoder.align_to(Core::NLMSG_ALIGNTO)
|
|
69
|
-
yield message_class.decode(decoder, header)
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# @param socket [Socket] Netlink socket
|
|
76
|
-
# @param type [:do, :dump] Request type
|
|
77
|
-
# @param request_class [Class] Request message class
|
|
78
|
-
# @param reply_class [Class] Reply message class
|
|
79
|
-
# @param args [Hash] Request arguments
|
|
80
|
-
def exchange_message(socket, type, request_class, reply_class, args)
|
|
81
|
-
flags = Core::NLM_F_REQUEST
|
|
82
|
-
flags |= type == :dump ? Core::NLM_F_DUMP : Core::NLM_F_ACK
|
|
83
|
-
|
|
84
|
-
request = request_class.from_params(args)
|
|
85
|
-
request.nlmsg_header.flags = flags
|
|
86
|
-
seq_pid = send_message(socket, request)
|
|
87
|
-
|
|
88
|
-
result = [] unless block_given?
|
|
89
|
-
|
|
90
|
-
done = false
|
|
91
|
-
begin
|
|
92
|
-
recv_message(socket, seq_pid, reply_class) do |message|
|
|
93
|
-
case message
|
|
94
|
-
when Done, Ack
|
|
95
|
-
done = true
|
|
96
|
-
when Exception
|
|
97
|
-
raise message
|
|
98
|
-
else
|
|
99
|
-
if block_given?
|
|
100
|
-
yield message
|
|
101
|
-
else
|
|
102
|
-
result << message
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
end until done
|
|
107
|
-
|
|
108
|
-
unless block_given?
|
|
109
|
-
type == :dump ? result : result.first
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
class AttributeSet
|
|
114
|
-
Attribute = Struct.new(:value)
|
|
115
|
-
class Attribute
|
|
116
|
-
def self.decode(decoder)
|
|
117
|
-
value = self::DATATYPE.decode(decoder)
|
|
118
|
-
new(value)
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def encode(encoder)
|
|
122
|
-
self.class::DATATYPE.encode(encoder, self.value)
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def initialize(attributes)
|
|
127
|
-
attr_class = self.class::Attribute
|
|
128
|
-
|
|
129
|
-
attributes.each do |attr|
|
|
130
|
-
unless attr.kind_of?(attr_class)
|
|
131
|
-
raise TypeError, "attribute must be an instance of #{attr_class}"
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
@attributes = Array(attributes)
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def [](type)
|
|
139
|
-
case type
|
|
140
|
-
when Symbol
|
|
141
|
-
attr_class = self.class.by_name(type)
|
|
142
|
-
when Integer
|
|
143
|
-
attr_class = self.class.by_type(type)
|
|
144
|
-
else
|
|
145
|
-
raise TypeError, "attribute type must be a Symbol or an Integer"
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
# TODO: multi-attr
|
|
149
|
-
@attributes.find { it.kind_of?(attr_class) } rescue binding.irb
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def <<(attr)
|
|
153
|
-
attr_class = self.class::Attribute
|
|
154
|
-
unless attr.kind_of?(attr_class)
|
|
155
|
-
raise TypeError, "attribute must be an instance of #{attr_class}"
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
@attributes << attr
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
private def encode1(encoder, attr)
|
|
162
|
-
nlattr = Core::NlAttr.new(0, attr.class::TYPE)
|
|
163
|
-
encoder.measure(Endian::Host::U16) do
|
|
164
|
-
nlattr.encode(encoder)
|
|
165
|
-
attr.encode(encoder)
|
|
166
|
-
end
|
|
167
|
-
encoder.align_to(Core::NLA_ALIGNTO)
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def encode(encoder)
|
|
171
|
-
@attributes.each do |attr|
|
|
172
|
-
encode1(encoder, attr)
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
class << self
|
|
177
|
-
private def decode1(decoder)
|
|
178
|
-
nlattr = Core::NlAttr.decode(decoder)
|
|
179
|
-
attr = decoder.limit(nlattr.len - Core::NLA_HDRLEN) do
|
|
180
|
-
if attr_class = self::BY_TYPE[nlattr.type & Core::NLA_TYPE_MASK]
|
|
181
|
-
attr_class.decode(decoder)
|
|
182
|
-
else
|
|
183
|
-
decoder.skip
|
|
184
|
-
nil
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
decoder.align_to(Core::NLA_ALIGNTO)
|
|
188
|
-
attr
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
def decode(decoder)
|
|
192
|
-
attrs = []
|
|
193
|
-
while decoder.available?
|
|
194
|
-
attr = decode1(decoder)
|
|
195
|
-
attrs << attr
|
|
196
|
-
end
|
|
197
|
-
new(attrs.compact)
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
def build_attributes(**params)
|
|
201
|
-
attrs = params.map do |name, value|
|
|
202
|
-
attr_class = self::BY_NAME[name] or raise "Unknown attribute #{name}"
|
|
203
|
-
attr_class.new(value)
|
|
204
|
-
end
|
|
205
|
-
new(attrs)
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
class Message
|
|
211
|
-
attr_accessor :nlmsg_header, :fixed_header, :attributes
|
|
212
|
-
|
|
213
|
-
def initialize(header, fixed_header = nil, attributes = self.class::ATTRIBUTE_SET.new)
|
|
214
|
-
@nlmsg_header = header
|
|
215
|
-
@fixed_header = fixed_header
|
|
216
|
-
@attributes = attributes
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
def self.from_params(params)
|
|
220
|
-
if self::FIXED_HEADER
|
|
221
|
-
header_params = params.slice(*self::FIXED_HEADER.members)
|
|
222
|
-
fixed_header = self::FIXED_HEADER.new(**header_params)
|
|
223
|
-
end
|
|
224
|
-
attribute_params = params.slice(*self::ATTRIBUTES)
|
|
225
|
-
attributes = self::ATTRIBUTE_SET.build_attributes(**attribute_params)
|
|
226
|
-
|
|
227
|
-
unknown = params.keys - attribute_params.keys
|
|
228
|
-
unknown -= header_params.keys if header_params
|
|
229
|
-
unless unknown.empty?
|
|
230
|
-
raise ArgumentError, "unknown parameters: #{unknown.join(', ')}"
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
header = Core::NlMsgHdr.new(0, self::TYPE, nil, nil, nil)
|
|
234
|
-
new(header, fixed_header, attributes)
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
def append_attribute(attribute)
|
|
238
|
-
@attributes << attribute
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def encode(encoder)
|
|
242
|
-
encoder.measure(Endian::Host::U16) do
|
|
243
|
-
@nlmsg_header.encode(encoder)
|
|
244
|
-
@fixed_header&.encode(encoder)
|
|
245
|
-
@attributes.encode(encoder)
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
def self.decode(decoder, header, type: header.type)
|
|
250
|
-
unless self::TYPE == type
|
|
251
|
-
raise "Expected message type #{self::TYPE}, got #{type}"
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
if fixed_header_class = self::FIXED_HEADER
|
|
255
|
-
fixed_header = fixed_header_class.decode(decoder)
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
attributes = self::ATTRIBUTE_SET.decode(decoder)
|
|
259
|
-
|
|
260
|
-
new(header, fixed_header, attributes)
|
|
261
|
-
end
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
module DataTypes
|
|
265
|
-
class Scalar
|
|
266
|
-
def initialize(type, check)
|
|
267
|
-
@type = type
|
|
268
|
-
@check = check
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def encode(encoder, value)
|
|
272
|
-
value ||= 0
|
|
273
|
-
encoder.put_value(@type, value.tap(&@check))
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
def decode(decoder)
|
|
277
|
-
value = decoder.get_value(@type).tap(&@check)
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
class String
|
|
282
|
-
def initialize(check)
|
|
283
|
-
@check = check
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
def encode(encoder, value)
|
|
287
|
-
encoder.put_zstring(value)
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
def decode(decoder)
|
|
291
|
-
decoder.get_zstring
|
|
292
|
-
end
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
class Binary
|
|
296
|
-
def initialize(check)
|
|
297
|
-
@check = check
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
def encode(encoder, value)
|
|
301
|
-
encoder.put_string(value)
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
def decode(decoder)
|
|
305
|
-
decoder.get_string
|
|
306
|
-
end
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
class Flag
|
|
310
|
-
def encode(encoder, value)
|
|
311
|
-
# flag attribute has no payload; presence encodes true
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
def decode(decoder)
|
|
315
|
-
true
|
|
316
|
-
end
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
# A 32-bit value paired with a selector mask (8 bytes total: value u32 + selector u32)
|
|
320
|
-
class Bitfield32
|
|
321
|
-
def encode(encoder, value)
|
|
322
|
-
v, selector = value.is_a?(Array) ? value : [value, 0xFFFFFFFF]
|
|
323
|
-
encoder.put_value(Endian::Host::U32, v)
|
|
324
|
-
encoder.put_value(Endian::Host::U32, selector)
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
def decode(decoder)
|
|
328
|
-
value = decoder.get_value(Endian::Host::U32)
|
|
329
|
-
selector = decoder.get_value(Endian::Host::U32)
|
|
330
|
-
[value, selector]
|
|
331
|
-
end
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
class Pad
|
|
335
|
-
def initialize(length = nil)
|
|
336
|
-
@length = length
|
|
337
|
-
end
|
|
338
|
-
|
|
339
|
-
def encode(encoder, _value)
|
|
340
|
-
encoder.put_string(?\0.b * @length) if @length
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
def decode(decoder)
|
|
344
|
-
@length ? decoder.skip(@length) : decoder.skip
|
|
345
|
-
nil
|
|
346
|
-
end
|
|
347
|
-
end
|
|
348
|
-
|
|
349
|
-
class NestedAttributes
|
|
350
|
-
def initialize(attribute_set)
|
|
351
|
-
@attribute_set = attribute_set
|
|
352
|
-
end
|
|
353
|
-
|
|
354
|
-
def encode(encoder, value)
|
|
355
|
-
@attribute_set.encode(encoder, value)
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
def decode(decoder)
|
|
359
|
-
@attribute_set.decode(decoder)
|
|
360
|
-
end
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
class IndexedArray
|
|
364
|
-
def initialize(sub_type)
|
|
365
|
-
@sub_type = sub_type
|
|
366
|
-
end
|
|
367
|
-
|
|
368
|
-
def encode(encoder, values)
|
|
369
|
-
values.each_with_index do |value, i|
|
|
370
|
-
nlattr = Core::NlAttr.new(0, i + 1)
|
|
371
|
-
encoder.measure(Endian::Host::U16) do
|
|
372
|
-
nlattr.encode(encoder)
|
|
373
|
-
@sub_type.encode(encoder, value)
|
|
374
|
-
end
|
|
375
|
-
encoder.align_to(Core::NLA_ALIGNTO)
|
|
376
|
-
end
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
def decode(decoder)
|
|
380
|
-
result = []
|
|
381
|
-
while decoder.available?
|
|
382
|
-
nlattr = Core::NlAttr.decode(decoder)
|
|
383
|
-
element = decoder.limit(nlattr.len - Core::NLA_HDRLEN) do
|
|
384
|
-
@sub_type.decode(decoder)
|
|
385
|
-
end
|
|
386
|
-
decoder.align_to(Core::NLA_ALIGNTO)
|
|
387
|
-
result << element
|
|
388
|
-
end
|
|
389
|
-
result
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
end
|
|
393
|
-
end
|
|
394
|
-
end
|
|
395
|
-
end
|