Skip to content
Browse files

Mask the top 3 bits for BSD ioctl requests

The linux calculation was copied from asm-generic/ioctl.h but looks off
still. If the size takes >14 bits, the direction will be overwritten.
  • Loading branch information...
1 parent f3f43fc commit b84cdf31856d5b4e1e5625225132f52db8e0d746 @msantos committed
Showing with 41 additions and 6 deletions.
  1. +41 −6 src/procket_ioctl.erl
View
47 src/procket_ioctl.erl
@@ -39,36 +39,71 @@
]).
+%%
+%% Calculate the values of the ioctl request macros at runtime.
+%%
+
+%% On BSD systems, the top 3 bits indicate the direction of the request:
+%%
+%% 8 : ioctl parameter will be copied from user space into the kernel
+%% 4 : ioctl parameter will be copied into the user supplied buffer from
+%% the kernel
+%% 2 : no parameters are used
+%%
+%% The remaining 13 bits are used to indicate the size of the parameter.
+%%
+%% On Linux systems, only the top 2 bits are used. Setting both bits to 0
+%% indicates a void parameter. The meaning of the bits is reversed:
+%%
+%% 8 : ioctl parameter will be copied into the user supplied buffer from
+%% the kernel
+%% 4 : ioctl parameter will be copied from user space into the kernel
+%%
+%% The remaining 14 bits is used to hold the length of the parameter.
+%%
%% BSD: <<IN:1, OUT:1, VOID:1, Length:13, Group:8, Command:8>>
%%
-%% IOC_OUT = 0x40000000
-%% IOC_IN = 0x80000000
+%% _IOC_OUT = 0x40000000
+%% _IOC_IN = 0x80000000
%%
%% #define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t))
%% #define _IOW(g,n,t) _IOC(IOC_IN, (g), (n), sizeof(t))
-
+%%
%% Linux: <<OUT:1, IN:1, Length:14, Group:8, Command:8>>
%%
-%% IOC_OUT = 0x80000000
-%% IOC_IN = 0x40000000
+%% _IOC_OUT = 0x80000000
+%% _IOC_IN = 0x40000000
%%
%% #define _IOR(g,n,t) _IOC(_IOC_READ,(g),(n),(t))
%% #define _IOW(g,n,t) _IOC(_IOC_WRITE,(g),(n),(t))
+%%
+%% BSD: _IOC_IN
+%% Linux: _IOC_WRITE << _IOC_DIRSHIFT (16)
in() -> in(os()).
in(bsd) -> 16#80000000;
in(linux) -> 16#40000000.
+%% BSD: _IOC_OUT
+%% Linux: _IOC_READ << _IOC_DIRSHIFT (16)
out() -> out(os()).
out(bsd) -> 16#40000000;
out(linux) -> 16#80000000.
+%% BSD: _IOC_VOID
+%% Linux: _IOC_NONE
void() -> void(os()).
void(bsd) -> 16#20000000;
void(linux) -> 0.
+-define(IOCPARM_MASK, 16#1fff).
+
ioc(Inout,Group,Num,Len) ->
- (Len bsl 16) bor Inout bor (Group bsl 8) bor Num.
+ Size = case os() of
+ bsd -> Len band ?IOCPARM_MASK;
+ linux -> Len
+ end,
+ Inout bor (Size bsl 16) bor (Group bsl 8) bor Num.
io(Type,NR) ->
ioc(void(), Type, NR, 0).

0 comments on commit b84cdf3

Please sign in to comment.
Something went wrong with that request. Please try again.