Alignment of structure members
This commit is contained in:
@@ -7,18 +7,6 @@ require 'netlink/nlsocket'
|
|||||||
require 'netlink/message'
|
require 'netlink/message'
|
||||||
|
|
||||||
module Netlink
|
module Netlink
|
||||||
# struct ipq_mode_msg
|
|
||||||
class IPQMode < Message
|
|
||||||
code IPQM_MODE
|
|
||||||
|
|
||||||
field :value, :uchar # IPQ_*
|
|
||||||
field_pad 1.size - 1 # FIXME! C structs need aligning
|
|
||||||
field :range, :size_t
|
|
||||||
# FIXME! Kernel enforces that IPQM_MODE messages must be at least
|
|
||||||
# as large as IPQM_VERDICT messages.
|
|
||||||
field_pad 16
|
|
||||||
end
|
|
||||||
|
|
||||||
# struct ipq_packet_msg
|
# struct ipq_packet_msg
|
||||||
class IPQPacket < Message
|
class IPQPacket < Message
|
||||||
code IPQM_PACKET
|
code IPQM_PACKET
|
||||||
@@ -28,13 +16,12 @@ module Netlink
|
|||||||
field :timestamp_sec, :long
|
field :timestamp_sec, :long
|
||||||
field :timestamp_usec, :long
|
field :timestamp_usec, :long
|
||||||
field :hook, :uint
|
field :hook, :uint
|
||||||
field :indev_name, :pattern => "Z#{IFNAMSIZ}"
|
field :indev_name, :pattern => "Z#{IFNAMSIZ}", :default => EMPTY_STRING
|
||||||
field :outdev_name, :pattern => "Z#{IFNAMSIZ}"
|
field :outdev_name, :pattern => "Z#{IFNAMSIZ}", :default => EMPTY_STRING
|
||||||
field :hw_protocol, :ns
|
field :hw_protocol, :ns
|
||||||
field :hw_type, :ushort
|
field :hw_type, :ushort
|
||||||
field :hw_addrlen, :uchar
|
field :hw_addrlen, :uchar
|
||||||
field :hw_addr, :pattern => "a8"
|
field :hw_addr, :pattern => "a8", :default => EMPTY_STRING
|
||||||
field_pad 1.size - 1 # FIXME!
|
|
||||||
field :data_len, :size_t
|
field :data_len, :size_t
|
||||||
field :payload, :binary # TODO: clip to data_len
|
field :payload, :binary # TODO: clip to data_len
|
||||||
end
|
end
|
||||||
@@ -44,12 +31,22 @@ module Netlink
|
|||||||
code IPQM_VERDICT
|
code IPQM_VERDICT
|
||||||
|
|
||||||
field :value, :uint # NF_*
|
field :value, :uint # NF_*
|
||||||
field_pad 1.size - 4
|
|
||||||
field :id, :ulong
|
field :id, :ulong
|
||||||
field :data_len, :size_t # TODO: auto set from payload.bytesize
|
field :data_len, :size_t # TODO: auto set from payload.bytesize
|
||||||
field :payload, :binary # optional replacement packet
|
field :payload, :binary # optional replacement packet
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# struct ipq_mode_msg
|
||||||
|
class IPQMode < Message
|
||||||
|
code IPQM_MODE
|
||||||
|
|
||||||
|
field :value, :uchar # IPQ_*
|
||||||
|
field :range, :size_t
|
||||||
|
# NOTE! Kernel enforced that IPQM_MODE messages must be at least
|
||||||
|
# as large as IPQM_VERDICT messages (otherwise you get EINVAL)
|
||||||
|
field_pad IPQVerdict.bytesize - bytesize
|
||||||
|
end
|
||||||
|
|
||||||
module Firewall
|
module Firewall
|
||||||
class Socket < NLSocket
|
class Socket < NLSocket
|
||||||
def initialize(opt={})
|
def initialize(opt={})
|
||||||
|
@@ -31,6 +31,11 @@ module Netlink
|
|||||||
class Message
|
class Message
|
||||||
TYPE_INFO = {} #:nodoc
|
TYPE_INFO = {} #:nodoc
|
||||||
|
|
||||||
|
# The size of the structure (in bytes)
|
||||||
|
def self.bytesize
|
||||||
|
@bytesize
|
||||||
|
end
|
||||||
|
|
||||||
# Define a new type for use with field and rtattr. You supply the
|
# Define a new type for use with field and rtattr. You supply the
|
||||||
# symbolic name for the type, and a set of options. field supports only:
|
# symbolic name for the type, and a set of options. field supports only:
|
||||||
# :pattern => "str" # format string for Array#pack / String#unpack
|
# :pattern => "str" # format string for Array#pack / String#unpack
|
||||||
@@ -53,27 +58,27 @@ module Netlink
|
|||||||
end
|
end
|
||||||
|
|
||||||
define_type :uchar, :pattern => "C"
|
define_type :uchar, :pattern => "C"
|
||||||
define_type :uint16, :pattern => "S"
|
define_type :uint16, :pattern => "S", :align => true
|
||||||
define_type :uint32, :pattern => "L"
|
define_type :uint32, :pattern => "L", :align => true
|
||||||
define_type :char, :pattern => "c"
|
define_type :char, :pattern => "c"
|
||||||
define_type :int16, :pattern => "s"
|
define_type :int16, :pattern => "s", :align => true
|
||||||
define_type :int32, :pattern => "l"
|
define_type :int32, :pattern => "l", :align => true
|
||||||
define_type :ushort, :pattern => "S_"
|
define_type :ushort, :pattern => "S_", :align => true
|
||||||
define_type :uint, :pattern => "I"
|
define_type :uint, :pattern => "I", :align => true
|
||||||
define_type :ulong, :pattern => "L_"
|
define_type :ulong, :pattern => "L_", :align => true
|
||||||
define_type :short, :pattern => "s_"
|
define_type :short, :pattern => "s_", :align => true
|
||||||
define_type :int, :pattern => "i"
|
define_type :int, :pattern => "i", :align => true
|
||||||
define_type :long, :pattern => "l_"
|
define_type :long, :pattern => "l_", :align => true
|
||||||
define_type :ns, :pattern => "n"
|
define_type :ns, :pattern => "n", :align => true
|
||||||
define_type :nl, :pattern => "N"
|
define_type :nl, :pattern => "N", :align => true
|
||||||
|
|
||||||
SIZE_T_SIZE = Integer(`echo __SIZEOF_SIZE_T__ | gcc -E -P -`) rescue 1.size
|
SIZE_T_SIZE = Integer(`echo __SIZEOF_SIZE_T__ | gcc -E -P -`) rescue 1.size
|
||||||
define_type :size_t,
|
define_type :size_t,
|
||||||
case SIZE_T_SIZE
|
case SIZE_T_SIZE
|
||||||
when 8
|
when 8
|
||||||
{:pattern => "Q"}
|
{:pattern => "Q", :align => true}
|
||||||
when 4
|
when 4
|
||||||
{:pattern => "L"}
|
{:pattern => "L", :align => true}
|
||||||
else
|
else
|
||||||
raise "Bad size_t"
|
raise "Bad size_t"
|
||||||
end
|
end
|
||||||
@@ -156,7 +161,7 @@ module Netlink
|
|||||||
@attrs.each(&blk)
|
@attrs.each(&blk)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set a field by name. Can use either symbol or string as key.
|
# Set a field by name. Currently can use either symbol or string as key.
|
||||||
def []=(k,v)
|
def []=(k,v)
|
||||||
send "#{k}=", v
|
send "#{k}=", v
|
||||||
end
|
end
|
||||||
@@ -170,6 +175,7 @@ module Netlink
|
|||||||
subclass.const_set(:FIELDS, [])
|
subclass.const_set(:FIELDS, [])
|
||||||
subclass.const_set(:FORMAT, "")
|
subclass.const_set(:FORMAT, "")
|
||||||
subclass.const_set(:DEFAULTS, {})
|
subclass.const_set(:DEFAULTS, {})
|
||||||
|
subclass.instance_variable_set(:@bytesize, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Map of numeric message type code => message class
|
# Map of numeric message type code => message class
|
||||||
@@ -186,9 +192,21 @@ module Netlink
|
|||||||
# field :foo, :uchar, :default=>0xff # use this default value
|
# field :foo, :uchar, :default=>0xff # use this default value
|
||||||
def self.field(name, type, opt={})
|
def self.field(name, type, opt={})
|
||||||
info = find_type(type)
|
info = find_type(type)
|
||||||
|
pattern = info[:pattern]
|
||||||
|
default = opt.fetch(:default) { info.fetch(:default, 0) }
|
||||||
|
|
||||||
|
# Apply padding for structure alignment if necessary
|
||||||
|
size = info[:size] || [default].pack(pattern).bytesize
|
||||||
|
if align = info[:align]
|
||||||
|
align = size if align == true
|
||||||
|
field_pad alignto(@bytesize, align) - @bytesize
|
||||||
|
end
|
||||||
|
@bytesize += size
|
||||||
|
|
||||||
self::FIELDS << name
|
self::FIELDS << name
|
||||||
self::FORMAT << info[:pattern]
|
self::FORMAT << pattern
|
||||||
self::DEFAULTS[name] = opt.fetch(:default) { info.fetch(:default, 0) }
|
self::DEFAULTS[name] = default
|
||||||
|
|
||||||
define_method name do
|
define_method name do
|
||||||
@attrs.fetch name
|
@attrs.fetch name
|
||||||
end
|
end
|
||||||
@@ -198,8 +216,11 @@ module Netlink
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Skip pad byte(s) - default 1
|
# Skip pad byte(s) - default 1
|
||||||
def self.field_pad(count=nil)
|
def self.field_pad(count=1)
|
||||||
self::FORMAT << "x#{count}" if count != 0
|
if count > 0
|
||||||
|
self::FORMAT << "x#{count}"
|
||||||
|
@bytesize += count
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the packed binary representation of this message (without
|
# Returns the packed binary representation of this message (without
|
||||||
@@ -224,6 +245,11 @@ module Netlink
|
|||||||
NLMSG_ALIGNTO_1 = NLMSG_ALIGNTO-1 #:nodoc:
|
NLMSG_ALIGNTO_1 = NLMSG_ALIGNTO-1 #:nodoc:
|
||||||
NLMSG_ALIGNTO_1_MASK = ~NLMSG_ALIGNTO_1 #:nodoc:
|
NLMSG_ALIGNTO_1_MASK = ~NLMSG_ALIGNTO_1 #:nodoc:
|
||||||
|
|
||||||
|
# Round up a number to multiple of m, where m is a power of two
|
||||||
|
def self.alignto(val, m)
|
||||||
|
(val + (m-1)) & ~(m-1)
|
||||||
|
end
|
||||||
|
|
||||||
# Round up a length to a multiple of NLMSG_ALIGNTO bytes
|
# Round up a length to a multiple of NLMSG_ALIGNTO bytes
|
||||||
def self.align(n)
|
def self.align(n)
|
||||||
(n + NLMSG_ALIGNTO_1) & NLMSG_ALIGNTO_1_MASK
|
(n + NLMSG_ALIGNTO_1) & NLMSG_ALIGNTO_1_MASK
|
||||||
@@ -268,7 +294,7 @@ module Netlink
|
|||||||
|
|
||||||
# Return the byte offset to the first rtattr
|
# Return the byte offset to the first rtattr
|
||||||
def self.attr_offset
|
def self.attr_offset
|
||||||
@attr_offset ||= Message.align(new.to_s.bytesize)
|
@attr_offset ||= Message.align(@bytesize)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the packed binary representation of this message.
|
# Returns the packed binary representation of this message.
|
||||||
|
@@ -26,7 +26,6 @@ module Netlink
|
|||||||
code RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK
|
code RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK
|
||||||
|
|
||||||
field :family, :uchar # Socket::AF_*
|
field :family, :uchar # Socket::AF_*
|
||||||
field_pad
|
|
||||||
field :type, :ushort # ARPHRD_*
|
field :type, :ushort # ARPHRD_*
|
||||||
field :index, :int
|
field :index, :int
|
||||||
field :flags, :uint # IFF_*
|
field :flags, :uint # IFF_*
|
||||||
|
Reference in New Issue
Block a user