smux.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545
  1. /* SNMP support
  2. * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
  3. *
  4. * This file is part of GNU Zebra.
  5. *
  6. * GNU Zebra is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2, or (at your option) any
  9. * later version.
  10. *
  11. * GNU Zebra is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GNU Zebra; see the file COPYING. If not, write to the Free
  18. * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  19. * 02111-1307, USA.
  20. */
  21. #include <zebra.h>
  22. #ifdef HAVE_SNMP
  23. #ifdef HAVE_NETSNMP
  24. #include <net-snmp/net-snmp-config.h>
  25. #include <net-snmp/net-snmp-includes.h>
  26. #else
  27. #include <asn1.h>
  28. #include <snmp.h>
  29. #include <snmp_impl.h>
  30. #endif
  31. #include "log.h"
  32. #include "thread.h"
  33. #include "linklist.h"
  34. #include "command.h"
  35. #include <lib/version.h>
  36. #include "memory.h"
  37. #include "sockunion.h"
  38. #include "smux.h"
  39. #define min(A,B) ((A) < (B) ? (A) : (B))
  40. enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
  41. void smux_event (enum smux_event, int);
  42. /* SMUX socket. */
  43. int smux_sock = -1;
  44. /* SMUX subtree list. */
  45. struct list *treelist;
  46. /* SMUX oid. */
  47. oid *smux_oid = NULL;
  48. size_t smux_oid_len;
  49. /* SMUX password. */
  50. char *smux_passwd = NULL;
  51. /* SMUX read threads. */
  52. struct thread *smux_read_thread;
  53. /* SMUX connect thrads. */
  54. struct thread *smux_connect_thread;
  55. /* SMUX debug flag. */
  56. int debug_smux = 0;
  57. /* SMUX failure count. */
  58. int fail = 0;
  59. /* SMUX node. */
  60. static struct cmd_node smux_node =
  61. {
  62. SMUX_NODE,
  63. "" /* SMUX has no interface. */
  64. };
  65. /* thread master */
  66. static struct thread_master *master;
  67. void *
  68. oid_copy (void *dest, const void *src, size_t size)
  69. {
  70. return memcpy (dest, src, size * sizeof (oid));
  71. }
  72. void
  73. oid2in_addr (oid oid[], int len, struct in_addr *addr)
  74. {
  75. int i;
  76. u_char *pnt;
  77. if (len == 0)
  78. return;
  79. pnt = (u_char *) addr;
  80. for (i = 0; i < len; i++)
  81. *pnt++ = oid[i];
  82. }
  83. void
  84. oid_copy_addr (oid oid[], struct in_addr *addr, int len)
  85. {
  86. int i;
  87. u_char *pnt;
  88. if (len == 0)
  89. return;
  90. pnt = (u_char *) addr;
  91. for (i = 0; i < len; i++)
  92. oid[i] = *pnt++;
  93. }
  94. int
  95. oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
  96. {
  97. int i;
  98. for (i = 0; i < min (o1_len, o2_len); i++)
  99. {
  100. if (o1[i] < o2[i])
  101. return -1;
  102. else if (o1[i] > o2[i])
  103. return 1;
  104. }
  105. if (o1_len < o2_len)
  106. return -1;
  107. if (o1_len > o2_len)
  108. return 1;
  109. return 0;
  110. }
  111. static int
  112. oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
  113. {
  114. int i;
  115. for (i = 0; i < min (o1_len, o2_len); i++)
  116. {
  117. if (o1[i] < o2[i])
  118. return -1;
  119. else if (o1[i] > o2[i])
  120. return 1;
  121. }
  122. if (o1_len < o2_len)
  123. return -1;
  124. return 0;
  125. }
  126. static void
  127. smux_oid_dump (const char *prefix, const oid *oid, size_t oid_len)
  128. {
  129. unsigned int i;
  130. int first = 1;
  131. char buf[MAX_OID_LEN * 3];
  132. buf[0] = '\0';
  133. for (i = 0; i < oid_len; i++)
  134. {
  135. sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
  136. first = 0;
  137. }
  138. zlog_debug ("%s: %s", prefix, buf);
  139. }
  140. static int
  141. smux_socket (void)
  142. {
  143. int ret;
  144. #ifdef HAVE_IPV6
  145. struct addrinfo hints, *res0, *res;
  146. int gai;
  147. #else
  148. struct sockaddr_in serv;
  149. struct servent *sp;
  150. #endif
  151. int sock = 0;
  152. #ifdef HAVE_IPV6
  153. memset(&hints, 0, sizeof(hints));
  154. hints.ai_family = PF_UNSPEC;
  155. hints.ai_socktype = SOCK_STREAM;
  156. gai = getaddrinfo(NULL, "smux", &hints, &res0);
  157. if (gai == EAI_SERVICE)
  158. {
  159. char servbuf[NI_MAXSERV];
  160. sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
  161. servbuf[sizeof (servbuf) - 1] = '\0';
  162. gai = getaddrinfo(NULL, servbuf, &hints, &res0);
  163. }
  164. if (gai)
  165. {
  166. zlog_warn("Cannot locate loopback service smux");
  167. return -1;
  168. }
  169. for(res=res0; res; res=res->ai_next)
  170. {
  171. if (res->ai_family != AF_INET
  172. #ifdef HAVE_IPV6
  173. && res->ai_family != AF_INET6
  174. #endif /* HAVE_IPV6 */
  175. )
  176. continue;
  177. sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  178. if (sock < 0)
  179. continue;
  180. sockopt_reuseaddr (sock);
  181. sockopt_reuseport (sock);
  182. ret = connect (sock, res->ai_addr, res->ai_addrlen);
  183. if (ret < 0)
  184. {
  185. close(sock);
  186. sock = -1;
  187. continue;
  188. }
  189. break;
  190. }
  191. freeaddrinfo(res0);
  192. if (sock < 0)
  193. zlog_warn ("Can't connect to SNMP agent with SMUX");
  194. #else
  195. sock = socket (AF_INET, SOCK_STREAM, 0);
  196. if (sock < 0)
  197. {
  198. zlog_warn ("Can't make socket for SNMP");
  199. return -1;
  200. }
  201. memset (&serv, 0, sizeof (struct sockaddr_in));
  202. serv.sin_family = AF_INET;
  203. #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  204. serv.sin_len = sizeof (struct sockaddr_in);
  205. #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
  206. sp = getservbyname ("smux", "tcp");
  207. if (sp != NULL)
  208. serv.sin_port = sp->s_port;
  209. else
  210. serv.sin_port = htons (SMUX_PORT_DEFAULT);
  211. serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
  212. sockopt_reuseaddr (sock);
  213. sockopt_reuseport (sock);
  214. ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
  215. if (ret < 0)
  216. {
  217. close (sock);
  218. smux_sock = -1;
  219. zlog_warn ("Can't connect to SNMP agent with SMUX");
  220. return -1;
  221. }
  222. #endif
  223. return sock;
  224. }
  225. static void
  226. smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
  227. long errindex, u_char val_type, void *arg, size_t arg_len)
  228. {
  229. int ret;
  230. u_char buf[BUFSIZ];
  231. u_char *ptr, *h1, *h1e, *h2, *h2e;
  232. size_t len, length;
  233. ptr = buf;
  234. len = BUFSIZ;
  235. length = len;
  236. if (debug_smux)
  237. {
  238. zlog_debug ("SMUX GETRSP send");
  239. zlog_debug ("SMUX GETRSP reqid: %ld", reqid);
  240. }
  241. h1 = ptr;
  242. /* Place holder h1 for complete sequence */
  243. ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
  244. h1e = ptr;
  245. ptr = asn_build_int (ptr, &len,
  246. (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  247. &reqid, sizeof (reqid));
  248. if (debug_smux)
  249. zlog_debug ("SMUX GETRSP errstat: %ld", errstat);
  250. ptr = asn_build_int (ptr, &len,
  251. (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  252. &errstat, sizeof (errstat));
  253. if (debug_smux)
  254. zlog_debug ("SMUX GETRSP errindex: %ld", errindex);
  255. ptr = asn_build_int (ptr, &len,
  256. (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  257. &errindex, sizeof (errindex));
  258. h2 = ptr;
  259. /* Place holder h2 for one variable */
  260. ptr = asn_build_sequence (ptr, &len,
  261. (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
  262. 0);
  263. h2e = ptr;
  264. ptr = snmp_build_var_op (ptr, objid, &objid_len,
  265. val_type, arg_len, arg, &len);
  266. /* Now variable size is known, fill in size */
  267. asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
  268. /* Fill in size of whole sequence */
  269. asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
  270. if (debug_smux)
  271. zlog_debug ("SMUX getresp send: %td", (ptr - buf));
  272. ret = send (smux_sock, buf, (ptr - buf), 0);
  273. }
  274. static u_char *
  275. smux_var (u_char *ptr, size_t len, oid objid[], size_t *objid_len,
  276. size_t *var_val_len,
  277. u_char *var_val_type,
  278. void **var_value)
  279. {
  280. u_char type;
  281. u_char val_type;
  282. size_t val_len;
  283. u_char *val;
  284. if (debug_smux)
  285. zlog_debug ("SMUX var parse: len %zd", len);
  286. /* Parse header. */
  287. ptr = asn_parse_header (ptr, &len, &type);
  288. if (debug_smux)
  289. {
  290. zlog_debug ("SMUX var parse: type %d len %zd", type, len);
  291. zlog_debug ("SMUX var parse: type must be %d",
  292. (ASN_SEQUENCE | ASN_CONSTRUCTOR));
  293. }
  294. /* Parse var option. */
  295. *objid_len = MAX_OID_LEN;
  296. ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
  297. &val_len, &val, &len);
  298. if (var_val_len)
  299. *var_val_len = val_len;
  300. if (var_value)
  301. *var_value = (void*) val;
  302. if (var_val_type)
  303. *var_val_type = val_type;
  304. /* Requested object id length is objid_len. */
  305. if (debug_smux)
  306. smux_oid_dump ("Request OID", objid, *objid_len);
  307. if (debug_smux)
  308. zlog_debug ("SMUX val_type: %d", val_type);
  309. /* Check request value type. */
  310. if (debug_smux)
  311. switch (val_type)
  312. {
  313. case ASN_NULL:
  314. /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
  315. ASN_NULL. */
  316. zlog_debug ("ASN_NULL");
  317. break;
  318. case ASN_INTEGER:
  319. zlog_debug ("ASN_INTEGER");
  320. break;
  321. case ASN_COUNTER:
  322. case ASN_GAUGE:
  323. case ASN_TIMETICKS:
  324. case ASN_UINTEGER:
  325. zlog_debug ("ASN_COUNTER");
  326. break;
  327. case ASN_COUNTER64:
  328. zlog_debug ("ASN_COUNTER64");
  329. break;
  330. case ASN_IPADDRESS:
  331. zlog_debug ("ASN_IPADDRESS");
  332. break;
  333. case ASN_OCTET_STR:
  334. zlog_debug ("ASN_OCTET_STR");
  335. break;
  336. case ASN_OPAQUE:
  337. case ASN_NSAP:
  338. case ASN_OBJECT_ID:
  339. zlog_debug ("ASN_OPAQUE");
  340. break;
  341. case SNMP_NOSUCHOBJECT:
  342. zlog_debug ("SNMP_NOSUCHOBJECT");
  343. break;
  344. case SNMP_NOSUCHINSTANCE:
  345. zlog_debug ("SNMP_NOSUCHINSTANCE");
  346. break;
  347. case SNMP_ENDOFMIBVIEW:
  348. zlog_debug ("SNMP_ENDOFMIBVIEW");
  349. break;
  350. case ASN_BIT_STR:
  351. zlog_debug ("ASN_BIT_STR");
  352. break;
  353. default:
  354. zlog_debug ("Unknown type");
  355. break;
  356. }
  357. return ptr;
  358. }
  359. /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
  360. ucd-snmp smux and as such suppose, that the peer receives in the message
  361. only one variable. Fortunately, IBM seems to do the same in AIX. */
  362. static int
  363. smux_set (oid *reqid, size_t *reqid_len,
  364. u_char val_type, void *val, size_t val_len, int action)
  365. {
  366. int j;
  367. struct subtree *subtree;
  368. struct variable *v;
  369. int subresult;
  370. oid *suffix;
  371. size_t suffix_len;
  372. int result;
  373. u_char *statP = NULL;
  374. WriteMethod *write_method = NULL;
  375. struct listnode *node, *nnode;
  376. /* Check */
  377. for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
  378. {
  379. subresult = oid_compare_part (reqid, *reqid_len,
  380. subtree->name, subtree->name_len);
  381. /* Subtree matched. */
  382. if (subresult == 0)
  383. {
  384. /* Prepare suffix. */
  385. suffix = reqid + subtree->name_len;
  386. suffix_len = *reqid_len - subtree->name_len;
  387. result = subresult;
  388. /* Check variables. */
  389. for (j = 0; j < subtree->variables_num; j++)
  390. {
  391. v = &subtree->variables[j];
  392. /* Always check suffix */
  393. result = oid_compare_part (suffix, suffix_len,
  394. v->name, v->namelen);
  395. /* This is exact match so result must be zero. */
  396. if (result == 0)
  397. {
  398. if (debug_smux)
  399. zlog_debug ("SMUX function call index is %d", v->magic);
  400. statP = (*v->findVar) (v, suffix, &suffix_len, 1,
  401. &val_len, &write_method);
  402. if (write_method)
  403. {
  404. return (*write_method)(action, val, val_type, val_len,
  405. statP, suffix, suffix_len, v);
  406. }
  407. else
  408. {
  409. return SNMP_ERR_READONLY;
  410. }
  411. }
  412. /* If above execution is failed or oid is small (so
  413. there is no further match). */
  414. if (result < 0)
  415. return SNMP_ERR_NOSUCHNAME;
  416. }
  417. }
  418. }
  419. return SNMP_ERR_NOSUCHNAME;
  420. }
  421. static int
  422. smux_get (oid *reqid, size_t *reqid_len, int exact,
  423. u_char *val_type,void **val, size_t *val_len)
  424. {
  425. int j;
  426. struct subtree *subtree;
  427. struct variable *v;
  428. int subresult;
  429. oid *suffix;
  430. size_t suffix_len;
  431. int result;
  432. WriteMethod *write_method=NULL;
  433. struct listnode *node, *nnode;
  434. /* Check */
  435. for (ALL_LIST_ELEMENTS (treelist, node, nnode,subtree))
  436. {
  437. subresult = oid_compare_part (reqid, *reqid_len,
  438. subtree->name, subtree->name_len);
  439. /* Subtree matched. */
  440. if (subresult == 0)
  441. {
  442. /* Prepare suffix. */
  443. suffix = reqid + subtree->name_len;
  444. suffix_len = *reqid_len - subtree->name_len;
  445. result = subresult;
  446. /* Check variables. */
  447. for (j = 0; j < subtree->variables_num; j++)
  448. {
  449. v = &subtree->variables[j];
  450. /* Always check suffix */
  451. result = oid_compare_part (suffix, suffix_len,
  452. v->name, v->namelen);
  453. /* This is exact match so result must be zero. */
  454. if (result == 0)
  455. {
  456. if (debug_smux)
  457. zlog_debug ("SMUX function call index is %d", v->magic);
  458. *val = (*v->findVar) (v, suffix, &suffix_len, exact,
  459. val_len, &write_method);
  460. /* There is no instance. */
  461. if (*val == NULL)
  462. return SNMP_NOSUCHINSTANCE;
  463. /* Call is suceed. */
  464. *val_type = v->type;
  465. return 0;
  466. }
  467. /* If above execution is failed or oid is small (so
  468. there is no further match). */
  469. if (result < 0)
  470. return SNMP_ERR_NOSUCHNAME;
  471. }
  472. }
  473. }
  474. return SNMP_ERR_NOSUCHNAME;
  475. }
  476. static int
  477. smux_getnext (oid *reqid, size_t *reqid_len, int exact,
  478. u_char *val_type,void **val, size_t *val_len)
  479. {
  480. int j;
  481. oid save[MAX_OID_LEN];
  482. int savelen = 0;
  483. struct subtree *subtree;
  484. struct variable *v;
  485. int subresult;
  486. oid *suffix;
  487. size_t suffix_len;
  488. int result;
  489. WriteMethod *write_method=NULL;
  490. struct listnode *node, *nnode;
  491. /* Save incoming request. */
  492. oid_copy (save, reqid, *reqid_len);
  493. savelen = *reqid_len;
  494. /* Check */
  495. for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
  496. {
  497. subresult = oid_compare_part (reqid, *reqid_len,
  498. subtree->name, subtree->name_len);
  499. /* If request is in the tree. The agent has to make sure we
  500. only receive requests we have registered for. */
  501. /* Unfortunately, that's not true. In fact, a SMUX subagent has to
  502. behave as if it manages the whole SNMP MIB tree itself. It's the
  503. duty of the master agent to collect the best answer and return it
  504. to the manager. See RFC 1227 chapter 3.1.6 for the glory details
  505. :-). ucd-snmp really behaves bad here as it actually might ask
  506. multiple times for the same GETNEXT request as it throws away the
  507. answer when it expects it in a different subtree and might come
  508. back later with the very same request. --jochen */
  509. if (subresult <= 0)
  510. {
  511. /* Prepare suffix. */
  512. suffix = reqid + subtree->name_len;
  513. suffix_len = *reqid_len - subtree->name_len;
  514. if (subresult < 0)
  515. {
  516. oid_copy(reqid, subtree->name, subtree->name_len);
  517. *reqid_len = subtree->name_len;
  518. }
  519. for (j = 0; j < subtree->variables_num; j++)
  520. {
  521. result = subresult;
  522. v = &subtree->variables[j];
  523. /* Next then check result >= 0. */
  524. if (result == 0)
  525. result = oid_compare_part (suffix, suffix_len,
  526. v->name, v->namelen);
  527. if (result <= 0)
  528. {
  529. if (debug_smux)
  530. zlog_debug ("SMUX function call index is %d", v->magic);
  531. if(result<0)
  532. {
  533. oid_copy(suffix, v->name, v->namelen);
  534. suffix_len = v->namelen;
  535. }
  536. *val = (*v->findVar) (v, suffix, &suffix_len, exact,
  537. val_len, &write_method);
  538. *reqid_len = suffix_len + subtree->name_len;
  539. if (*val)
  540. {
  541. *val_type = v->type;
  542. return 0;
  543. }
  544. }
  545. }
  546. }
  547. }
  548. memcpy (reqid, save, savelen * sizeof(oid));
  549. *reqid_len = savelen;
  550. return SNMP_ERR_NOSUCHNAME;
  551. }
  552. /* GET message header. */
  553. static u_char *
  554. smux_parse_get_header (u_char *ptr, size_t *len, long *reqid)
  555. {
  556. u_char type;
  557. long errstat;
  558. long errindex;
  559. /* Request ID. */
  560. ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
  561. if (debug_smux)
  562. zlog_debug ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
  563. /* Error status. */
  564. ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
  565. if (debug_smux)
  566. zlog_debug ("SMUX GET errstat %ld len: %zd", errstat, *len);
  567. /* Error index. */
  568. ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
  569. if (debug_smux)
  570. zlog_debug ("SMUX GET errindex %ld len: %zd", errindex, *len);
  571. return ptr;
  572. }
  573. static void
  574. smux_parse_set (u_char *ptr, size_t len, int action)
  575. {
  576. long reqid;
  577. oid oid[MAX_OID_LEN];
  578. size_t oid_len;
  579. u_char val_type;
  580. void *val;
  581. size_t val_len;
  582. int ret;
  583. if (debug_smux)
  584. zlog_debug ("SMUX SET(%s) message parse: len %zd",
  585. (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
  586. len);
  587. /* Parse SET message header. */
  588. ptr = smux_parse_get_header (ptr, &len, &reqid);
  589. /* Parse SET message object ID. */
  590. ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
  591. ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
  592. if (debug_smux)
  593. zlog_debug ("SMUX SET ret %d", ret);
  594. /* Return result. */
  595. if (RESERVE1 == action)
  596. smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
  597. }
  598. static void
  599. smux_parse_get (u_char *ptr, size_t len, int exact)
  600. {
  601. long reqid;
  602. oid oid[MAX_OID_LEN];
  603. size_t oid_len;
  604. u_char val_type;
  605. void *val;
  606. size_t val_len;
  607. int ret;
  608. if (debug_smux)
  609. zlog_debug ("SMUX GET message parse: len %zd", len);
  610. /* Parse GET message header. */
  611. ptr = smux_parse_get_header (ptr, &len, &reqid);
  612. /* Parse GET message object ID. We needn't the value come */
  613. ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
  614. /* Traditional getstatptr. */
  615. if (exact)
  616. ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
  617. else
  618. ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
  619. /* Return result. */
  620. if (ret == 0)
  621. smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
  622. else
  623. smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
  624. }
  625. /* Parse SMUX_CLOSE message. */
  626. static void
  627. smux_parse_close (u_char *ptr, int len)
  628. {
  629. long reason = 0;
  630. while (len--)
  631. {
  632. reason = (reason << 8) | (long) *ptr;
  633. ptr++;
  634. }
  635. zlog_info ("SMUX_CLOSE with reason: %ld", reason);
  636. }
  637. /* SMUX_RRSP message. */
  638. static void
  639. smux_parse_rrsp (u_char *ptr, size_t len)
  640. {
  641. u_char val;
  642. long errstat;
  643. ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
  644. if (debug_smux)
  645. zlog_debug ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
  646. }
  647. /* Parse SMUX message. */
  648. static int
  649. smux_parse (u_char *ptr, size_t len)
  650. {
  651. /* This buffer we'll use for SOUT message. We could allocate it with
  652. malloc and save only static pointer/lenght, but IMHO static
  653. buffer is a faster solusion. */
  654. static u_char sout_save_buff[SMUXMAXPKTSIZE];
  655. static int sout_save_len = 0;
  656. int len_income = len; /* see note below: YYY */
  657. u_char type;
  658. u_char rollback;
  659. rollback = ptr[2]; /* important only for SMUX_SOUT */
  660. process_rest: /* see note below: YYY */
  661. /* Parse SMUX message type and subsequent length. */
  662. ptr = asn_parse_header (ptr, &len, &type);
  663. if (debug_smux)
  664. zlog_debug ("SMUX message received type: %d rest len: %zd", type, len);
  665. switch (type)
  666. {
  667. case SMUX_OPEN:
  668. /* Open must be not send from SNMP agent. */
  669. zlog_warn ("SMUX_OPEN received: resetting connection.");
  670. return -1;
  671. break;
  672. case SMUX_RREQ:
  673. /* SMUX_RREQ message is invalid for us. */
  674. zlog_warn ("SMUX_RREQ received: resetting connection.");
  675. return -1;
  676. break;
  677. case SMUX_SOUT:
  678. /* SMUX_SOUT message is now valied for us. */
  679. if (debug_smux)
  680. zlog_debug ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
  681. if (sout_save_len > 0)
  682. {
  683. smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
  684. sout_save_len = 0;
  685. }
  686. else
  687. zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
  688. if (len_income > 3)
  689. {
  690. /* YYY: this strange code has to solve the "slow peer"
  691. problem: When agent sends SMUX_SOUT message it doesn't
  692. wait any responce and may send some next message to
  693. subagent. Then the peer in 'smux_read()' will recieve
  694. from socket the 'concatenated' buffer, contaning both
  695. SMUX_SOUT message and the next one
  696. (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
  697. the buffer is longer than 3 ( length of SMUX_SOUT ), we
  698. must process the rest of it. This effect may be observed
  699. if 'debug_smux' is set to '1' */
  700. ptr++;
  701. len = len_income - 3;
  702. goto process_rest;
  703. }
  704. break;
  705. case SMUX_GETRSP:
  706. /* SMUX_GETRSP message is invalid for us. */
  707. zlog_warn ("SMUX_GETRSP received: resetting connection.");
  708. return -1;
  709. break;
  710. case SMUX_CLOSE:
  711. /* Close SMUX connection. */
  712. if (debug_smux)
  713. zlog_debug ("SMUX_CLOSE");
  714. smux_parse_close (ptr, len);
  715. return -1;
  716. break;
  717. case SMUX_RRSP:
  718. /* This is response for register message. */
  719. if (debug_smux)
  720. zlog_debug ("SMUX_RRSP");
  721. smux_parse_rrsp (ptr, len);
  722. break;
  723. case SMUX_GET:
  724. /* Exact request for object id. */
  725. if (debug_smux)
  726. zlog_debug ("SMUX_GET");
  727. smux_parse_get (ptr, len, 1);
  728. break;
  729. case SMUX_GETNEXT:
  730. /* Next request for object id. */
  731. if (debug_smux)
  732. zlog_debug ("SMUX_GETNEXT");
  733. smux_parse_get (ptr, len, 0);
  734. break;
  735. case SMUX_SET:
  736. /* SMUX_SET is supported with some limitations. */
  737. if (debug_smux)
  738. zlog_debug ("SMUX_SET");
  739. /* save the data for future SMUX_SOUT */
  740. memcpy (sout_save_buff, ptr, len);
  741. sout_save_len = len;
  742. smux_parse_set (ptr, len, RESERVE1);
  743. break;
  744. default:
  745. zlog_info ("Unknown type: %d", type);
  746. break;
  747. }
  748. return 0;
  749. }
  750. /* SMUX message read function. */
  751. static int
  752. smux_read (struct thread *t)
  753. {
  754. int sock;
  755. int len;
  756. u_char buf[SMUXMAXPKTSIZE];
  757. int ret;
  758. /* Clear thread. */
  759. sock = THREAD_FD (t);
  760. smux_read_thread = NULL;
  761. if (debug_smux)
  762. zlog_debug ("SMUX read start");
  763. /* Read message from SMUX socket. */
  764. len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
  765. if (len < 0)
  766. {
  767. zlog_warn ("Can't read all SMUX packet: %s", safe_strerror (errno));
  768. close (sock);
  769. smux_sock = -1;
  770. smux_event (SMUX_CONNECT, 0);
  771. return -1;
  772. }
  773. if (len == 0)
  774. {
  775. zlog_warn ("SMUX connection closed: %d", sock);
  776. close (sock);
  777. smux_sock = -1;
  778. smux_event (SMUX_CONNECT, 0);
  779. return -1;
  780. }
  781. if (debug_smux)
  782. zlog_debug ("SMUX read len: %d", len);
  783. /* Parse the message. */
  784. ret = smux_parse (buf, len);
  785. if (ret < 0)
  786. {
  787. close (sock);
  788. smux_sock = -1;
  789. smux_event (SMUX_CONNECT, 0);
  790. return -1;
  791. }
  792. /* Regiser read thread. */
  793. smux_event (SMUX_READ, sock);
  794. return 0;
  795. }
  796. static int
  797. smux_open (int sock)
  798. {
  799. u_char buf[BUFSIZ];
  800. u_char *ptr;
  801. size_t len;
  802. long version;
  803. u_char progname[] = QUAGGA_PROGNAME "-" QUAGGA_VERSION;
  804. if (debug_smux)
  805. {
  806. smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
  807. zlog_debug ("SMUX open progname: %s", progname);
  808. zlog_debug ("SMUX open password: %s", smux_passwd);
  809. }
  810. ptr = buf;
  811. len = BUFSIZ;
  812. /* SMUX Header. As placeholder. */
  813. ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
  814. /* SMUX Open. */
  815. version = 0;
  816. ptr = asn_build_int (ptr, &len,
  817. (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  818. &version, sizeof (version));
  819. /* SMUX connection oid. */
  820. ptr = asn_build_objid (ptr, &len,
  821. (u_char)
  822. (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
  823. smux_oid, smux_oid_len);
  824. /* SMUX connection description. */
  825. ptr = asn_build_string (ptr, &len,
  826. (u_char)
  827. (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
  828. progname, strlen (progname));
  829. /* SMUX connection password. */
  830. ptr = asn_build_string (ptr, &len,
  831. (u_char)
  832. (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
  833. (u_char *)smux_passwd, strlen (smux_passwd));
  834. /* Fill in real SMUX header. We exclude ASN header size (2). */
  835. len = BUFSIZ;
  836. asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
  837. return send (sock, buf, (ptr - buf), 0);
  838. }
  839. int
  840. smux_trap (const oid *name, size_t namelen,
  841. const oid *iname, size_t inamelen,
  842. const struct trap_object *trapobj, size_t trapobjlen,
  843. unsigned int tick, u_char sptrap)
  844. {
  845. unsigned int i;
  846. u_char buf[BUFSIZ];
  847. u_char *ptr;
  848. size_t len, length;
  849. struct in_addr addr;
  850. unsigned long val;
  851. u_char *h1, *h1e;
  852. ptr = buf;
  853. len = BUFSIZ;
  854. length = len;
  855. /* When SMUX connection is not established. */
  856. if (smux_sock < 0)
  857. return 0;
  858. /* SMUX header. */
  859. ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
  860. /* Sub agent enterprise oid. */
  861. ptr = asn_build_objid (ptr, &len,
  862. (u_char)
  863. (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
  864. smux_oid, smux_oid_len);
  865. /* IP address. */
  866. addr.s_addr = 0;
  867. ptr = asn_build_string (ptr, &len,
  868. (u_char)
  869. (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
  870. (u_char *)&addr, sizeof (addr));
  871. /* Generic trap integer. */
  872. val = SNMP_TRAP_ENTERPRISESPECIFIC;
  873. ptr = asn_build_int (ptr, &len,
  874. (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  875. (long *)&val, sizeof (val));
  876. /* Specific trap integer. */
  877. val = sptrap;
  878. ptr = asn_build_int (ptr, &len,
  879. (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  880. (long *)&val, sizeof (val));
  881. /* Timeticks timestamp. */
  882. val = 0;
  883. ptr = asn_build_unsigned_int (ptr, &len,
  884. (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS),
  885. &val, sizeof (val));
  886. /* Variables. */
  887. h1 = ptr;
  888. ptr = asn_build_sequence (ptr, &len,
  889. (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
  890. 0);
  891. /* Iteration for each objects. */
  892. h1e = ptr;
  893. for (i = 0; i < trapobjlen; i++)
  894. {
  895. int ret;
  896. oid oid[MAX_OID_LEN];
  897. size_t oid_len;
  898. void *val;
  899. size_t val_len;
  900. u_char val_type;
  901. /* Make OID. */
  902. if (trapobj[i].namelen > 0)
  903. {
  904. oid_copy (oid, name, namelen);
  905. oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen);
  906. oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen);
  907. oid_len = namelen + trapobj[i].namelen + inamelen;
  908. }
  909. else
  910. {
  911. oid_copy (oid, name, namelen);
  912. oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen * (-1));
  913. oid_len = namelen + trapobj[i].namelen * (-1) ;
  914. }
  915. if (debug_smux)
  916. {
  917. smux_oid_dump ("Trap", name, namelen);
  918. if (trapobj[i].namelen < 0)
  919. smux_oid_dump ("Trap",
  920. trapobj[i].name, (- 1) * (trapobj[i].namelen));
  921. else
  922. {
  923. smux_oid_dump ("Trap", trapobj[i].name, (trapobj[i].namelen));
  924. smux_oid_dump ("Trap", iname, inamelen);
  925. }
  926. smux_oid_dump ("Trap", oid, oid_len);
  927. zlog_info ("BUFSIZ: %d // oid_len: %lu", BUFSIZ, (u_long)oid_len);
  928. }
  929. ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
  930. if (debug_smux)
  931. zlog_debug ("smux_get result %d", ret);
  932. if (ret == 0)
  933. ptr = snmp_build_var_op (ptr, oid, &oid_len,
  934. val_type, val_len, val, &len);
  935. }
  936. /* Now variable size is known, fill in size */
  937. asn_build_sequence(h1, &length,
  938. (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
  939. ptr - h1e);
  940. /* Fill in size of whole sequence */
  941. len = BUFSIZ;
  942. asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
  943. return send (smux_sock, buf, (ptr - buf), 0);
  944. }
  945. static int
  946. smux_register (int sock)
  947. {
  948. u_char buf[BUFSIZ];
  949. u_char *ptr;
  950. int ret;
  951. size_t len;
  952. long priority;
  953. long operation;
  954. struct subtree *subtree;
  955. struct listnode *node, *nnode;
  956. ret = 0;
  957. for (ALL_LIST_ELEMENTS (treelist, node, nnode, subtree))
  958. {
  959. ptr = buf;
  960. len = BUFSIZ;
  961. /* SMUX RReq Header. */
  962. ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
  963. /* Register MIB tree. */
  964. ptr = asn_build_objid (ptr, &len,
  965. (u_char)
  966. (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
  967. subtree->name, subtree->name_len);
  968. /* Priority. */
  969. priority = -1;
  970. ptr = asn_build_int (ptr, &len,
  971. (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  972. &priority, sizeof (priority));
  973. /* Operation. */
  974. operation = 2; /* Register R/W */
  975. ptr = asn_build_int (ptr, &len,
  976. (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
  977. &operation, sizeof (operation));
  978. if (debug_smux)
  979. {
  980. smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
  981. zlog_debug ("SMUX register priority: %ld", priority);
  982. zlog_debug ("SMUX register operation: %ld", operation);
  983. }
  984. len = BUFSIZ;
  985. asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
  986. ret = send (sock, buf, (ptr - buf), 0);
  987. if (ret < 0)
  988. return ret;
  989. }
  990. return ret;
  991. }
  992. /* Try to connect to SNMP agent. */
  993. static int
  994. smux_connect (struct thread *t)
  995. {
  996. int ret;
  997. if (debug_smux)
  998. zlog_debug ("SMUX connect try %d", fail + 1);
  999. /* Clear thread poner of myself. */
  1000. smux_connect_thread = NULL;
  1001. /* Make socket. Try to connect. */
  1002. smux_sock = smux_socket ();
  1003. if (smux_sock < 0)
  1004. {
  1005. if (++fail < SMUX_MAX_FAILURE)
  1006. smux_event (SMUX_CONNECT, 0);
  1007. return 0;
  1008. }
  1009. /* Send OPEN PDU. */
  1010. ret = smux_open (smux_sock);
  1011. if (ret < 0)
  1012. {
  1013. zlog_warn ("SMUX open message send failed: %s", safe_strerror (errno));
  1014. close (smux_sock);
  1015. smux_sock = -1;
  1016. if (++fail < SMUX_MAX_FAILURE)
  1017. smux_event (SMUX_CONNECT, 0);
  1018. return -1;
  1019. }
  1020. /* Send any outstanding register PDUs. */
  1021. ret = smux_register (smux_sock);
  1022. if (ret < 0)
  1023. {
  1024. zlog_warn ("SMUX register message send failed: %s", safe_strerror (errno));
  1025. close (smux_sock);
  1026. smux_sock = -1;
  1027. if (++fail < SMUX_MAX_FAILURE)
  1028. smux_event (SMUX_CONNECT, 0);
  1029. return -1;
  1030. }
  1031. /* Everything goes fine. */
  1032. smux_event (SMUX_READ, smux_sock);
  1033. return 0;
  1034. }
  1035. /* Clear all SMUX related resources. */
  1036. static void
  1037. smux_stop (void)
  1038. {
  1039. if (smux_read_thread)
  1040. {
  1041. thread_cancel (smux_read_thread);
  1042. smux_read_thread = NULL;
  1043. }
  1044. if (smux_connect_thread)
  1045. {
  1046. thread_cancel (smux_connect_thread);
  1047. smux_connect_thread = NULL;
  1048. }
  1049. if (smux_sock >= 0)
  1050. {
  1051. close (smux_sock);
  1052. smux_sock = -1;
  1053. }
  1054. }
  1055. void
  1056. smux_event (enum smux_event event, int sock)
  1057. {
  1058. switch (event)
  1059. {
  1060. case SMUX_SCHEDULE:
  1061. smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
  1062. break;
  1063. case SMUX_CONNECT:
  1064. smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
  1065. break;
  1066. case SMUX_READ:
  1067. smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
  1068. break;
  1069. default:
  1070. break;
  1071. }
  1072. }
  1073. static int
  1074. smux_str2oid (const char *str, oid *oid, size_t *oid_len)
  1075. {
  1076. int len;
  1077. int val;
  1078. len = 0;
  1079. val = 0;
  1080. *oid_len = 0;
  1081. if (*str == '.')
  1082. str++;
  1083. if (*str == '\0')
  1084. return 0;
  1085. while (1)
  1086. {
  1087. if (! isdigit (*str))
  1088. return -1;
  1089. while (isdigit (*str))
  1090. {
  1091. val *= 10;
  1092. val += (*str - '0');
  1093. str++;
  1094. }
  1095. if (*str == '\0')
  1096. break;
  1097. if (*str != '.')
  1098. return -1;
  1099. oid[len++] = val;
  1100. val = 0;
  1101. str++;
  1102. }
  1103. oid[len++] = val;
  1104. *oid_len = len;
  1105. return 0;
  1106. }
  1107. static oid *
  1108. smux_oid_dup (oid *objid, size_t objid_len)
  1109. {
  1110. oid *new;
  1111. new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
  1112. oid_copy (new, objid, objid_len);
  1113. return new;
  1114. }
  1115. static int
  1116. smux_peer_oid (struct vty *vty, const char *oid_str, const char *passwd_str)
  1117. {
  1118. int ret;
  1119. oid oid[MAX_OID_LEN];
  1120. size_t oid_len;
  1121. ret = smux_str2oid (oid_str, oid, &oid_len);
  1122. if (ret != 0)
  1123. {
  1124. vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
  1125. return CMD_WARNING;
  1126. }
  1127. if (smux_oid)
  1128. {
  1129. free (smux_oid);
  1130. smux_oid = NULL;
  1131. }
  1132. /* careful, smux_passwd might point to string constant */
  1133. if (smux_passwd)
  1134. {
  1135. free (smux_passwd);
  1136. smux_passwd = NULL;
  1137. }
  1138. smux_oid = smux_oid_dup (oid, oid_len);
  1139. smux_oid_len = oid_len;
  1140. if (passwd_str)
  1141. smux_passwd = strdup (passwd_str);
  1142. else
  1143. smux_passwd = strdup ("");
  1144. return 0;
  1145. }
  1146. int
  1147. smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
  1148. size_t *var_len, WriteMethod **write_method)
  1149. {
  1150. oid fulloid[MAX_OID_LEN];
  1151. int ret;
  1152. oid_copy (fulloid, v->name, v->namelen);
  1153. fulloid[v->namelen] = 0;
  1154. /* Check against full instance. */
  1155. ret = oid_compare (name, *length, fulloid, v->namelen + 1);
  1156. /* Check single instance. */
  1157. if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
  1158. return MATCH_FAILED;
  1159. /* In case of getnext, fill in full instance. */
  1160. memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
  1161. *length = v->namelen + 1;
  1162. *write_method = 0;
  1163. *var_len = sizeof(long); /* default to 'long' results */
  1164. return MATCH_SUCCEEDED;
  1165. }
  1166. static int
  1167. smux_peer_default (void)
  1168. {
  1169. if (smux_oid)
  1170. {
  1171. free (smux_oid);
  1172. smux_oid = NULL;
  1173. }
  1174. /* careful, smux_passwd might be pointing at string constant */
  1175. if (smux_passwd)
  1176. {
  1177. free (smux_passwd);
  1178. smux_passwd = NULL;
  1179. }
  1180. return CMD_SUCCESS;
  1181. }
  1182. DEFUN (smux_peer,
  1183. smux_peer_cmd,
  1184. "smux peer OID",
  1185. "SNMP MUX protocol settings\n"
  1186. "SNMP MUX peer settings\n"
  1187. "Object ID used in SMUX peering\n")
  1188. {
  1189. if (smux_peer_oid (vty, argv[0], NULL) == 0)
  1190. {
  1191. smux_start();
  1192. return CMD_SUCCESS;
  1193. }
  1194. else
  1195. return CMD_WARNING;
  1196. }
  1197. DEFUN (smux_peer_password,
  1198. smux_peer_password_cmd,
  1199. "smux peer OID PASSWORD",
  1200. "SNMP MUX protocol settings\n"
  1201. "SNMP MUX peer settings\n"
  1202. "SMUX peering object ID\n"
  1203. "SMUX peering password\n")
  1204. {
  1205. if (smux_peer_oid (vty, argv[0], argv[1]) == 0)
  1206. {
  1207. smux_start();
  1208. return CMD_SUCCESS;
  1209. }
  1210. else
  1211. return CMD_WARNING;
  1212. }
  1213. DEFUN (no_smux_peer,
  1214. no_smux_peer_cmd,
  1215. "no smux peer",
  1216. NO_STR
  1217. "SNMP MUX protocol settings\n"
  1218. "SNMP MUX peer settings\n")
  1219. {
  1220. smux_stop();
  1221. return smux_peer_default ();
  1222. }
  1223. ALIAS (no_smux_peer,
  1224. no_smux_peer_oid_cmd,
  1225. "no smux peer OID",
  1226. NO_STR
  1227. "SNMP MUX protocol settings\n"
  1228. "SNMP MUX peer settings\n"
  1229. "SMUX peering object ID\n")
  1230. ALIAS (no_smux_peer,
  1231. no_smux_peer_oid_password_cmd,
  1232. "no smux peer OID PASSWORD",
  1233. NO_STR
  1234. "SNMP MUX protocol settings\n"
  1235. "SNMP MUX peer settings\n"
  1236. "SMUX peering object ID\n"
  1237. "SMUX peering password\n")
  1238. static int
  1239. config_write_smux (struct vty *vty)
  1240. {
  1241. int first = 1;
  1242. unsigned int i;
  1243. if (smux_oid)
  1244. {
  1245. vty_out (vty, "smux peer ");
  1246. for (i = 0; i < smux_oid_len; i++)
  1247. {
  1248. vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
  1249. first = 0;
  1250. }
  1251. vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
  1252. }
  1253. return 0;
  1254. }
  1255. /* Register subtree to smux master tree. */
  1256. void
  1257. smux_register_mib (const char *descr, struct variable *var,
  1258. size_t width, int num,
  1259. oid name[], size_t namelen)
  1260. {
  1261. struct subtree *tree;
  1262. tree = (struct subtree *)malloc(sizeof(struct subtree));
  1263. oid_copy (tree->name, name, namelen);
  1264. tree->name_len = namelen;
  1265. tree->variables = var;
  1266. tree->variables_num = num;
  1267. tree->variables_width = width;
  1268. tree->registered = 0;
  1269. listnode_add_sort(treelist, tree);
  1270. }
  1271. /* Compare function to keep treelist sorted */
  1272. static int
  1273. smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
  1274. {
  1275. return oid_compare(tree1->name, tree1->name_len,
  1276. tree2->name, tree2->name_len);
  1277. }
  1278. /* Initialize some values then schedule first SMUX connection. */
  1279. void
  1280. smux_init (struct thread_master *tm)
  1281. {
  1282. /* copy callers thread master */
  1283. master = tm;
  1284. /* Make MIB tree. */
  1285. treelist = list_new();
  1286. treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
  1287. /* Install commands. */
  1288. install_node (&smux_node, config_write_smux);
  1289. install_element (CONFIG_NODE, &smux_peer_cmd);
  1290. install_element (CONFIG_NODE, &smux_peer_password_cmd);
  1291. install_element (CONFIG_NODE, &no_smux_peer_cmd);
  1292. install_element (CONFIG_NODE, &no_smux_peer_oid_cmd);
  1293. install_element (CONFIG_NODE, &no_smux_peer_oid_password_cmd);
  1294. }
  1295. void
  1296. smux_start(void)
  1297. {
  1298. /* Close any existing connections. */
  1299. smux_stop();
  1300. /* Schedule first connection. */
  1301. smux_event (SMUX_SCHEDULE, 0);
  1302. }
  1303. #endif /* HAVE_SNMP */