Alignment of structure members

This commit is contained in:
Brian Candler
2011-05-01 17:39:47 +01:00
parent b78327c3b6
commit f205d19591
3 changed files with 60 additions and 38 deletions

View File

@@ -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,11 +31,21 @@ 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

View File

@@ -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.

View File

@@ -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_*