Permalink
Browse files

Rewrite arp responder.

  • Loading branch information...
1 parent 9b59548 commit 04307b80241a960d696f63caa7773b5d53cd9c50 @archaelus committed Mar 10, 2013
Showing with 72 additions and 105 deletions.
  1. +72 −105 src/enet_arp_responder.erl
View
@@ -9,25 +9,25 @@
-behaviour(gen_server).
--include("logging.hrl").
--include("enet_types.hrl").
+-include("../include/logging.hrl").
+-include("../include/enet_types.hrl").
+-include("enet_arp_cache.hrl").
-include_lib("eunit/include/eunit.hrl").
%% API
--export([start_link/0]).
--export([attach/2
+-export([start/0]).
+-export([attach/1
,eth_addr/2
,ip_addr/2
+ ,arp_filter/1
+ ,publish/3
]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
--record(state, {tid}).
-
-%% Table entries
--define(ARP_ENTRY(Mac, Addr), {Addr, Mac}).
+-record(state, {cache}).
%%====================================================================
%% API
@@ -37,121 +37,86 @@
%% @doc Starts the server
%% @end
%%--------------------------------------------------------------------
-start_link() ->
- gen_server:start_link(?MODULE, [], []).
+start() ->
+ gen_server:start(?MODULE, [], []).
attach(Interface) ->
- {ok, Pid} = start_link(),
+ {ok, Pid} = start(),
attach(Pid, Interface).
attach(Dumper, Interface) ->
gen_server:call(Dumper, {sub, Interface}),
{ok, Dumper}.
-eth_addr(Cache, IpAddr) ->
- gen_server:call(Cache, {eth_addr, IpAddr}).
+eth_addr(Pid, IpAddr) ->
+ gen_server:call(Pid, {eth_addr, IpAddr}).
+
+ip_addr(Pid, EthAddr) ->
+ gen_server:call(Pid, {ip_addr, EthAddr}).
-ip_addr(Cache, EthAddr) ->
- gen_server:call(Cache, {ip_addr, EthAddr}).
+publish(Pid, EthAddr, IpAddr) ->
+ gen_server:call(Pid, {publish, EthAddr, IpAddr}).
+arp_filter({enet, _, {rx, _, #eth{type=arp}}}) -> true;
+arp_filter(_) -> false.
%%====================================================================
%% gen_server callbacks
%%====================================================================
-%%--------------------------------------------------------------------
%% @private
-%% @spec init(Args) -> {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% @doc Initialises the server's state
-%% @end
-%%--------------------------------------------------------------------
init([]) ->
- Tid = ets:new(?MODULE, []),
- {ok, #state{tid=Tid}}.
+ {ok, #state{cache = enet_arp_cache:new()}}.
-%%--------------------------------------------------------------------
%% @private
-%% @spec
-%% handle_call(Request, From, State) -> {reply, Reply, State} |
-%% {reply, Reply, State, Timeout} |
-%% {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, Reply, State} |
-%% {stop, Reason, State}
-%% @doc Call message handler callbacks
-%% @end
-%%--------------------------------------------------------------------
+handle_call({publish, EthAddr, IpAddr}, _From,
+ State = #state{cache = OldCache}) ->
+ NewCache = enet_arp_cache:publish(EthAddr, IpAddr, OldCache),
+ {reply, ok, State#state{cache = NewCache}};
+handle_call({eth_addr, IpAddr}, _From, State = #state{cache = Cache}) ->
+ case enet_arp_cache:lookup_ip_addr(IpAddr, Cache) of
+ not_found ->
+ {reply, not_found, State};
+ #entry{ethaddr = Addr} ->
+ {reply, Addr, State}
+ end;
+
+handle_call({ip_addr, EthAddr}, _From, State = #state{cache = Cache}) ->
+ case enet_arp_cache:lookup_eth_addr(EthAddr, Cache) of
+ not_found ->
+ {reply, not_found, State};
+ #entry{ipaddr = Addr} ->
+ {reply, Addr, State}
+ end;
handle_call({sub, Interface}, _From, State) ->
- {reply, pubsub:sync_subscribe(Interface), State};
+ {reply, pubsub:sync_subscribe(Interface, fun ?MODULE:arp_filter/1), State};
handle_call(Call, _From, State) ->
?WARN("Unexpected call ~p.", [Call]),
{noreply, State}.
-%%--------------------------------------------------------------------
%% @private
-%% @spec
-%% handle_cast(Msg, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
-%% @doc Cast message handler callbacks
-%% @end
-%%--------------------------------------------------------------------
handle_cast(Msg, State) ->
?WARN("Unexpected cast ~p", [Msg]),
{noreply, State}.
-%%--------------------------------------------------------------------
-%% @private
-%% @spec
-%% handle_info(Info, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
-%% @doc Non gen-server message handler callbacks
-%% @end
-%%--------------------------------------------------------------------
-
-%% handle_info({enet, _IF, {tx, Frame}}, State) ->
-%% P = enet_codec:decode(eth, Frame, [all]),
-%% print([{dir, send}, {raw, Frame}, {packet, P}], State),
-%% {noreply, State};
-%% handle_info({enet, _IF, {RX, Frame}}, State)
-%% when RX =:= rx;
-%% RX =:= promisc_rx ->
-%% print([{dir, recv}, {raw, Frame}], State),
-%% {noreply, State};
-handle_info({enet, IF, {RX, Frame, Pkt = #eth{type=arp}}}, State)
+handle_info({enet, IF, {RX, _Frame, Pkt = #eth{type=arp}}}, State)
when RX =:= rx;
RX =:= promisc_rx ->
handle_arp_rx(IF, Pkt, State),
{noreply, State};
+
handle_info(Info, State) ->
?WARN("Unexpected info ~p", [Info]),
{noreply, State}.
-%%--------------------------------------------------------------------
%% @private
-%% @spec terminate(Reason, State) -> void()
-%% @doc This function is called by a gen_server when it is about to
-%% terminate. It should be the opposite of Module:init/1 and do any necessary
-%% cleaning up. When it returns, the gen_server terminates with Reason.
-%% The return value is ignored.
-%% @end
-%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ok.
-%%--------------------------------------------------------------------
%% @private
-%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
-%% @doc Convert process state when code is changed
-%% @end
-%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@@ -160,40 +125,42 @@ code_change(_OldVsn, State, _Extra) ->
%%--------------------------------------------------------------------
handle_arp_rx(IF, #eth{type=arp,data=Pkt}, State) ->
- try enet_codec:decode(arp, Pkt) of
- {error, bad_packet} ->
- %% XXX - log corrupt arp packet somehow?
- ignore;
- #arp{} = Q ->
- handle_arp_rx(IF, Q, State)
+ try enet_codec:decode(arp, Pkt, [{decode_types, [arp]}]) of
+ #arp{htype = ethernet,
+ ptype = ipv4,
+ op=request} = Q ->
+ handle_arp_request(IF, Q, State);
+ _ ->
+ ?INFO("Ignoring arp:~n~p", [Pkt]),
+ ignore
catch
- _Type:_Error ->
+ Class:Error ->
+ ?WARN("~p:~p while decoding~n~p~nStack:~p",
+ [Class, Error, Pkt, erlang:get_stacktrace()]),
%% XXX - couldn't decode Pkt, Type:Error.
ignore
- end;
+ end.
-handle_arp_rx(IF,
- Q = #arp{htype = ethernet,
- ptype = Type,
- op = request,
- sender = Sender = {SMac, SAddr},
- target = {TMac, TAddr}
- },
- State) ->
- case cache_lookup(TAddr, State) of
- [] ->
- ignore;
- [?ARP_ENTRY(CMac, CAddr)] ->
+handle_arp_request({enet_eth_iface, IF},
+ #arp{htype = ethernet,
+ ptype = ipv4,
+ op = request,
+ sender = Sender = {SMac, _SAddr},
+ target = {_TMac, TAddr}},
+ #state{cache = Cache}) ->
+ case enet_arp_cache:lookup_ip_addr(TAddr, Cache) of
+ not_found -> ignore;
+ #entry{publish = false} -> ignore;
+ #entry{publish = true,
+ ethaddr = CMac,
+ ipaddr = CAddr} ->
R = #arp{op = reply,
htype = ethernet,
- ptype = Type,
+ ptype = ipv4,
sender = {CMac, CAddr},
target = Sender
},
- Reply = #eth{dst=SMac, type=arp, data=enet_codec:encode(arp, R)},
- enet_host:send(Reply)
+ Reply = #eth{dst=SMac, type=arp,
+ data=enet_codec:encode(arp, R, [])},
+ enet_eth_iface:send(IF, Reply)
end.
-
-
-cache_lookup(Key, #state{tid=T}) ->
- ets:lookup(T, Key).

0 comments on commit 04307b8

Please sign in to comment.