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
21-module(snmp_pdus).
22
23-define(SNMP_USE_V3, true).
24-include("snmp_types.hrl").
25
26-define(VMODULE,"PDUS").
27-include("snmp_verbosity.hrl").
28
29%% See RFC1155, RFC1157, RFC1901, RFC1902, RFC1905, RFC2272
30
31
32%% API
33-export([enc_message/1, enc_message_only/1, enc_pdu/1,
34	 enc_varbind/1,
35	 enc_oct_str_tag/1, enc_scoped_pdu/1,
36	 enc_usm_security_parameters/1,
37	 dec_message/1, dec_message_only/1, dec_pdu/1,
38	 dec_scoped_pdu_data/1, dec_scoped_pdu/1,
39	 dec_usm_security_parameters/1,
40	 strip_encrypted_scoped_pdu_data/1,
41	 octet_str_to_bits/1, bits_to_str/1,
42	 get_encoded_length/1,
43	 enc_value/2, dec_value/1]).
44
45%% -compile(export_all).
46
47%% Returns the number of octets required to encode Length.
48get_encoded_length(Length) ->
49    length(elength(Length)).
50
51dec_message([48 | Bytes]) ->
52    Bytes2 = get_data_bytes(Bytes),
53    case dec_snmp_version(Bytes2) of
54	{'version-3', Rest} ->
55	    dec_rest_v3_msg(Rest);
56	{Vsn, Rest} -> % 1 or 2
57	    dec_rest_v1_v2_msg(Vsn, Rest)
58    end.
59
60dec_message_only([48 | Bytes]) ->
61    Bytes2 = get_data_bytes(Bytes),
62    case dec_snmp_version(Bytes2) of
63	{'version-3', Rest} ->
64	    dec_rest_v3_msg_only(Rest);
65	{Vsn, Rest} -> % 1 or 2
66	    dec_rest_v1_v2_msg_only(Vsn, Rest)
67    end.
68
69dec_snmp_version(Bytes) ->
70    case (catch dec_int_tag(Bytes, 10)) of
71	{error, {bad_integer, BadInt}} ->
72	    exit({bad_version, BadInt});
73	{SNMPversion, Rest} when is_integer(SNMPversion) andalso is_list(Rest) ->
74	    {dec_snmp_ver(SNMPversion), Rest};
75	{'EXIT', Reason} ->
76	    exit(Reason)
77    end.
78
79
80dec_snmp_ver(0) ->
81    'version-1';
82dec_snmp_ver(1) ->
83    'version-2';
84dec_snmp_ver(3) ->
85    'version-3';
86dec_snmp_ver(Vsn) ->
87    exit({bad_version, Vsn}).
88
89dec_rest_v1_v2_msg(Vsn, Rest1) ->
90    {Community, Rest2} = dec_oct_str_tag(Rest1),
91    PDU = dec_pdu(Rest2),
92    #message{version = Vsn, vsn_hdr = Community, data = PDU}.
93
94dec_rest_v1_v2_msg_only(Vsn, Rest1) ->
95    {Community, Rest2} = dec_oct_str_tag(Rest1),
96    #message{version = Vsn, vsn_hdr = Community, data = Rest2}.
97
98dec_rest_v3_msg_only([48 | Bytes]) -> % starts with header data sequence
99    {Size, Tail} = dec_len(Bytes),
100    {HBytes, Bytes1} = split_at(Tail, Size, []),
101    %% Decode HeaderData
102    {MsgID, HBytes1} = dec_int_tag(HBytes),
103    chk_msg_id(MsgID),
104    {MsgMaxSize, HBytes2} = dec_int_tag(HBytes1),
105    chk_msg_max_size(MsgMaxSize),
106    {MsgFlags, HBytes3} = dec_oct_str_tag(HBytes2),
107    {MsgSecurityModel, []} = dec_int_tag(HBytes3),
108    chk_msg_sec_model(MsgSecurityModel),
109    %% Continue with Message
110%    {MsgSecurityParameters, Bytes2} = dec_oct_str_tag(Bytes1),
111
112    [4 | Bytes1a] = Bytes1,
113    {Size1a, Tail1a} = dec_len(Bytes1a),
114    {MsgSecurityParameters, Bytes2} = split_at(Tail1a, Size1a, []),
115
116    %% [48 , HdrDataLen, HdrData, 4, MsgSecLen, MsgSec, ...]
117    %% NOTE: HdrDataLen is always so small that one octet is enough to
118    %%         encode its length.
119    %%       MsgSecLen is worse... but for USM, it is small enough for
120    %%         one octet.  USM is currently the only secmodel.
121    %% 1 + 1 + Size + 1 + 1 + Size1a
122    HdrSize = Size + Size1a + 4,
123    V3Hdr = #v3_hdr{msgID = MsgID,
124		    msgMaxSize = MsgMaxSize,
125		    msgFlags = MsgFlags, %dec_msg_flags(MsgFlags),
126		    msgSecurityModel = MsgSecurityModel,
127		    msgSecurityParameters = MsgSecurityParameters,
128		    hdr_size = HdrSize},
129    #message{version = 'version-3', vsn_hdr = V3Hdr, data = Bytes2}.
130
131dec_rest_v3_msg(Bytes) ->
132    Message = dec_rest_v3_msg_only(Bytes),
133    Data = Message#message.data,
134    Message#message{data = dec_scoped_pdu_data(Data)}.
135
136dec_scoped_pdu_data([48 | Bytes]) -> % plaintext
137    {ScopedPdu, []} = dec_scoped_pdu_notag(Bytes),
138    ScopedPdu;
139dec_scoped_pdu_data([4 | Bytes]) -> % encryptedPDU
140    {EncryptedPDU, []} = dec_oct_str_notag(Bytes),
141    EncryptedPDU.
142
143
144dec_scoped_pdu([48 | Bytes]) ->
145    element(1, dec_scoped_pdu_notag(Bytes)).
146
147dec_scoped_pdu_notag(Bytes) ->
148    Bytes1 = get_data_bytes(Bytes),
149    {ContextEngineID, Bytes2} = dec_oct_str_tag(Bytes1),
150    {ContextName, Bytes3} = dec_oct_str_tag(Bytes2),
151    Pdu = dec_pdu(Bytes3),
152    {#scopedPdu{contextEngineID = ContextEngineID,
153		contextName = ContextName,
154		data = Pdu},
155     []}.
156
157dec_pdu_tag(160) ->
158    'get-request';
159dec_pdu_tag(161) ->
160    'get-next-request';
161dec_pdu_tag(162) ->
162    'get-response';
163dec_pdu_tag(163) ->
164    'set-request';
165%% 164 SNMPv1 Trap
166%% 165 Bulk
167dec_pdu_tag(166) ->
168    'inform-request';
169dec_pdu_tag(167) ->
170    'snmpv2-trap';
171dec_pdu_tag(168) ->
172    report.
173
174
175dec_pdu([164 | Bytes]) ->      % It's a trap
176    Bytes2 = get_data_bytes(Bytes),
177    {Enterprise, Rest1} = dec_oid_tag(Bytes2),
178    {{'IpAddress', [_, _, _, _] = AgentAddr}, Rest2} = dec_value(Rest1),
179    {GenericTrap, Rest3} = dec_int_tag(Rest2),
180    {SpecificTrap, Rest4} = dec_int_tag(Rest3),
181    {{'TimeTicks', TimeStamp}, VBBytes} = dec_value(Rest4),
182    VBs = dec_VBs(VBBytes),
183    #trappdu{enterprise = Enterprise, agent_addr = AgentAddr,
184	     generic_trap = GenericTrap, specific_trap = SpecificTrap,
185	     time_stamp = TimeStamp, varbinds = VBs};
186
187dec_pdu([165 | Bytes]) ->    % Bulk
188    Bytes2 = get_data_bytes(Bytes),
189    {RequestID, Rest1} = dec_int_tag(Bytes2),
190    {NonRepeaters, Rest2} = dec_int_tag(Rest1),
191    {MaxRepetitions,VBbytes} = dec_int_tag(Rest2),
192    VBs = dec_VBs(VBbytes),
193    #pdu{type = 'get-bulk-request', request_id = RequestID,
194	 error_status = NonRepeaters, error_index = MaxRepetitions,
195	 varbinds = VBs};
196
197dec_pdu([PduTag | Bytes]) ->
198    Type = dec_pdu_tag(PduTag),
199    Bytes2 = get_data_bytes(Bytes),
200    {RequestID, Rest1} = dec_int_tag(Bytes2),
201    {ErrStat, Rest2} = dec_int_tag(Rest1),
202    ErrStatus = case lists:keysearch(ErrStat, 2, errMsgs()) of
203		    {value, {ErrStatName, _ErrStat}} ->
204			ErrStatName;
205		    false ->
206			ErrStat
207		end,
208    {ErrIndex, VarbindsBytes} = dec_int_tag(Rest2),
209    VBs = dec_VBs(VarbindsBytes),
210    #pdu{type = Type, request_id = RequestID, error_status = ErrStatus,
211	 error_index = ErrIndex, varbinds = VBs}.
212
213dec_VBs([48 | Bytes]) ->
214    Bytes1 = get_data_bytes(Bytes),
215    dec_individual_VBs(Bytes1, 1, []).
216
217dec_individual_VBs([], _No, VBs) ->
218    lists:reverse(VBs);
219dec_individual_VBs([48 | Bytes], OrgIndex, AccVBs) ->
220    {_SizeOfThisVB, Bytes2} = dec_len(Bytes),
221    {Oid, Rest} = dec_oid_tag(Bytes2),
222    {{Type, Value}, Rest2} = dec_value(Rest),
223    % perhaps we should check that we have eaten SizeOfThisVB bytes, but we
224    % don't consider ourselves to have time for such list traversing stuff.
225    dec_individual_VBs(Rest2, OrgIndex + 1, [#varbind{oid = Oid,
226						      variabletype = Type,
227						      value = Value,
228						      org_index = OrgIndex}
229					     | AccVBs]).
230
231dec_usm_security_parameters([48 | Bytes1]) ->
232    {_Len, Bytes2} = dec_len(Bytes1),
233    {MsgAuthEngineID, Bytes3} = dec_oct_str_tag(Bytes2),
234    {MsgAuthEngineBoots, Bytes4} = dec_int_tag(Bytes3),
235    {MsgAuthEngineTime, Bytes5} = dec_int_tag(Bytes4),
236    {MsgUserName, Bytes6} = dec_oct_str_tag(Bytes5),
237    {MsgAuthParams, Bytes7} = dec_oct_str_tag(Bytes6),
238    {MsgPrivParams, []} = dec_oct_str_tag(Bytes7),
239    #usmSecurityParameters{msgAuthoritativeEngineID = MsgAuthEngineID,
240			   msgAuthoritativeEngineBoots = MsgAuthEngineBoots,
241			   msgAuthoritativeEngineTime = MsgAuthEngineTime,
242			   msgUserName = MsgUserName,
243			   msgAuthenticationParameters = MsgAuthParams,
244			   msgPrivacyParameters = MsgPrivParams}.
245
246strip_encrypted_scoped_pdu_data([48 | Bytes]) ->
247    {Size, Tail} = dec_len(Bytes),
248    [48 | elength(Size)] ++ strip(Size, Tail).
249
250strip(N, [H|T]) when N > 0 -> [H | strip(N-1, T)];
251strip(0, _Tail) ->
252    [].
253
254
255%%----------------------------------------------------------------------
256%% Returns:{Type, Value}
257%%----------------------------------------------------------------------
258
259%% OBJECT IDENTIFIER
260dec_value([6 | Bytes]) ->
261    {Value, Rest} = dec_oid_notag(Bytes),
262    {{'OBJECT IDENTIFIER', Value}, Rest};
263dec_value([5,0 | T]) ->
264    {{'NULL', 'NULL'}, T};
265
266%% INTEGER
267dec_value([2 | Bytes]) ->
268    {Value, Rest} = dec_integer_notag(Bytes),
269    {{'INTEGER', Value}, Rest};
270
271%% OCTET STRING
272dec_value([4 | Bytes]) ->
273    {Value, Rest} = dec_oct_str_notag(Bytes),
274    {{'OCTET STRING', Value}, Rest};
275
276%% IpAddress
277dec_value([64 | Bytes]) ->
278    {Value, Rest} = dec_oct_str_notag(Bytes),
279    {{'IpAddress', Value}, Rest};
280
281%% Counter32
282dec_value([65 | Bytes]) ->
283    %% Counter32 is an unsigned 32 but is actually encoded as
284    %% a signed integer 32 (INTEGER).
285    {Value, Rest} = dec_integer_notag(Bytes),
286    Value2 =
287    	if
288    	    (Value >= 0) andalso (Value =< 16#ffffffff) ->
289    		%% We accept value above 16#7fffffff
290    		%% in order to be backward bug-compatible
291    		Value;
292    	    (Value < 0) ->
293    		16#ffffffff + Value + 1;
294    	    true ->
295    		exit({error, {bad_counter32, Value}})
296    	end,
297    {{'Counter32', Value2}, Rest};
298
299%% Unsigned32
300dec_value([66 | Bytes]) ->
301    {Value, Rest} = dec_integer_notag(Bytes),
302    Value2 =
303	if
304	    (Value >= 0) andalso (Value =< 16#ffffffff) ->
305		Value;
306	    (Value < 0) ->
307		16#ffffffff + Value + 1;
308	    true ->
309		exit({error, {bad_unsigned32, Value}})
310	end,
311    {{'Unsigned32', Value2}, Rest};
312
313%% TimeTicks
314dec_value([67 | Bytes]) ->
315    {Value, Rest} = dec_integer_notag(Bytes),
316    Value2 =
317	if
318	    (Value >= 0) andalso (Value =< 16#ffffffff) ->
319		Value;
320	    (Value < 0) ->
321		16#ffffffff + Value + 1;
322	true ->
323	    exit({error, {bad_timeticks, Value}})
324	end,
325    {{'TimeTicks', Value2}, Rest};
326
327%% Opaque
328dec_value([68 | Bytes]) ->
329    {Value, Rest} = dec_oct_str_notag(Bytes),
330    {{'Opaque', Value}, Rest};
331
332%% Counter64
333dec_value([70 | Bytes]) ->
334    %% Counter64 is an unsigned 64 but is actually encoded as
335    %% a signed integer 64.
336    {Value, Rest} = dec_integer_notag(Bytes),
337    Value2 =
338    	if
339    	    (Value >= 0) andalso (Value < 16#8000000000000000) ->
340    		Value;
341    	    (Value < 0) ->
342    		16#ffffffffffffffff + Value + 1;
343    	    true ->
344    		exit({error, {bad_counter64, Value}})	end,
345    {{'Counter64', Value2}, Rest};
346
347dec_value([128,0|T]) ->
348    {{'NULL', noSuchObject}, T};
349dec_value([129,0|T]) ->
350    {{'NULL', noSuchInstance}, T};
351dec_value([130,0|T]) ->
352    {{'NULL', endOfMibView}, T}.
353
354
355%%----------------------------------------------------------------------
356%% Purpose: Uses the beginning length bytes to return the actual data.
357%% If data has the wrong length, the program is exited.
358%% Pre: Tag is removed.
359%%----------------------------------------------------------------------
360get_data_bytes(Bytes) ->
361    {Size, Tail} = dec_len(Bytes),
362    if
363	length(Tail) =:= Size ->
364	    Tail;
365	true ->
366	    exit({error, {wrong_length, Bytes}})
367    end.
368
369split_at(L, 0, Acc) ->
370    {lists:reverse(Acc), L};
371split_at([H|T], N, Acc) ->
372    split_at(T, N-1, [H|Acc]).
373
374%%----------------------------------------------------------------------
375%% All decoding routines return: {Data, RestBytes}
376%%----------------------------------------------------------------------
377
378dec_int_tag([2 | Bytes]) ->
379    dec_integer_notag(Bytes).
380dec_int_tag([2 | Bytes], SizeLimit) ->
381    dec_integer_notag(Bytes, SizeLimit).
382
383dec_integer_notag(Ints) ->
384    dec_integer_notag(Ints, infinity).
385dec_integer_notag(Ints, SizeLimit) ->
386    case dec_len(Ints) of
387	{Size, Ints2} when SizeLimit =:= infinity ->
388	    do_dec_integer_notag(Size, Ints2);
389	{Size, Ints2} when (is_integer(SizeLimit) andalso
390			    (Size =< SizeLimit)) ->
391	    do_dec_integer_notag(Size, Ints2);
392	{BadSize, _BadInts2} ->
393	    throw({error, {bad_integer, {BadSize, SizeLimit}}})
394    end.
395
396do_dec_integer_notag(Size, Ints) ->
397    if hd(Ints) band 128 == 0 -> %% Positive number
398	    dec_pos_int(Ints, Size, 8 * (Size - 1));
399       true -> %% Negative
400	    dec_neg_int(Ints, Size, 8 * (Size - 1))
401    end.
402
403
404dec_pos_int(T, 0, _) -> {0, T};
405dec_pos_int([Byte|Tail], Size, Shift) ->
406    {Int, Rest} = dec_pos_int(Tail, Size - 1, Shift - 8),
407    {(Byte bsl Shift) bor Int, Rest}.
408
409dec_neg_int(T, 0, _) -> {0, T};
410dec_neg_int([Byte|Tail], Size, Shift) ->
411    {Int, Rest} = dec_pos_int(Tail, Size - 1, Shift-8),
412    {(-128 + (Byte band 127) bsl Shift) bor Int, Rest}.
413
414dec_oct_str_tag([4 | Bytes]) ->
415    dec_oct_str_notag(Bytes).
416
417dec_oct_str_notag(Bytes) ->
418    {Size, Tail} = dec_len(Bytes),
419    split_at(Tail, Size, []).
420
421dec_oid_tag([6 | Bytes]) ->
422    dec_oid_notag(Bytes).
423
424dec_oid_notag(Bytes) ->
425    {Size, [H | Tail]} = dec_len(Bytes),
426    {Oid, Rest} = dec_oid_elements(Tail, Size - 1, []),
427    {[H div 40, H rem 40 | Oid], Rest}.
428
429dec_oid_elements(L, 0, Acc) ->
430    {lists:reverse(Acc), L};
431dec_oid_elements([Dig|Tail], Size, Acc) when Dig < 128 ->
432    dec_oid_elements(Tail, Size - 1, [Dig | Acc]);
433dec_oid_elements([Dig|Tail], Size, Acc) ->
434    {Num, Neaten, Tl} = dec_oid_element(Tail,1,Dig band 127),
435    dec_oid_elements(Tl, Size - Neaten, [Num|Acc]).
436
437dec_oid_element([Dig|Tail], Neaten, Num) when Dig < 128 ->
438    {Num*128+Dig,Neaten+1,Tail};
439dec_oid_element([Dig|Tail],Neaten, Num) ->
440    dec_oid_element(Tail, Neaten+1, Num*128 + (Dig band 127)).
441
442chk_msg_id(MsgId) when (MsgId >= 0) andalso (MsgId =< 2147483647) -> ok;
443chk_msg_id(MsgId) -> exit({bad_msg_id, MsgId}).
444
445chk_msg_max_size(MMS) when (MMS >= 484) andalso (MMS =< 2147483647) -> ok;
446chk_msg_max_size(MMS) -> exit({bad_msg_max_size, MMS}).
447
448chk_msg_sec_model(MsgSecurityModel) when MsgSecurityModel >= 0,
449					 MsgSecurityModel =< 2147483647 -> ok;
450chk_msg_sec_model(MsgSecurityModel) ->
451    exit({bad_msg_sec_model, MsgSecurityModel}).
452
453%%----------------------------------------------------------------------
454%% Code copied from the original ASN.1 compiler written by
455%% klacke@erix.ericsson.se
456%%----------------------------------------------------------------------
457
458%%----------------------------------------------------------------------
459%% Returns: {Len, Tail}
460%%----------------------------------------------------------------------
461dec_len([128|_Tail]) ->
462    %% indefinite form - not allowed in SNMP
463    exit({asn1_error, indefinite_length});
464
465dec_len([Hd|Tl]) when Hd >= 0 ->
466    %% definite form
467    if
468	Hd < 128 -> % 8th bit is cleared
469	    %% Short form (actually, we can remove this test, since snmp_pdus
470	    %% performs this test _before_ calling this function)
471	    {Hd,Tl};
472	true ->
473	    %% Long form
474	    No = Hd band 127,  % clear 8th bit
475	    {DigList, Rest} = head(No, Tl),
476	    Size = dec_integer_len(DigList),
477	    {Size, Rest}
478    end.
479
480dec_integer_len([D]) ->
481    D;
482dec_integer_len([A,B]) ->
483    (A bsl 8) bor B;
484dec_integer_len([A,B,C]) ->
485    (A bsl 16) bor (B bsl 8) bor C;
486%% More than 3 elements for length => either *very* long packet
487%% (which we don't handle), or the length is encoded with more octets
488%% than necessary (in which case the first octet must be 0).
489dec_integer_len([0 | T]) ->
490    dec_integer_len(T).
491
492%%-----------------------------------------------------------------
493%% head(N, List) -> {List1, List2}
494%%   List == List1 ++ List2
495%%   length(List1) == N
496%%-----------------------------------------------------------------
497head(L,List) ->
498    head(L,List,[]).
499
500head(0,L,Res) ->
501    {lists:reverse(Res),L};
502
503head(Int,[H|Tail],Res) ->
504    head(Int-1,Tail,[H|Res]);
505head(Int, [], _Res) ->
506    exit({asn1_error, {bad_length, Int}}).
507
508%%%----------------------------------------------------------------------
509%%% ENCODING ENCODING ENCODING ENCODING ENCODING ENCODING ENCODING ENCODING
510%%%----------------------------------------------------------------------
511
512enc_message(#message{version = Ver, vsn_hdr = VsnHdr, data = Data}) ->
513    VerBytes = enc_version(Ver),
514    Bytes =
515	case Ver of
516	    'version-3' ->
517		V3HeaderBytes = enc_v3_header(VsnHdr),
518		DataBytes = enc_scoped_pdu(Data),
519		V3HeaderBytes ++ DataBytes;
520	    _ ->
521		ComBytes = enc_community(VsnHdr),
522		DataBytes = enc_pdu(Data),
523		ComBytes ++ DataBytes
524	end,
525    Bytes2 = VerBytes ++ Bytes,
526    Len = elength(length(Bytes2)),
527    [48 | Len] ++ Bytes2.
528
529enc_message_only(#message{version = Ver, vsn_hdr = VsnHdr, data = DataBytes}) ->
530    VerBytes = enc_version(Ver),
531    Bytes =
532	case Ver of
533	    'version-3' ->
534		V3HeaderBytes = enc_v3_header(VsnHdr),
535		V3HeaderBytes ++ DataBytes;
536	    _ ->
537		ComBytes = enc_community(VsnHdr),
538		ComBytes ++ DataBytes
539	end,
540    Bytes2 = VerBytes ++ Bytes,
541    Len = elength(length(Bytes2)),
542    [48 | Len] ++ Bytes2.
543
544enc_version('version-1') ->
545    [2,1,0];
546enc_version('version-2') ->
547    [2,1,1];
548enc_version('version-3') ->
549    [2,1,3].
550
551enc_community(Com) ->
552    enc_oct_str_tag(Com).
553
554enc_v3_header(#v3_hdr{msgID = MsgID,
555		      msgMaxSize = MsgMaxSize,
556		      msgFlags = MsgFlags,
557		      msgSecurityModel = MsgSecurityModel,
558		      msgSecurityParameters = MsgSecurityParameters}) ->
559    Bytes = lists:append([enc_integer_tag(MsgID),
560			  enc_integer_tag(MsgMaxSize),
561			  enc_oct_str_tag(MsgFlags),
562			  enc_integer_tag(MsgSecurityModel)]),
563    Len = elength(length(Bytes)),
564    lists:append([[48 | Len], Bytes, enc_oct_str_tag(MsgSecurityParameters)]).
565
566enc_scoped_pdu(#scopedPdu{contextEngineID = ContextEngineID,
567			  contextName = ContextName,
568			  data = Data}) ->
569    Bytes = lists:append([enc_oct_str_tag(ContextEngineID),
570			  enc_oct_str_tag(ContextName),
571			  enc_pdu(Data)]),
572    Len = elength(length(Bytes)),
573    [48 | Len] ++ Bytes.
574
575
576enc_pdu(PDU) when PDU#pdu.type =:= 'get-request' ->
577    enc_pdu(160, PDU);
578enc_pdu(PDU) when PDU#pdu.type =:= 'get-next-request' ->
579    enc_pdu(161, PDU);
580enc_pdu(PDU) when PDU#pdu.type =:= 'get-response' ->
581    enc_pdu(162, PDU);
582enc_pdu(PDU) when PDU#pdu.type =:= 'set-request' ->
583    enc_pdu(163, PDU);
584enc_pdu(PDU) when PDU#pdu.type =:= 'get-bulk-request' ->
585    enc_pdu(165, PDU);
586enc_pdu(PDU) when PDU#pdu.type =:= 'inform-request' ->
587    enc_pdu(166, PDU);
588enc_pdu(PDU) when PDU#pdu.type =:= 'snmpv2-trap' ->
589    enc_pdu(167, PDU);
590enc_pdu(PDU) when PDU#pdu.type =:= report ->
591    enc_pdu(168, PDU);
592enc_pdu(TrapPDU) when is_record(TrapPDU, trappdu) ->
593    enc_Trap(TrapPDU).
594
595
596enc_pdu(Tag,PDU) ->
597    Bytes2 = enc_pdu2(PDU),
598    Len2 = elength(length(Bytes2)),
599    lists:append([Tag | Len2], Bytes2).
600
601enc_pdu2(#pdu{type = Type, request_id = ReqId, error_index = ErrIndex,
602	      error_status = ErrStat, varbinds = VBs}) ->
603    ReqBytes = enc_integer_tag(ReqId),
604    Val = err_val(ErrStat,Type),
605    ErrStatBytes = enc_integer_tag(Val),
606    ErrIndexBytes = enc_integer_tag(ErrIndex),
607    VBsBytes = enc_VarBindList(VBs),
608    lists:append([ReqBytes, ErrStatBytes, ErrIndexBytes, VBsBytes]).
609
610enc_usm_security_parameters(
611  #usmSecurityParameters{msgAuthoritativeEngineID = MsgAuthEngineID,
612			 msgAuthoritativeEngineBoots = MsgAuthEngineBoots,
613			 msgAuthoritativeEngineTime = MsgAuthEngineTime,
614			 msgUserName = MsgUserName,
615			 msgAuthenticationParameters = MsgAuthParams,
616			 msgPrivacyParameters = MsgPrivParams}) ->
617    Bytes1 = enc_oct_str_tag(MsgAuthEngineID),
618    Bytes2 = enc_integer_tag(MsgAuthEngineBoots),
619    Bytes3 = enc_integer_tag(MsgAuthEngineTime),
620    Bytes4 = enc_oct_str_tag(MsgUserName),
621    Bytes5 = enc_oct_str_tag(MsgAuthParams),
622    Bytes6 = enc_oct_str_tag(MsgPrivParams),
623    Bytes7 = lists:append([Bytes1, Bytes2, Bytes3, Bytes4, Bytes5, Bytes6]),
624    Len = elength(length(Bytes7)),
625    [48 | Len] ++ Bytes7.
626
627err_val(Int,'get-bulk-request') when is_integer(Int) -> Int;
628err_val(ErrStat, _) ->
629    {value, {_ErrStat, Val}} = lists:keysearch(ErrStat, 1, errMsgs()),
630    Val.
631
632errMsgs() ->
633    [{noError,0},{tooBig,1},{noSuchName,2},
634     {badValue,3},{readOnly,4},{genErr,5},
635     %% v2
636     {noAccess,6},{wrongType,7},{wrongLength,8},{wrongEncoding,9},
637     {wrongValue,10},{noCreation,11},{inconsistentValue,12},
638     {resourceUnavailable,13},{commitFailed,14},{undoFailed,15},
639     {authorizationError,16},{notWritable,17},{inconsistentName,18}].
640
641enc_VarBindList(EncodedVBs) when is_integer(hd(EncodedVBs)) ->
642    Len1 = elength(length(EncodedVBs)),
643    lists:append([48 | Len1],EncodedVBs);
644enc_VarBindList(VBs) ->
645    Bytes1 = lists:append(lists:map(fun enc_varbind/1, VBs)),
646    Len1 = elength(length(Bytes1)),
647    lists:append([48 | Len1],Bytes1).
648
649enc_varbind(Varbind) ->
650    Bytes1 = enc_VarBind_attributes(Varbind),
651    Len1 = elength(length(Bytes1)),
652    lists:append([48 | Len1],Bytes1).
653
654
655enc_VarBind_attributes(#varbind{oid = Oid, variabletype = Type,value = Val}) ->
656    OidBytes = enc_oid_tag(Oid),
657    ValueBytes = enc_value(Type, Val),
658    lists:append(OidBytes, ValueBytes).
659
660enc_value('INTEGER', Val) ->
661    enc_integer_tag(Val);
662enc_value('OCTET STRING', Val) ->
663    enc_oct_str_tag(Val);
664enc_value('BITS', Val) ->
665    enc_oct_str_tag(bits_to_str(Val));
666enc_value('OBJECT IDENTIFIER', Val) ->
667    enc_oid_tag(Val);
668enc_value('IpAddress', {A, B, C, D}) ->
669    enc_value('IpAddress', [A,B,C,D]);
670enc_value('IpAddress', Val) when is_list(Val) ->
671    Bytes2 = enc_oct_str_notag(Val),
672    Len2 = elength(length(Bytes2)),
673    lists:append([64 | Len2],Bytes2);
674enc_value('Opaque', Val) ->
675    Bytes2 = enc_oct_str_notag(Val),
676    Len2 = elength(length(Bytes2)),
677    lists:append([68 | Len2],Bytes2);
678enc_value(_Type, noSuchObject) ->
679    [128,0];
680enc_value(_Type, noSuchInstance) ->
681    [129,0];
682enc_value(_Type, endOfMibView) ->
683    [130,0];
684enc_value('NULL', _Val) ->
685    [5,0];
686enc_value('Counter32', Val) ->
687    Val2 =
688	if
689	    Val > 16#ffffffff ->
690		exit({error, {bad_counter32, Val}});
691	    Val >= 16#80000000 ->
692		(Val band 16#7fffffff) - 16#80000000;
693	    Val >= 0 ->
694		Val;
695	    true ->
696		exit({error, {bad_counter32, Val}})
697	end,
698    Bytes2 = enc_integer_notag(Val2),
699    Len2 = elength(length(Bytes2)),
700    lists:append([65 | Len2],Bytes2);
701enc_value('Unsigned32', Val) ->
702    if
703	(Val >= 0) andalso (Val =< 4294967295) ->
704	    Bytes2 = enc_integer_notag(Val),
705	    Len2 = elength(length(Bytes2)),
706	    lists:append([66 | Len2], Bytes2);
707	true ->
708	    exit({error, {bad_counter32, Val}})
709    end;
710enc_value('TimeTicks', Val) ->
711    if
712	(Val >= 0) andalso (Val =< 4294967295) ->
713	    Bytes2 = enc_integer_notag(Val),
714	    Len2 = elength(length(Bytes2)),
715	    lists:append([67 | Len2], Bytes2);
716	true ->
717	    exit({error, {bad_timeticks, Val}})
718    end;
719enc_value('Counter64', Val) ->
720    Val2 =
721	if
722	    Val > 16#ffffffffffffffff ->
723		exit({error, {bad_counter64, Val}});
724	    Val >= 16#8000000000000000 ->
725		(Val band 16#7fffffffffffffff) - 16#8000000000000000;
726	    Val >= 0 ->
727		Val;
728	    true ->
729		exit({error, {bad_counter64, Val}})
730	end,
731    Bytes2 = enc_integer_notag(Val2),
732    Len2 = elength(length(Bytes2)),
733    lists:append([70 | Len2],Bytes2).
734
735
736%%----------------------------------------------------------------------
737%% Impl according to RFC1906, section 8
738%% For example: the number 1010 0000 (=160)   0100 0001 (=65) is represented as
739%% the octet string: 1000 0010, 0000 0101 (=[130,5])
740%%----------------------------------------------------------------------
741bits_to_str(0) -> "";
742bits_to_str(Int) ->
743    [rev_int8(Int band 255) | bits_to_str(Int div 256)].
744
745rev_int8(Val) ->
746    rev_int(Val,0,1,128).
747
748rev_int(_Val,Res,256,0) -> Res;
749rev_int(Val,Res,OldBit,NewBit) when Val band OldBit =/= 0 ->
750    rev_int(Val,Res+NewBit,OldBit*2,NewBit div 2);
751rev_int(Val,Res,OldBit,NewBit) ->
752    rev_int(Val,Res,OldBit*2,NewBit div 2).
753
754octet_str_to_bits(Str) ->
755    octet_str_to_bits(Str,1).
756
757octet_str_to_bits("",_) -> 0;
758octet_str_to_bits([Byte|Bytes],Mul) ->
759    Mul*rev_int8(Byte)+octet_str_to_bits(Bytes,Mul*256).
760
761
762enc_Trap(TrapPdu) when is_record(TrapPdu, trappdu) ->
763    Bytes1 = enc_trap_data(TrapPdu),
764    Len1 = elength(length(Bytes1)),
765    lists:append([164 | Len1],Bytes1).
766
767
768enc_trap_data(#trappdu{enterprise = Enterprise,
769		       agent_addr = AgentAddr,
770		       generic_trap = GenericTrap,
771		       specific_trap = SpecificTrap,
772		       time_stamp = TimeStamp,
773		       varbinds = VBs}) ->
774    L1 = enc_oid_tag(Enterprise),
775    L2 = enc_value('IpAddress', AgentAddr),
776    L3 = enc_integer_tag(GenericTrap),
777    L4 = enc_integer_tag(SpecificTrap),
778    L5 = enc_value('TimeTicks', TimeStamp),
779    L6 = enc_VarBindList(VBs),
780    lists:append([L1,L2,L3,L4,L5,L6]).
781
782enc_oid_tag([E1,E2|RestOid]) when E1 * 40 + E2 =< 255 ->
783    Head = 40*E1 + E2,  % weird
784    Res = e_object_elements(RestOid, []),
785    lists:append([6 | elength(length(Res) + 1)],[Head|Res]).
786
787e_object_elements([Num | T], Res)  ->
788    e_object_elements(T, lists:append(e_object_element(Num),Res));
789
790e_object_elements([], Res) -> lists:reverse(Res).
791
792%%----------------------------------------------------------------------
793%% The reversed encoding for an oid-element
794%%----------------------------------------------------------------------
795e_object_element(Num) when Num > 0 ->
796    [Last|T] = e_object_element2(Num),
797    [Last-128|T];
798e_object_element(0) -> [0].
799
800e_object_element2(Num) when Num > 0 ->
801    Byte = (Num rem 128),
802    [128+Byte | e_object_element2((Num-Byte) div 128)];
803e_object_element2(0) -> [].
804
805enc_integer_tag(Val) when Val >= 0 ->  %% stdcase positive ints
806    Bytes = eint(Val,[]),
807    [2 | elength(length(Bytes))] ++ Bytes;
808
809enc_integer_tag(Val) ->  %% It's a negative number
810    Bytes = enint(Val,[]),
811    [2 | elength(length(Bytes))] ++ Bytes.
812
813enc_integer_notag(Val) when Val >= 0 ->  %% stdcase positive ints
814    eint(Val,[]);
815
816enc_integer_notag(Val) -> %% It's a negative number
817    enint(Val,[]).
818
819eint(0, [B|Acc]) when B < 128 ->
820    [B|Acc];
821eint(N, Acc) ->
822    eint(N bsr 8, [N band 16#ff| Acc]).
823
824enint(-1, [B1|T]) when B1 > 127 ->
825    [B1|T];
826enint(N, Acc) ->
827    enint(N bsr 8, [N band 16#ff|Acc]).
828
829enc_oct_str_tag(OStr) when is_list(OStr) ->
830    lists:append([4|elength(length(OStr))],OStr);
831enc_oct_str_tag(OBin) ->
832    [4 | elength(size(OBin))] ++ binary_to_list(OBin).
833
834
835enc_oct_str_notag(OStr) -> OStr.
836
837%%-----------------------------------------------------------------
838%% Always use definite form
839%%-----------------------------------------------------------------
840%% Short
841elength(L) when L < 127 ->
842    [L];
843
844%% 3 cases of long form
845elength(L) when L =< 16#FF ->
846    [2#10000001,L];
847
848elength(L) when L  =< 16#FFFF ->
849    [2#10000010,(L bsr 8),(L band 16#FF)];
850
851elength(L) when L =< 16#7FFFFF ->
852    [2#10000011,(L bsr 16),((L band 16#FF00) bsr 8), (L band 16#FF)].
853
854
855