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