1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2016. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(snmpa_svbl). 21 22-include("snmp_types.hrl"). 23 24-define(VMODULE,"SVBL"). 25-include("snmp_verbosity.hrl"). 26 27-export([sort_varbindlist/2, sort_varbinds_rows/1, sa_split/1, 28 delete_org_index/1, col_to_orgindex/2]). 29 30%%----------------------------------------------------------------- 31%% Func: sort_varbindlist/2 32%% Args: Varbinds is a list of #varbind 33%% Purpose: Group all variablebindings that corresponds to logically 34%% the same entity, i.e. group all plain variables, all 35%% table operations for each table, all varbinds to each 36%% subagent. 37%% Returns: {VarbindsForThisAgent 38%% VarbindsForSubAgents} where 39%% VarbindsForThisAgent = List of {TableOid, List of #ivarbinds} | 40%% #ivarbinds 41%% VarbindsForSubAgents = List of {SubAgentPid, 42%% List of {SAOid, #varbinds}} 43%%----------------------------------------------------------------- 44sort_varbindlist(Mib, Varbinds) -> 45 {Vars, Tabs, Subagents} = partition(Mib, Varbinds), 46 {lists:append(Tabs, Vars), Subagents}. 47 48partition(Mib, Vbs) -> 49 partition(Mib, Vbs, [], [], []). 50partition(Mib, [Varbind | Vbs], Vars, Tabs, Subs) -> 51 #varbind{oid = Oid} = Varbind, 52 ?vtrace("partition -> Oid: ~p", [Oid]), 53 case snmpa_mib:lookup(Mib, Oid) of 54 {table_column, MibEntry, TableOid} -> 55 IVarbind = #ivarbind{varbind = fix_bits(Varbind, MibEntry), 56 mibentry = MibEntry}, 57 NewTabs = insert_key(TableOid, IVarbind, Tabs), 58 partition(Mib, Vbs, Vars, NewTabs, Subs); 59 {subagent, SubagentPid, SAOid} -> 60 NewSubs = insert_key(SubagentPid, {SAOid, Varbind}, Subs), 61 partition(Mib, Vbs, Vars, Tabs, NewSubs); 62 {variable, MibEntry} -> 63 IVarbind = #ivarbind{varbind = fix_bits(Varbind, MibEntry), 64 mibentry = MibEntry}, 65 partition(Mib, Vbs, [IVarbind | Vars], Tabs, Subs); 66 {false, ErrorCode} -> % ErrorCode = noSuchObject | noSuchInstance 67 IVarbind = #ivarbind{status = ErrorCode, varbind = Varbind}, 68 partition(Mib, Vbs, [IVarbind | Vars], Tabs, Subs) 69 end; 70partition(_Mib, [], Vars, Subs, Tabs) -> 71 {Vars, Subs, Tabs}. 72 73% fix_bits(#varbind{bertype = 'BITS', 74% variabletype = 'OCTET STRING', 75% value = V} = VarBind, #me{asn1_type = A}) -> 76% VarBind#varbind{variabletype = 'BITS', 77% value = snmp_pdus:octet_str_to_bits(V)}; 78fix_bits(VarBind, #me{asn1_type=A}) 79 when ((A#asn1_type.bertype =:= 'BITS') andalso 80 (VarBind#varbind.variabletype =:= 'OCTET STRING') andalso 81 is_list(VarBind#varbind.value)) -> 82 VarBind#varbind{variabletype = 'BITS', 83 value = snmp_pdus:octet_str_to_bits(VarBind#varbind.value)}; 84fix_bits(Vb,_me) -> Vb. 85 86insert_key(Key, Value, [{Key, Values} | Rest]) -> 87 [{Key, [Value | Values]} | Rest]; 88insert_key(Key, Value, [{KeyX, Values} | Rest]) -> 89 [{KeyX, Values} | insert_key(Key, Value, Rest)]; 90insert_key(Key, Value, []) -> 91 [{Key, [Value]}]. 92 93%%----------------------------------------------------------------- 94%% Tranforms a list of {Oid, Vb} to a 2-tuple with all 95%% Oids and all Vbs. These lists will be reversed. 96%%----------------------------------------------------------------- 97sa_split(Vbs) -> sa_split(Vbs, [], []). 98sa_split([{SAOid, Vb} | T], Oids, Vbs) -> 99 sa_split(T, [SAOid | Oids], [Vb | Vbs]); 100sa_split([], Oids, Vbs) -> 101 {Oids, Vbs}. 102 103%%----------------------------------------------------------------- 104%% Func: sort_varbinds_rows/1 105%% Args: Varbinds is a list of {Oid, Value}. 106%% Pre: Varbinds is for one table. 107%% Purpose: Sorts all varbinds in Oid order, and in row order. 108%% Returns: list of Row where 109%% Row = {Indexes, List of Col} and 110%% Col = {ColNo, Value, OrgIndex} and 111%% OrgIndex is index in original varbind list. 112%%----------------------------------------------------------------- 113sort_varbinds_rows(Varbinds) -> 114 P = pack(Varbinds), 115 S = lists:keysort(1, P), 116 unpack(S). 117 118%% In: list of {Oid, Value} 119%% Out: list of {{Indexes_for_row, Col}, Val, Index} 120pack(V) -> pack(1, V). 121pack(Index, [{[Col | Rest], Val} | T]) -> 122 [{{Rest, Col}, Val, Index} | pack(Index+1, T)]; 123pack(_, []) -> []. 124 125unpack([{{Rest, Col}, Val, Index} | T]) -> 126 unpack(Rest, [[{Col, Val, Index}]], T); 127unpack([]) -> []. 128 129unpack(Rest, [Row | Rows], [{{Rest, Col}, Val, Index} | T]) -> 130 unpack(Rest, [[{Col, Val, Index} | Row] | Rows], T); 131unpack(Rest, [Row | Rows], [{{Rest2, Col}, Val, Index} | T]) -> 132 unpack(Rest2, [[{Col, Val, Index}], 133 {Rest, lists:reverse(Row)} | Rows], T); 134unpack(Rest, [Row | Rows], []) -> 135 NewRow = {Rest, lists:reverse(Row)}, 136 lists:reverse([NewRow | Rows]). 137 138%% OrgIndex should not be present when we call the is_set_ok/set/undo 139%% table functions. They just see the list of cols, and if an error 140%% occurs, they return the column nunber. 141%% Also, delete duplicate columns. If a SET is performed with duplicate 142%% columns, it is undefined which column to use. We just pick one. 143delete_org_index([{RowIndex, Cols} | Rows]) -> 144 [{RowIndex, doi(Cols)} | delete_org_index(Rows)]; 145delete_org_index([]) -> []. 146 147doi([{Col, Val, OrgIndex}, {Col, _Val, _OrgIndex} | T]) -> 148 doi([{Col, Val, OrgIndex} | T]); 149doi([{Col, Val, _OrgIndex} | T]) -> 150 [{Col, Val} | doi(T)]; 151doi([]) -> []. 152 153%% Maps the column number to OrgIndex. 154col_to_orgindex(0, _) -> 0; 155col_to_orgindex(Col, [{Col, _Val, OrgIndex}|_]) -> 156 OrgIndex; 157col_to_orgindex(Col, [_|Cols]) -> 158 col_to_orgindex(Col, Cols); 159col_to_orgindex(BadCol, _) -> 160 {false, BadCol}. 161