nl 0.3.0 → 0.4.2
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 +15 -0
- data/Rakefile +7 -0
- data/lib/nl/async/dispatcher.rb +16 -16
- data/lib/nl/async/driver.rb +0 -2
- data/lib/nl/async/mailbox.rb +0 -2
- data/lib/nl/async/operation.rb +0 -2
- data/lib/nl/async.rb +0 -2
- data/lib/nl/attribute_set.rb +173 -0
- data/lib/nl/bitfield32.rb +86 -0
- data/lib/nl/blocking_transport.rb +12 -12
- data/lib/nl/connection.rb +7 -9
- data/lib/nl/datagram.rb +7 -9
- data/lib/nl/datatypes.rb +454 -0
- data/lib/nl/decoder.rb +4 -0
- data/lib/nl/endian.rb +9 -0
- data/lib/nl/exchange.rb +40 -18
- data/lib/nl/family.rb +50 -55
- data/lib/nl/genl/client.rb +105 -0
- data/lib/nl/genl/protocol.rb +59 -0
- data/lib/nl/genl/wire.rb +95 -0
- data/lib/nl/genl.rb +60 -62
- data/lib/nl/notification.rb +3 -6
- data/lib/nl/notification_router.rb +30 -23
- data/lib/nl/raw/client.rb +83 -0
- data/lib/nl/raw/protocol.rb +112 -0
- data/lib/nl/raw/wire.rb +147 -0
- data/lib/nl/raw.rb +104 -0
- data/lib/nl/sequence_allocator.rb +0 -2
- data/lib/nl/socket.rb +21 -5
- 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 +5 -6
- 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 +29 -0
- data/sig/generated/nl/error.rbs +27 -0
- data/sig/generated/nl/exchange.rbs +75 -0
- data/sig/generated/nl/family.rbs +89 -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 +49 -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 +59 -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 +48 -7
- data/lib/nl/core.rb +0 -94
- data/lib/nl/genl/connection.rb +0 -89
- data/lib/nl/protocols/genl.rb +0 -74
- data/lib/nl/protocols/raw.rb +0 -460
data/lib/nl/protocols/raw.rb
DELETED
|
@@ -1,460 +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 NotificationRouting
|
|
9
|
-
def family_key(_protocol) = nil
|
|
10
|
-
def frame_key(_header) = nil
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
NOTIFICATION_ROUTING = NotificationRouting.new.freeze
|
|
14
|
-
|
|
15
|
-
AckFrame = Data.define(:header)
|
|
16
|
-
ErrorFrame = Data.define(:header, :errno)
|
|
17
|
-
DoneFrame = Data.define(:header, :errno)
|
|
18
|
-
UnknownFrame = Data.define(:header)
|
|
19
|
-
DataFrame = Data.define(:header, :message)
|
|
20
|
-
Request = Data.define(:type, :flags, :message)
|
|
21
|
-
|
|
22
|
-
attr_reader :name, :protonum
|
|
23
|
-
|
|
24
|
-
def initialize(name, protonum)
|
|
25
|
-
@name = name
|
|
26
|
-
@protonum = protonum
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def encode_message(encoder, request, seq:, pid:)
|
|
30
|
-
header = Core::NlMsgHdr.new(0, request.type, request.flags, seq, pid)
|
|
31
|
-
encoder.measure(Endian::Host::U16) do
|
|
32
|
-
header.encode(encoder)
|
|
33
|
-
request.message.encode(encoder)
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def decode_message(decoder, message_class)
|
|
38
|
-
header = NlMsgHdr.decode(decoder)
|
|
39
|
-
decoder.limit(header.len - Core::NLMSG_HDRLEN) do
|
|
40
|
-
DataFrame.new(header:, message: message_class.decode(decoder, type: header.type))
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Decodes one frame using the reply class associated with its sequence.
|
|
45
|
-
def decode_frame(header, payload, message_class)
|
|
46
|
-
decoder = Decoder.new(payload)
|
|
47
|
-
if header.type < Core::NLMSG_MIN_TYPE
|
|
48
|
-
case header.type
|
|
49
|
-
when Core::NLMSG_ERROR
|
|
50
|
-
errno = decoder.get_value(Endian::Host::SINT)
|
|
51
|
-
if errno.positive?
|
|
52
|
-
raise ProtocolViolation, "expected zero or negative NLMSG_ERROR errno, got #{errno}"
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
errno.zero? ? AckFrame.new(header:) : ErrorFrame.new(header:, errno: -errno)
|
|
56
|
-
when Core::NLMSG_DONE
|
|
57
|
-
return DoneFrame.new(header:, errno: nil) unless decoder.available?
|
|
58
|
-
|
|
59
|
-
errno = decoder.get_value(Endian::Host::SINT)
|
|
60
|
-
if errno.positive?
|
|
61
|
-
raise ProtocolViolation, "expected zero or negative NLMSG_DONE errno, got #{errno}"
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
DoneFrame.new(header:, errno: errno.negative? ? -errno : nil)
|
|
65
|
-
else
|
|
66
|
-
UnknownFrame.new(header:)
|
|
67
|
-
end
|
|
68
|
-
else
|
|
69
|
-
raise ArgumentError, 'reply class is required for a data message' unless message_class
|
|
70
|
-
|
|
71
|
-
DataFrame.new(header:, message: message_class.decode(decoder, type: header.type))
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def send_message(socket, request, seq:, pid:)
|
|
76
|
-
encoder = Encoder.new
|
|
77
|
-
encode_message(encoder, request, seq:, pid:)
|
|
78
|
-
socket.sendmsg(encoder.buffer.get_string, 0, Socket.sockaddr_nl(0, 0))
|
|
79
|
-
nil
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def build_request(kind, request_class, args)
|
|
83
|
-
flags = Core::NLM_F_REQUEST
|
|
84
|
-
flags |= kind == :dump ? Core::NLM_F_DUMP : Core::NLM_F_ACK
|
|
85
|
-
|
|
86
|
-
message = request_class.from_params(args)
|
|
87
|
-
Request.new(type: frame_type(request_class), flags:, message:)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# Raw Netlink sockets carry a single protocol family.
|
|
91
|
-
def notification_routing = NOTIFICATION_ROUTING
|
|
92
|
-
|
|
93
|
-
# Whether an unsolicited data frame belongs to this protocol.
|
|
94
|
-
def notification_frame?(header, _payload)
|
|
95
|
-
header.type >= Core::NLMSG_MIN_TYPE
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Looks up the generated notification class for an unsolicited frame.
|
|
99
|
-
def notification_class(header, _payload, classes)
|
|
100
|
-
classes[header.type]
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def decode_notification(header, payload, message_class)
|
|
104
|
-
decode_frame(header, payload, message_class).message
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def multicast_group_id(name, value)
|
|
108
|
-
value or raise UnresolvedMulticastGroupError,
|
|
109
|
-
"multicast group #{name.inspect} has no fixed ID"
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
private def frame_type(message_class) = message_class::TYPE
|
|
113
|
-
|
|
114
|
-
class AttributeSet
|
|
115
|
-
Attribute = Struct.new(:value)
|
|
116
|
-
class Attribute
|
|
117
|
-
def self.decode(decoder)
|
|
118
|
-
value = self::DATATYPE.decode(decoder)
|
|
119
|
-
new(value)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def encode(encoder)
|
|
123
|
-
self.class::DATATYPE.encode(encoder, self.value)
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def initialize(attributes)
|
|
128
|
-
attr_class = self.class::Attribute
|
|
129
|
-
|
|
130
|
-
attributes.each do |attr|
|
|
131
|
-
unless attr.kind_of?(attr_class)
|
|
132
|
-
raise TypeError, "attribute must be an instance of #{attr_class}"
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
@attributes = Array(attributes)
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def [](type)
|
|
140
|
-
case type
|
|
141
|
-
when Symbol
|
|
142
|
-
attr_class = self.class.by_name(type)
|
|
143
|
-
when Integer
|
|
144
|
-
attr_class = self.class.by_type(type)
|
|
145
|
-
else
|
|
146
|
-
raise TypeError, "attribute type must be a Symbol or an Integer"
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# TODO: multi-attr
|
|
150
|
-
@attributes.find { it.kind_of?(attr_class) } rescue binding.irb
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def <<(attr)
|
|
154
|
-
attr_class = self.class::Attribute
|
|
155
|
-
unless attr.kind_of?(attr_class)
|
|
156
|
-
raise TypeError, "attribute must be an instance of #{attr_class}"
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
@attributes << attr
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
private def encode1(encoder, attr)
|
|
163
|
-
datatype = attr.class::DATATYPE
|
|
164
|
-
type = attr.class::TYPE | datatype.nlattr_type_flags
|
|
165
|
-
nlattr = Core::NlAttr.new(0, type)
|
|
166
|
-
encoder.measure(Endian::Host::U16) do
|
|
167
|
-
nlattr.encode(encoder)
|
|
168
|
-
attr.encode(encoder)
|
|
169
|
-
end
|
|
170
|
-
encoder.align_to(Core::NLA_ALIGNTO)
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def encode(encoder)
|
|
174
|
-
@attributes.each do |attr|
|
|
175
|
-
encode1(encoder, attr)
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
class << self
|
|
180
|
-
private def decode1(decoder)
|
|
181
|
-
nlattr = Core::NlAttr.decode(decoder)
|
|
182
|
-
attr = decoder.limit(nlattr.len - Core::NLA_HDRLEN) do
|
|
183
|
-
if attr_class = self::BY_TYPE[nlattr.type & Core::NLA_TYPE_MASK]
|
|
184
|
-
attr_class.decode(decoder)
|
|
185
|
-
else
|
|
186
|
-
decoder.skip
|
|
187
|
-
nil
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
decoder.align_to(Core::NLA_ALIGNTO)
|
|
191
|
-
attr
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def decode(decoder)
|
|
195
|
-
attrs = []
|
|
196
|
-
while decoder.available?
|
|
197
|
-
attr = decode1(decoder)
|
|
198
|
-
attrs << attr
|
|
199
|
-
end
|
|
200
|
-
new(attrs.compact)
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
def build_attributes(**params)
|
|
204
|
-
attrs = params.map do |name, value|
|
|
205
|
-
attr_class = self::BY_NAME[name] or raise "Unknown attribute #{name}"
|
|
206
|
-
attr_class.new(value)
|
|
207
|
-
end
|
|
208
|
-
new(attrs)
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
class Message
|
|
214
|
-
attr_accessor :fixed_header, :attributes
|
|
215
|
-
|
|
216
|
-
def initialize(fixed_header = nil, attributes = self.class::ATTRIBUTE_SET.new)
|
|
217
|
-
@fixed_header = fixed_header
|
|
218
|
-
@attributes = attributes
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
def self.from_params(params)
|
|
222
|
-
if self::FIXED_HEADER
|
|
223
|
-
header_params = params.slice(*self::FIXED_HEADER.members)
|
|
224
|
-
fixed_header = self::FIXED_HEADER.new(**header_params)
|
|
225
|
-
end
|
|
226
|
-
attribute_params = params.slice(*self::ATTRIBUTES)
|
|
227
|
-
attributes = self::ATTRIBUTE_SET.build_attributes(**attribute_params)
|
|
228
|
-
|
|
229
|
-
unknown = params.keys - attribute_params.keys
|
|
230
|
-
unknown -= header_params.keys if header_params
|
|
231
|
-
unless unknown.empty?
|
|
232
|
-
raise ArgumentError, "unknown parameters: #{unknown.join(', ')}"
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
new(fixed_header, attributes)
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
def append_attribute(attribute)
|
|
239
|
-
@attributes << attribute
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
def encode(encoder)
|
|
243
|
-
@fixed_header&.encode(encoder)
|
|
244
|
-
@attributes.encode(encoder)
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
def self.decode(decoder, type:)
|
|
248
|
-
unless self::TYPE == type
|
|
249
|
-
raise "Expected message type #{self::TYPE}, got #{type}"
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
if fixed_header_class = self::FIXED_HEADER
|
|
253
|
-
fixed_header = fixed_header_class.decode(decoder)
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
attributes = self::ATTRIBUTE_SET.decode(decoder)
|
|
257
|
-
|
|
258
|
-
new(fixed_header, attributes)
|
|
259
|
-
end
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
module DataTypes
|
|
263
|
-
class Base
|
|
264
|
-
def nlattr_type_flags
|
|
265
|
-
0
|
|
266
|
-
end
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
class Scalar < Base
|
|
270
|
-
def initialize(type, check)
|
|
271
|
-
@type = type
|
|
272
|
-
@check = check
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
def encode(encoder, value)
|
|
276
|
-
value ||= 0
|
|
277
|
-
encoder.put_value(@type, value.tap(&@check))
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
def decode(decoder)
|
|
281
|
-
value = decoder.get_value(@type).tap(&@check)
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
class String < Base
|
|
286
|
-
def initialize(check)
|
|
287
|
-
@check = check
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
def encode(encoder, value)
|
|
291
|
-
encoder.put_zstring(value)
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
def decode(decoder)
|
|
295
|
-
decoder.get_zstring
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
class Binary < Base
|
|
300
|
-
def initialize(check)
|
|
301
|
-
@check = check
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
def encode(encoder, value)
|
|
305
|
-
encoder.put_string(value)
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
def decode(decoder)
|
|
309
|
-
decoder.get_string
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
class Flag < Base
|
|
314
|
-
def encode(encoder, value)
|
|
315
|
-
# flag attribute has no payload; presence encodes true
|
|
316
|
-
end
|
|
317
|
-
|
|
318
|
-
def decode(decoder)
|
|
319
|
-
true
|
|
320
|
-
end
|
|
321
|
-
end
|
|
322
|
-
|
|
323
|
-
# A 32-bit value paired with a selector mask (8 bytes total: value u32 + selector u32)
|
|
324
|
-
class Bitfield32 < Base
|
|
325
|
-
def encode(encoder, value)
|
|
326
|
-
v, selector = value.is_a?(Array) ? value : [value, 0xFFFFFFFF]
|
|
327
|
-
encoder.put_value(Endian::Host::U32, v)
|
|
328
|
-
encoder.put_value(Endian::Host::U32, selector)
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
def decode(decoder)
|
|
332
|
-
value = decoder.get_value(Endian::Host::U32)
|
|
333
|
-
selector = decoder.get_value(Endian::Host::U32)
|
|
334
|
-
[value, selector]
|
|
335
|
-
end
|
|
336
|
-
end
|
|
337
|
-
|
|
338
|
-
class Pad < Base
|
|
339
|
-
def initialize(length = nil)
|
|
340
|
-
@length = length
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
def encode(encoder, _value)
|
|
344
|
-
encoder.put_string(?\0.b * @length) if @length
|
|
345
|
-
end
|
|
346
|
-
|
|
347
|
-
def decode(decoder)
|
|
348
|
-
@length ? decoder.skip(@length) : decoder.skip
|
|
349
|
-
nil
|
|
350
|
-
end
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
class NestedAttributes < Base
|
|
354
|
-
def initialize(attribute_set)
|
|
355
|
-
@attribute_set = attribute_set
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
def nlattr_type_flags
|
|
359
|
-
Core::NLA_F_NESTED
|
|
360
|
-
end
|
|
361
|
-
|
|
362
|
-
def encode(encoder, value)
|
|
363
|
-
unless value.is_a?(@attribute_set)
|
|
364
|
-
raise TypeError, "value must be an instance of #{@attribute_set}"
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
value.encode(encoder)
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
def decode(decoder)
|
|
371
|
-
@attribute_set.decode(decoder)
|
|
372
|
-
end
|
|
373
|
-
end
|
|
374
|
-
|
|
375
|
-
# Nested attributes whose type numbers are keys rather than members of
|
|
376
|
-
# an attribute set. Each level is returned as an Integer-keyed Hash;
|
|
377
|
-
# values at the innermost level are decoded as @attribute_set.
|
|
378
|
-
class NestTypeValue < Base
|
|
379
|
-
def initialize(attribute_set, levels)
|
|
380
|
-
raise ArgumentError, 'levels must be positive' unless levels.positive?
|
|
381
|
-
|
|
382
|
-
@attribute_set = attribute_set
|
|
383
|
-
@levels = levels
|
|
384
|
-
end
|
|
385
|
-
|
|
386
|
-
def encode(encoder, value)
|
|
387
|
-
encode_level(encoder, value, @levels)
|
|
388
|
-
end
|
|
389
|
-
|
|
390
|
-
def decode(decoder)
|
|
391
|
-
decode_level(decoder, @levels)
|
|
392
|
-
end
|
|
393
|
-
|
|
394
|
-
private def encode_level(encoder, values, levels)
|
|
395
|
-
values.each do |type, value|
|
|
396
|
-
nlattr = Core::NlAttr.new(0, type | Core::NLA_F_NESTED)
|
|
397
|
-
encoder.measure(Endian::Host::U16) do
|
|
398
|
-
nlattr.encode(encoder)
|
|
399
|
-
if levels == 1
|
|
400
|
-
value.encode(encoder)
|
|
401
|
-
else
|
|
402
|
-
encode_level(encoder, value, levels - 1)
|
|
403
|
-
end
|
|
404
|
-
end
|
|
405
|
-
encoder.align_to(Core::NLA_ALIGNTO)
|
|
406
|
-
end
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
private def decode_level(decoder, levels)
|
|
410
|
-
result = {}
|
|
411
|
-
while decoder.available?(Core::NLA_HDRLEN)
|
|
412
|
-
nlattr = Core::NlAttr.decode(decoder)
|
|
413
|
-
type = nlattr.type & Core::NLA_TYPE_MASK
|
|
414
|
-
value = decoder.limit(nlattr.len - Core::NLA_HDRLEN) do
|
|
415
|
-
if levels == 1
|
|
416
|
-
@attribute_set.decode(decoder)
|
|
417
|
-
else
|
|
418
|
-
decode_level(decoder, levels - 1)
|
|
419
|
-
end
|
|
420
|
-
end
|
|
421
|
-
decoder.align_to(Core::NLA_ALIGNTO)
|
|
422
|
-
result[type] = value
|
|
423
|
-
end
|
|
424
|
-
result
|
|
425
|
-
end
|
|
426
|
-
end
|
|
427
|
-
|
|
428
|
-
class IndexedArray < Base
|
|
429
|
-
def initialize(sub_type)
|
|
430
|
-
@sub_type = sub_type
|
|
431
|
-
end
|
|
432
|
-
|
|
433
|
-
def encode(encoder, values)
|
|
434
|
-
values.each_with_index do |value, i|
|
|
435
|
-
nlattr = Core::NlAttr.new(0, i + 1)
|
|
436
|
-
encoder.measure(Endian::Host::U16) do
|
|
437
|
-
nlattr.encode(encoder)
|
|
438
|
-
@sub_type.encode(encoder, value)
|
|
439
|
-
end
|
|
440
|
-
encoder.align_to(Core::NLA_ALIGNTO)
|
|
441
|
-
end
|
|
442
|
-
end
|
|
443
|
-
|
|
444
|
-
def decode(decoder)
|
|
445
|
-
result = []
|
|
446
|
-
while decoder.available?
|
|
447
|
-
nlattr = Core::NlAttr.decode(decoder)
|
|
448
|
-
element = decoder.limit(nlattr.len - Core::NLA_HDRLEN) do
|
|
449
|
-
@sub_type.decode(decoder)
|
|
450
|
-
end
|
|
451
|
-
decoder.align_to(Core::NLA_ALIGNTO)
|
|
452
|
-
result << element
|
|
453
|
-
end
|
|
454
|
-
result
|
|
455
|
-
end
|
|
456
|
-
end
|
|
457
|
-
end
|
|
458
|
-
end
|
|
459
|
-
end
|
|
460
|
-
end
|