1 /* OSPFv2 SNMP support
2  * Copyright (C) 2005 6WIND <alain.ritoux@6wind.com>
3  * Copyright (C) 2000 IP Infusion Inc.
4  *
5  * Written by Kunihiro Ishiguro <kunihiro@zebra.org>
6  *
7  * This file is part of GNU Zebra.
8  *
9  * GNU Zebra is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2, or (at your option) any
12  * later version.
13  *
14  * GNU Zebra is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; see the file COPYING; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
24 #include <zebra.h>
25 
26 #include <net-snmp/net-snmp-config.h>
27 #include <net-snmp/net-snmp-includes.h>
28 
29 #include "if.h"
30 #include "log.h"
31 #include "prefix.h"
32 #include "table.h"
33 #include "command.h"
34 #include "memory.h"
35 #include "smux.h"
36 #include "libfrr.h"
37 #include "version.h"
38 
39 #include "ospfd/ospfd.h"
40 #include "ospfd/ospf_interface.h"
41 #include "ospfd/ospf_asbr.h"
42 #include "ospfd/ospf_lsa.h"
43 #include "ospfd/ospf_lsdb.h"
44 #include "ospfd/ospf_abr.h"
45 #include "ospfd/ospf_neighbor.h"
46 #include "ospfd/ospf_nsm.h"
47 #include "ospfd/ospf_flood.h"
48 #include "ospfd/ospf_ism.h"
49 #include "ospfd/ospf_dump.h"
50 #include "ospfd/ospf_route.h"
51 #include "ospfd/ospf_zebra.h"
52 
53 /* OSPF2-MIB. */
54 #define OSPF2MIB 1,3,6,1,2,1,14
55 
56 /* OSPF MIB General Group values. */
57 #define OSPFROUTERID                     1
58 #define OSPFADMINSTAT                    2
59 #define OSPFVERSIONNUMBER                3
60 #define OSPFAREABDRRTRSTATUS             4
61 #define OSPFASBDRRTRSTATUS               5
62 #define OSPFEXTERNLSACOUNT               6
63 #define OSPFEXTERNLSACKSUMSUM            7
64 #define OSPFTOSSUPPORT                   8
65 #define OSPFORIGINATENEWLSAS             9
66 #define OSPFRXNEWLSAS                    10
67 #define OSPFEXTLSDBLIMIT                 11
68 #define OSPFMULTICASTEXTENSIONS          12
69 #define OSPFEXITOVERFLOWINTERVAL         13
70 #define OSPFDEMANDEXTENSIONS             14
71 
72 /* OSPF MIB ospfAreaTable. */
73 #define OSPFAREAID                       1
74 #define OSPFAUTHTYPE                     2
75 #define OSPFIMPORTASEXTERN               3
76 #define OSPFSPFRUNS                      4
77 #define OSPFAREABDRRTRCOUNT              5
78 #define OSPFASBDRRTRCOUNT                6
79 #define OSPFAREALSACOUNT                 7
80 #define OSPFAREALSACKSUMSUM              8
81 #define OSPFAREASUMMARY                  9
82 #define OSPFAREASTATUS                   10
83 
84 /* OSPF MIB ospfStubAreaTable. */
85 #define OSPFSTUBAREAID                   1
86 #define OSPFSTUBTOS                      2
87 #define OSPFSTUBMETRIC                   3
88 #define OSPFSTUBSTATUS                   4
89 #define OSPFSTUBMETRICTYPE               5
90 
91 /* OSPF MIB ospfLsdbTable. */
92 #define OSPFLSDBAREAID                   1
93 #define OSPFLSDBTYPE                     2
94 #define OSPFLSDBLSID                     3
95 #define OSPFLSDBROUTERID                 4
96 #define OSPFLSDBSEQUENCE                 5
97 #define OSPFLSDBAGE                      6
98 #define OSPFLSDBCHECKSUM                 7
99 #define OSPFLSDBADVERTISEMENT            8
100 
101 /* OSPF MIB ospfAreaRangeTable. */
102 #define OSPFAREARANGEAREAID              1
103 #define OSPFAREARANGENET                 2
104 #define OSPFAREARANGEMASK                3
105 #define OSPFAREARANGESTATUS              4
106 #define OSPFAREARANGEEFFECT              5
107 
108 /* OSPF MIB ospfHostTable. */
109 #define OSPFHOSTIPADDRESS                1
110 #define OSPFHOSTTOS                      2
111 #define OSPFHOSTMETRIC                   3
112 #define OSPFHOSTSTATUS                   4
113 #define OSPFHOSTAREAID                   5
114 
115 /* OSPF MIB ospfIfTable. */
116 #define OSPFIFIPADDRESS                  1
117 #define OSPFADDRESSLESSIF                2
118 #define OSPFIFAREAID                     3
119 #define OSPFIFTYPE                       4
120 #define OSPFIFADMINSTAT                  5
121 #define OSPFIFRTRPRIORITY                6
122 #define OSPFIFTRANSITDELAY               7
123 #define OSPFIFRETRANSINTERVAL            8
124 #define OSPFIFHELLOINTERVAL              9
125 #define OSPFIFRTRDEADINTERVAL            10
126 #define OSPFIFPOLLINTERVAL               11
127 #define OSPFIFSTATE                      12
128 #define OSPFIFDESIGNATEDROUTER           13
129 #define OSPFIFBACKUPDESIGNATEDROUTER     14
130 #define OSPFIFEVENTS                     15
131 #define OSPFIFAUTHKEY                    16
132 #define OSPFIFSTATUS                     17
133 #define OSPFIFMULTICASTFORWARDING        18
134 #define OSPFIFDEMAND                     19
135 #define OSPFIFAUTHTYPE                   20
136 
137 /* OSPF MIB ospfIfMetricTable. */
138 #define OSPFIFMETRICIPADDRESS            1
139 #define OSPFIFMETRICADDRESSLESSIF        2
140 #define OSPFIFMETRICTOS                  3
141 #define OSPFIFMETRICVALUE                4
142 #define OSPFIFMETRICSTATUS               5
143 
144 /* OSPF MIB ospfVirtIfTable. */
145 #define OSPFVIRTIFAREAID                 1
146 #define OSPFVIRTIFNEIGHBOR               2
147 #define OSPFVIRTIFTRANSITDELAY           3
148 #define OSPFVIRTIFRETRANSINTERVAL        4
149 #define OSPFVIRTIFHELLOINTERVAL          5
150 #define OSPFVIRTIFRTRDEADINTERVAL        6
151 #define OSPFVIRTIFSTATE                  7
152 #define OSPFVIRTIFEVENTS                 8
153 #define OSPFVIRTIFAUTHKEY                9
154 #define OSPFVIRTIFSTATUS                 10
155 #define OSPFVIRTIFAUTHTYPE               11
156 
157 /* OSPF MIB ospfNbrTable. */
158 #define OSPFNBRIPADDR                    1
159 #define OSPFNBRADDRESSLESSINDEX          2
160 #define OSPFNBRRTRID                     3
161 #define OSPFNBROPTIONS                   4
162 #define OSPFNBRPRIORITY                  5
163 #define OSPFNBRSTATE                     6
164 #define OSPFNBREVENTS                    7
165 #define OSPFNBRLSRETRANSQLEN             8
166 #define OSPFNBMANBRSTATUS                9
167 #define OSPFNBMANBRPERMANENCE            10
168 #define OSPFNBRHELLOSUPPRESSED           11
169 
170 /* OSPF MIB ospfVirtNbrTable. */
171 #define OSPFVIRTNBRAREA                  1
172 #define OSPFVIRTNBRRTRID                 2
173 #define OSPFVIRTNBRIPADDR                3
174 #define OSPFVIRTNBROPTIONS               4
175 #define OSPFVIRTNBRSTATE                 5
176 #define OSPFVIRTNBREVENTS                6
177 #define OSPFVIRTNBRLSRETRANSQLEN         7
178 #define OSPFVIRTNBRHELLOSUPPRESSED       8
179 
180 /* OSPF MIB ospfExtLsdbTable. */
181 #define OSPFEXTLSDBTYPE                  1
182 #define OSPFEXTLSDBLSID                  2
183 #define OSPFEXTLSDBROUTERID              3
184 #define OSPFEXTLSDBSEQUENCE              4
185 #define OSPFEXTLSDBAGE                   5
186 #define OSPFEXTLSDBCHECKSUM              6
187 #define OSPFEXTLSDBADVERTISEMENT         7
188 
189 /* OSPF MIB ospfAreaAggregateTable. */
190 #define OSPFAREAAGGREGATEAREAID          1
191 #define OSPFAREAAGGREGATELSDBTYPE        2
192 #define OSPFAREAAGGREGATENET             3
193 #define OSPFAREAAGGREGATEMASK            4
194 #define OSPFAREAAGGREGATESTATUS          5
195 #define OSPFAREAAGGREGATEEFFECT          6
196 
197 /* SYNTAX Status from OSPF-MIB. */
198 #define OSPF_STATUS_ENABLED  1
199 #define OSPF_STATUS_DISABLED 2
200 
201 /* SNMP value hack. */
202 #define COUNTER     ASN_COUNTER
203 #define INTEGER     ASN_INTEGER
204 #define GAUGE       ASN_GAUGE
205 #define TIMETICKS   ASN_TIMETICKS
206 #define IPADDRESS   ASN_IPADDRESS
207 #define STRING      ASN_OCTET_STR
208 
209 /* Because DR/DROther values are exhanged wrt RFC */
210 #define ISM_SNMP(x)                                                            \
211 	(((x) == ISM_DROther) ? ISM_DR : ((x) == ISM_DR) ? ISM_DROther : (x))
212 
213 /* Declare static local variables for convenience. */
214 SNMP_LOCAL_VARIABLES
215 
216 /* OSPF-MIB instances. */
217 static oid ospf_oid[] = {OSPF2MIB};
218 static oid ospf_trap_oid[] = {OSPF2MIB, 16, 2}; /* Not reverse mappable! */
219 
220 /* IP address 0.0.0.0. */
221 static struct in_addr ospf_empty_addr = {.s_addr = 0};
222 
223 /* Hook functions. */
224 static uint8_t *ospfGeneralGroup(struct variable *, oid *, size_t *, int,
225 				 size_t *, WriteMethod **);
226 static uint8_t *ospfAreaEntry(struct variable *, oid *, size_t *, int, size_t *,
227 			      WriteMethod **);
228 static uint8_t *ospfStubAreaEntry(struct variable *, oid *, size_t *, int,
229 				  size_t *, WriteMethod **);
230 static uint8_t *ospfLsdbEntry(struct variable *, oid *, size_t *, int, size_t *,
231 			      WriteMethod **);
232 static uint8_t *ospfAreaRangeEntry(struct variable *, oid *, size_t *, int,
233 				   size_t *, WriteMethod **);
234 static uint8_t *ospfHostEntry(struct variable *, oid *, size_t *, int, size_t *,
235 			      WriteMethod **);
236 static uint8_t *ospfIfEntry(struct variable *, oid *, size_t *, int, size_t *,
237 			    WriteMethod **);
238 static uint8_t *ospfIfMetricEntry(struct variable *, oid *, size_t *, int,
239 				  size_t *, WriteMethod **);
240 static uint8_t *ospfVirtIfEntry(struct variable *, oid *, size_t *, int,
241 				size_t *, WriteMethod **);
242 static uint8_t *ospfNbrEntry(struct variable *, oid *, size_t *, int, size_t *,
243 			     WriteMethod **);
244 static uint8_t *ospfVirtNbrEntry(struct variable *, oid *, size_t *, int,
245 				 size_t *, WriteMethod **);
246 static uint8_t *ospfExtLsdbEntry(struct variable *, oid *, size_t *, int,
247 				 size_t *, WriteMethod **);
248 static uint8_t *ospfAreaAggregateEntry(struct variable *, oid *, size_t *, int,
249 				       size_t *, WriteMethod **);
250 
251 static struct variable ospf_variables[] = {
252 	/* OSPF general variables */
253 	{OSPFROUTERID, IPADDRESS, RWRITE, ospfGeneralGroup, 2, {1, 1}},
254 	{OSPFADMINSTAT, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 2}},
255 	{OSPFVERSIONNUMBER, INTEGER, RONLY, ospfGeneralGroup, 2, {1, 3}},
256 	{OSPFAREABDRRTRSTATUS, INTEGER, RONLY, ospfGeneralGroup, 2, {1, 4}},
257 	{OSPFASBDRRTRSTATUS, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 5}},
258 	{OSPFEXTERNLSACOUNT, GAUGE, RONLY, ospfGeneralGroup, 2, {1, 6}},
259 	{OSPFEXTERNLSACKSUMSUM, INTEGER, RONLY, ospfGeneralGroup, 2, {1, 7}},
260 	{OSPFTOSSUPPORT, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 8}},
261 	{OSPFORIGINATENEWLSAS, COUNTER, RONLY, ospfGeneralGroup, 2, {1, 9}},
262 	{OSPFRXNEWLSAS, COUNTER, RONLY, ospfGeneralGroup, 2, {1, 10}},
263 	{OSPFEXTLSDBLIMIT, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 11}},
264 	{OSPFMULTICASTEXTENSIONS,
265 	 INTEGER,
266 	 RWRITE,
267 	 ospfGeneralGroup,
268 	 2,
269 	 {1, 12}},
270 	{OSPFEXITOVERFLOWINTERVAL,
271 	 INTEGER,
272 	 RWRITE,
273 	 ospfGeneralGroup,
274 	 2,
275 	 {1, 13}},
276 	{OSPFDEMANDEXTENSIONS, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 14}},
277 
278 	/* OSPF area data structure. */
279 	{OSPFAREAID, IPADDRESS, RONLY, ospfAreaEntry, 3, {2, 1, 1}},
280 	{OSPFAUTHTYPE, INTEGER, RWRITE, ospfAreaEntry, 3, {2, 1, 2}},
281 	{OSPFIMPORTASEXTERN, INTEGER, RWRITE, ospfAreaEntry, 3, {2, 1, 3}},
282 	{OSPFSPFRUNS, COUNTER, RONLY, ospfAreaEntry, 3, {2, 1, 4}},
283 	{OSPFAREABDRRTRCOUNT, GAUGE, RONLY, ospfAreaEntry, 3, {2, 1, 5}},
284 	{OSPFASBDRRTRCOUNT, GAUGE, RONLY, ospfAreaEntry, 3, {2, 1, 6}},
285 	{OSPFAREALSACOUNT, GAUGE, RONLY, ospfAreaEntry, 3, {2, 1, 7}},
286 	{OSPFAREALSACKSUMSUM, INTEGER, RONLY, ospfAreaEntry, 3, {2, 1, 8}},
287 	{OSPFAREASUMMARY, INTEGER, RWRITE, ospfAreaEntry, 3, {2, 1, 9}},
288 	{OSPFAREASTATUS, INTEGER, RWRITE, ospfAreaEntry, 3, {2, 1, 10}},
289 
290 	/* OSPF stub area information. */
291 	{OSPFSTUBAREAID, IPADDRESS, RONLY, ospfStubAreaEntry, 3, {3, 1, 1}},
292 	{OSPFSTUBTOS, INTEGER, RONLY, ospfStubAreaEntry, 3, {3, 1, 2}},
293 	{OSPFSTUBMETRIC, INTEGER, RWRITE, ospfStubAreaEntry, 3, {3, 1, 3}},
294 	{OSPFSTUBSTATUS, INTEGER, RWRITE, ospfStubAreaEntry, 3, {3, 1, 4}},
295 	{OSPFSTUBMETRICTYPE, INTEGER, RWRITE, ospfStubAreaEntry, 3, {3, 1, 5}},
296 
297 	/* OSPF link state database. */
298 	{OSPFLSDBAREAID, IPADDRESS, RONLY, ospfLsdbEntry, 3, {4, 1, 1}},
299 	{OSPFLSDBTYPE, INTEGER, RONLY, ospfLsdbEntry, 3, {4, 1, 2}},
300 	{OSPFLSDBLSID, IPADDRESS, RONLY, ospfLsdbEntry, 3, {4, 1, 3}},
301 	{OSPFLSDBROUTERID, IPADDRESS, RONLY, ospfLsdbEntry, 3, {4, 1, 4}},
302 	{OSPFLSDBSEQUENCE, INTEGER, RONLY, ospfLsdbEntry, 3, {4, 1, 5}},
303 	{OSPFLSDBAGE, INTEGER, RONLY, ospfLsdbEntry, 3, {4, 1, 6}},
304 	{OSPFLSDBCHECKSUM, INTEGER, RONLY, ospfLsdbEntry, 3, {4, 1, 7}},
305 	{OSPFLSDBADVERTISEMENT, STRING, RONLY, ospfLsdbEntry, 3, {4, 1, 8}},
306 
307 	/* Area range table. */
308 	{OSPFAREARANGEAREAID,
309 	 IPADDRESS,
310 	 RONLY,
311 	 ospfAreaRangeEntry,
312 	 3,
313 	 {5, 1, 1}},
314 	{OSPFAREARANGENET, IPADDRESS, RONLY, ospfAreaRangeEntry, 3, {5, 1, 2}},
315 	{OSPFAREARANGEMASK,
316 	 IPADDRESS,
317 	 RWRITE,
318 	 ospfAreaRangeEntry,
319 	 3,
320 	 {5, 1, 3}},
321 	{OSPFAREARANGESTATUS,
322 	 INTEGER,
323 	 RWRITE,
324 	 ospfAreaRangeEntry,
325 	 3,
326 	 {5, 1, 4}},
327 	{OSPFAREARANGEEFFECT,
328 	 INTEGER,
329 	 RWRITE,
330 	 ospfAreaRangeEntry,
331 	 3,
332 	 {5, 1, 5}},
333 
334 	/* OSPF host table. */
335 	{OSPFHOSTIPADDRESS, IPADDRESS, RONLY, ospfHostEntry, 3, {6, 1, 1}},
336 	{OSPFHOSTTOS, INTEGER, RONLY, ospfHostEntry, 3, {6, 1, 2}},
337 	{OSPFHOSTMETRIC, INTEGER, RWRITE, ospfHostEntry, 3, {6, 1, 3}},
338 	{OSPFHOSTSTATUS, INTEGER, RWRITE, ospfHostEntry, 3, {6, 1, 4}},
339 	{OSPFHOSTAREAID, IPADDRESS, RONLY, ospfHostEntry, 3, {6, 1, 5}},
340 
341 	/* OSPF interface table. */
342 	{OSPFIFIPADDRESS, IPADDRESS, RONLY, ospfIfEntry, 3, {7, 1, 1}},
343 	{OSPFADDRESSLESSIF, INTEGER, RONLY, ospfIfEntry, 3, {7, 1, 2}},
344 	{OSPFIFAREAID, IPADDRESS, RWRITE, ospfIfEntry, 3, {7, 1, 3}},
345 	{OSPFIFTYPE, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 4}},
346 	{OSPFIFADMINSTAT, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 5}},
347 	{OSPFIFRTRPRIORITY, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 6}},
348 	{OSPFIFTRANSITDELAY, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 7}},
349 	{OSPFIFRETRANSINTERVAL, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 8}},
350 	{OSPFIFHELLOINTERVAL, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 9}},
351 	{OSPFIFRTRDEADINTERVAL, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 10}},
352 	{OSPFIFPOLLINTERVAL, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 11}},
353 	{OSPFIFSTATE, INTEGER, RONLY, ospfIfEntry, 3, {7, 1, 12}},
354 	{OSPFIFDESIGNATEDROUTER, IPADDRESS, RONLY, ospfIfEntry, 3, {7, 1, 13}},
355 	{OSPFIFBACKUPDESIGNATEDROUTER,
356 	 IPADDRESS,
357 	 RONLY,
358 	 ospfIfEntry,
359 	 3,
360 	 {7, 1, 14}},
361 	{OSPFIFEVENTS, COUNTER, RONLY, ospfIfEntry, 3, {7, 1, 15}},
362 	{OSPFIFAUTHKEY, STRING, RWRITE, ospfIfEntry, 3, {7, 1, 16}},
363 	{OSPFIFSTATUS, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 17}},
364 	{OSPFIFMULTICASTFORWARDING,
365 	 INTEGER,
366 	 RWRITE,
367 	 ospfIfEntry,
368 	 3,
369 	 {7, 1, 18}},
370 	{OSPFIFDEMAND, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 19}},
371 	{OSPFIFAUTHTYPE, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 20}},
372 
373 	/* OSPF interface metric table. */
374 	{OSPFIFMETRICIPADDRESS,
375 	 IPADDRESS,
376 	 RONLY,
377 	 ospfIfMetricEntry,
378 	 3,
379 	 {8, 1, 1}},
380 	{OSPFIFMETRICADDRESSLESSIF,
381 	 INTEGER,
382 	 RONLY,
383 	 ospfIfMetricEntry,
384 	 3,
385 	 {8, 1, 2}},
386 	{OSPFIFMETRICTOS, INTEGER, RONLY, ospfIfMetricEntry, 3, {8, 1, 3}},
387 	{OSPFIFMETRICVALUE, INTEGER, RWRITE, ospfIfMetricEntry, 3, {8, 1, 4}},
388 	{OSPFIFMETRICSTATUS, INTEGER, RWRITE, ospfIfMetricEntry, 3, {8, 1, 5}},
389 
390 	/* OSPF virtual interface table. */
391 	{OSPFVIRTIFAREAID, IPADDRESS, RONLY, ospfVirtIfEntry, 3, {9, 1, 1}},
392 	{OSPFVIRTIFNEIGHBOR, IPADDRESS, RONLY, ospfVirtIfEntry, 3, {9, 1, 2}},
393 	{OSPFVIRTIFTRANSITDELAY,
394 	 INTEGER,
395 	 RWRITE,
396 	 ospfVirtIfEntry,
397 	 3,
398 	 {9, 1, 3}},
399 	{OSPFVIRTIFRETRANSINTERVAL,
400 	 INTEGER,
401 	 RWRITE,
402 	 ospfVirtIfEntry,
403 	 3,
404 	 {9, 1, 4}},
405 	{OSPFVIRTIFHELLOINTERVAL,
406 	 INTEGER,
407 	 RWRITE,
408 	 ospfVirtIfEntry,
409 	 3,
410 	 {9, 1, 5}},
411 	{OSPFVIRTIFRTRDEADINTERVAL,
412 	 INTEGER,
413 	 RWRITE,
414 	 ospfVirtIfEntry,
415 	 3,
416 	 {9, 1, 6}},
417 	{OSPFVIRTIFSTATE, INTEGER, RONLY, ospfVirtIfEntry, 3, {9, 1, 7}},
418 	{OSPFVIRTIFEVENTS, COUNTER, RONLY, ospfVirtIfEntry, 3, {9, 1, 8}},
419 	{OSPFVIRTIFAUTHKEY, STRING, RWRITE, ospfVirtIfEntry, 3, {9, 1, 9}},
420 	{OSPFVIRTIFSTATUS, INTEGER, RWRITE, ospfVirtIfEntry, 3, {9, 1, 10}},
421 	{OSPFVIRTIFAUTHTYPE, INTEGER, RWRITE, ospfVirtIfEntry, 3, {9, 1, 11}},
422 
423 	/* OSPF neighbor table. */
424 	{OSPFNBRIPADDR, IPADDRESS, RONLY, ospfNbrEntry, 3, {10, 1, 1}},
425 	{OSPFNBRADDRESSLESSINDEX, INTEGER, RONLY, ospfNbrEntry, 3, {10, 1, 2}},
426 	{OSPFNBRRTRID, IPADDRESS, RONLY, ospfNbrEntry, 3, {10, 1, 3}},
427 	{OSPFNBROPTIONS, INTEGER, RONLY, ospfNbrEntry, 3, {10, 1, 4}},
428 	{OSPFNBRPRIORITY, INTEGER, RWRITE, ospfNbrEntry, 3, {10, 1, 5}},
429 	{OSPFNBRSTATE, INTEGER, RONLY, ospfNbrEntry, 3, {10, 1, 6}},
430 	{OSPFNBREVENTS, COUNTER, RONLY, ospfNbrEntry, 3, {10, 1, 7}},
431 	{OSPFNBRLSRETRANSQLEN, GAUGE, RONLY, ospfNbrEntry, 3, {10, 1, 8}},
432 	{OSPFNBMANBRSTATUS, INTEGER, RWRITE, ospfNbrEntry, 3, {10, 1, 9}},
433 	{OSPFNBMANBRPERMANENCE, INTEGER, RONLY, ospfNbrEntry, 3, {10, 1, 10}},
434 	{OSPFNBRHELLOSUPPRESSED, INTEGER, RONLY, ospfNbrEntry, 3, {10, 1, 11}},
435 
436 	/* OSPF virtual neighbor table. */
437 	{OSPFVIRTNBRAREA, IPADDRESS, RONLY, ospfVirtNbrEntry, 3, {11, 1, 1}},
438 	{OSPFVIRTNBRRTRID, IPADDRESS, RONLY, ospfVirtNbrEntry, 3, {11, 1, 2}},
439 	{OSPFVIRTNBRIPADDR, IPADDRESS, RONLY, ospfVirtNbrEntry, 3, {11, 1, 3}},
440 	{OSPFVIRTNBROPTIONS, INTEGER, RONLY, ospfVirtNbrEntry, 3, {11, 1, 4}},
441 	{OSPFVIRTNBRSTATE, INTEGER, RONLY, ospfVirtNbrEntry, 3, {11, 1, 5}},
442 	{OSPFVIRTNBREVENTS, COUNTER, RONLY, ospfVirtNbrEntry, 3, {11, 1, 6}},
443 	{OSPFVIRTNBRLSRETRANSQLEN,
444 	 INTEGER,
445 	 RONLY,
446 	 ospfVirtNbrEntry,
447 	 3,
448 	 {11, 1, 7}},
449 	{OSPFVIRTNBRHELLOSUPPRESSED,
450 	 INTEGER,
451 	 RONLY,
452 	 ospfVirtNbrEntry,
453 	 3,
454 	 {11, 1, 8}},
455 
456 	/* OSPF link state database, external. */
457 	{OSPFEXTLSDBTYPE, INTEGER, RONLY, ospfExtLsdbEntry, 3, {12, 1, 1}},
458 	{OSPFEXTLSDBLSID, IPADDRESS, RONLY, ospfExtLsdbEntry, 3, {12, 1, 2}},
459 	{OSPFEXTLSDBROUTERID,
460 	 IPADDRESS,
461 	 RONLY,
462 	 ospfExtLsdbEntry,
463 	 3,
464 	 {12, 1, 3}},
465 	{OSPFEXTLSDBSEQUENCE, INTEGER, RONLY, ospfExtLsdbEntry, 3, {12, 1, 4}},
466 	{OSPFEXTLSDBAGE, INTEGER, RONLY, ospfExtLsdbEntry, 3, {12, 1, 5}},
467 	{OSPFEXTLSDBCHECKSUM, INTEGER, RONLY, ospfExtLsdbEntry, 3, {12, 1, 6}},
468 	{OSPFEXTLSDBADVERTISEMENT,
469 	 STRING,
470 	 RONLY,
471 	 ospfExtLsdbEntry,
472 	 3,
473 	 {12, 1, 7}},
474 
475 	/* OSPF area aggregate table. */
476 	{OSPFAREAAGGREGATEAREAID,
477 	 IPADDRESS,
478 	 RONLY,
479 	 ospfAreaAggregateEntry,
480 	 3,
481 	 {14, 1, 1}},
482 	{OSPFAREAAGGREGATELSDBTYPE,
483 	 INTEGER,
484 	 RONLY,
485 	 ospfAreaAggregateEntry,
486 	 3,
487 	 {14, 1, 2}},
488 	{OSPFAREAAGGREGATENET,
489 	 IPADDRESS,
490 	 RONLY,
491 	 ospfAreaAggregateEntry,
492 	 3,
493 	 {14, 1, 3}},
494 	{OSPFAREAAGGREGATEMASK,
495 	 IPADDRESS,
496 	 RONLY,
497 	 ospfAreaAggregateEntry,
498 	 3,
499 	 {14, 1, 4}},
500 	{OSPFAREAAGGREGATESTATUS,
501 	 INTEGER,
502 	 RWRITE,
503 	 ospfAreaAggregateEntry,
504 	 3,
505 	 {14, 1, 5}},
506 	{OSPFAREAAGGREGATEEFFECT,
507 	 INTEGER,
508 	 RWRITE,
509 	 ospfAreaAggregateEntry,
510 	 3,
511 	 {14, 1, 6}}};
512 
513 /* The administrative status of OSPF.  When OSPF is enbled on at least
514    one interface return 1. */
ospf_admin_stat(struct ospf * ospf)515 static int ospf_admin_stat(struct ospf *ospf)
516 {
517 	struct listnode *node;
518 	struct ospf_interface *oi;
519 
520 	if (ospf == NULL)
521 		return 0;
522 
523 	for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi))
524 		if (oi && oi->address)
525 			return 1;
526 
527 	return 0;
528 }
529 
ospfGeneralGroup(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)530 static uint8_t *ospfGeneralGroup(struct variable *v, oid *name, size_t *length,
531 				 int exact, size_t *var_len,
532 				 WriteMethod **write_method)
533 {
534 	struct ospf *ospf;
535 
536 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
537 
538 	/* Check whether the instance identifier is valid */
539 	if (smux_header_generic(v, name, length, exact, var_len, write_method)
540 	    == MATCH_FAILED)
541 		return NULL;
542 
543 	/* Return the current value of the variable */
544 	switch (v->magic) {
545 	case OSPFROUTERID: /* 1 */
546 		/* Router-ID of this OSPF instance. */
547 		if (ospf)
548 			return SNMP_IPADDRESS(ospf->router_id);
549 		else
550 			return SNMP_IPADDRESS(ospf_empty_addr);
551 	case OSPFADMINSTAT: /* 2 */
552 		/* The administrative status of OSPF in the router. */
553 		if (ospf_admin_stat(ospf))
554 			return SNMP_INTEGER(OSPF_STATUS_ENABLED);
555 		else
556 			return SNMP_INTEGER(OSPF_STATUS_DISABLED);
557 	case OSPFVERSIONNUMBER: /* 3 */
558 		/* OSPF version 2. */
559 		return SNMP_INTEGER(OSPF_VERSION);
560 	case OSPFAREABDRRTRSTATUS: /* 4 */
561 		/* Area Border router status. */
562 		if (ospf && CHECK_FLAG(ospf->flags, OSPF_FLAG_ABR))
563 			return SNMP_INTEGER(SNMP_TRUE);
564 		else
565 			return SNMP_INTEGER(SNMP_FALSE);
566 	case OSPFASBDRRTRSTATUS: /* 5 */
567 		/* AS Border router status. */
568 		if (ospf && CHECK_FLAG(ospf->flags, OSPF_FLAG_ASBR))
569 			return SNMP_INTEGER(SNMP_TRUE);
570 		else
571 			return SNMP_INTEGER(SNMP_FALSE);
572 	case OSPFEXTERNLSACOUNT: /* 6 */
573 		/* External LSA counts. */
574 		if (ospf)
575 			return SNMP_INTEGER(ospf_lsdb_count_all(ospf->lsdb));
576 		else
577 			return SNMP_INTEGER(0);
578 	case OSPFEXTERNLSACKSUMSUM: /* 7 */
579 		/* External LSA checksum. */
580 		return SNMP_INTEGER(0);
581 	case OSPFTOSSUPPORT: /* 8 */
582 		/* TOS is not supported. */
583 		return SNMP_INTEGER(SNMP_FALSE);
584 	case OSPFORIGINATENEWLSAS: /* 9 */
585 		/* The number of new link-state advertisements. */
586 		if (ospf)
587 			return SNMP_INTEGER(ospf->lsa_originate_count);
588 		else
589 			return SNMP_INTEGER(0);
590 	case OSPFRXNEWLSAS: /* 10 */
591 		/* The number of link-state advertisements received determined
592 		   to be new instantiations. */
593 		if (ospf)
594 			return SNMP_INTEGER(ospf->rx_lsa_count);
595 		else
596 			return SNMP_INTEGER(0);
597 	case OSPFEXTLSDBLIMIT: /* 11 */
598 		/* There is no limit for the number of non-default
599 		   AS-external-LSAs. */
600 		return SNMP_INTEGER(-1);
601 	case OSPFMULTICASTEXTENSIONS: /* 12 */
602 		/* Multicast Extensions to OSPF is not supported. */
603 		return SNMP_INTEGER(0);
604 	case OSPFEXITOVERFLOWINTERVAL: /* 13 */
605 		/* Overflow is not supported. */
606 		return SNMP_INTEGER(0);
607 	case OSPFDEMANDEXTENSIONS: /* 14 */
608 		/* Demand routing is not supported. */
609 		return SNMP_INTEGER(SNMP_FALSE);
610 	default:
611 		return NULL;
612 	}
613 	return NULL;
614 }
615 
616 static struct ospf_area *
ospf_area_lookup_next(struct ospf * ospf,struct in_addr * area_id,int first)617 ospf_area_lookup_next(struct ospf *ospf, struct in_addr *area_id, int first)
618 {
619 	struct ospf_area *area;
620 	struct listnode *node;
621 
622 	if (ospf == NULL)
623 		return NULL;
624 
625 	if (first) {
626 		node = listhead(ospf->areas);
627 		if (node) {
628 			area = listgetdata(node);
629 			*area_id = area->area_id;
630 			return area;
631 		}
632 		return NULL;
633 	}
634 	for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
635 		if (ntohl(area->area_id.s_addr) > ntohl(area_id->s_addr)) {
636 			*area_id = area->area_id;
637 			return area;
638 		}
639 	}
640 	return NULL;
641 }
642 
ospfAreaLookup(struct variable * v,oid name[],size_t * length,struct in_addr * addr,int exact)643 static struct ospf_area *ospfAreaLookup(struct variable *v, oid name[],
644 					size_t *length, struct in_addr *addr,
645 					int exact)
646 {
647 	struct ospf *ospf;
648 	struct ospf_area *area;
649 	int len;
650 
651 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
652 	if (ospf == NULL)
653 		return NULL;
654 
655 	if (exact) {
656 		/* Length is insufficient to lookup OSPF area. */
657 		if (*length - v->namelen != sizeof(struct in_addr))
658 			return NULL;
659 
660 		oid2in_addr(name + v->namelen, sizeof(struct in_addr), addr);
661 
662 		area = ospf_area_lookup_by_area_id(ospf, *addr);
663 
664 		return area;
665 	} else {
666 		len = *length - v->namelen;
667 		if (len > 4)
668 			len = 4;
669 
670 		oid2in_addr(name + v->namelen, len, addr);
671 
672 		area = ospf_area_lookup_next(ospf, addr, len == 0 ? 1 : 0);
673 
674 		if (area == NULL)
675 			return NULL;
676 
677 		oid_copy_addr(name + v->namelen, addr, sizeof(struct in_addr));
678 		*length = sizeof(struct in_addr) + v->namelen;
679 
680 		return area;
681 	}
682 	return NULL;
683 }
684 
ospfAreaEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)685 static uint8_t *ospfAreaEntry(struct variable *v, oid *name, size_t *length,
686 			      int exact, size_t *var_len,
687 			      WriteMethod **write_method)
688 {
689 	struct ospf_area *area;
690 	struct in_addr addr;
691 
692 	if (smux_header_table(v, name, length, exact, var_len, write_method)
693 	    == MATCH_FAILED)
694 		return NULL;
695 
696 	memset(&addr, 0, sizeof(struct in_addr));
697 
698 	area = ospfAreaLookup(v, name, length, &addr, exact);
699 	if (!area)
700 		return NULL;
701 
702 	/* Return the current value of the variable */
703 	switch (v->magic) {
704 	case OSPFAREAID: /* 1 */
705 		return SNMP_IPADDRESS(area->area_id);
706 	case OSPFAUTHTYPE: /* 2 */
707 		return SNMP_INTEGER(area->auth_type);
708 	case OSPFIMPORTASEXTERN: /* 3 */
709 		return SNMP_INTEGER(area->external_routing + 1);
710 	case OSPFSPFRUNS: /* 4 */
711 		return SNMP_INTEGER(area->spf_calculation);
712 	case OSPFAREABDRRTRCOUNT: /* 5 */
713 		return SNMP_INTEGER(area->abr_count);
714 	case OSPFASBDRRTRCOUNT: /* 6 */
715 		return SNMP_INTEGER(area->asbr_count);
716 	case OSPFAREALSACOUNT: /* 7 */
717 		return SNMP_INTEGER(area->lsdb->total);
718 	case OSPFAREALSACKSUMSUM: /* 8 */
719 		return SNMP_INTEGER(0);
720 	case OSPFAREASUMMARY: /* 9 */
721 #define OSPF_noAreaSummary   1
722 #define OSPF_sendAreaSummary 2
723 		if (area->no_summary)
724 			return SNMP_INTEGER(OSPF_noAreaSummary);
725 		else
726 			return SNMP_INTEGER(OSPF_sendAreaSummary);
727 	case OSPFAREASTATUS: /* 10 */
728 		return SNMP_INTEGER(SNMP_VALID);
729 	default:
730 		return NULL;
731 	}
732 	return NULL;
733 }
734 
ospf_stub_area_lookup_next(struct in_addr * area_id,int first)735 static struct ospf_area *ospf_stub_area_lookup_next(struct in_addr *area_id,
736 						    int first)
737 {
738 	struct ospf_area *area;
739 	struct listnode *node;
740 	struct ospf *ospf;
741 
742 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
743 	if (ospf == NULL)
744 		return NULL;
745 
746 	for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) {
747 		if (area->external_routing == OSPF_AREA_STUB) {
748 			if (first) {
749 				*area_id = area->area_id;
750 				return area;
751 			} else if (ntohl(area->area_id.s_addr)
752 				   > ntohl(area_id->s_addr)) {
753 				*area_id = area->area_id;
754 				return area;
755 			}
756 		}
757 	}
758 	return NULL;
759 }
760 
ospfStubAreaLookup(struct variable * v,oid name[],size_t * length,struct in_addr * addr,int exact)761 static struct ospf_area *ospfStubAreaLookup(struct variable *v, oid name[],
762 					    size_t *length,
763 					    struct in_addr *addr, int exact)
764 {
765 	struct ospf *ospf;
766 	struct ospf_area *area;
767 	int len;
768 
769 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
770 	if (ospf == NULL)
771 		return NULL;
772 
773 	/* Exact lookup. */
774 	if (exact) {
775 		/* ospfStubAreaID + ospfStubTOS. */
776 		if (*length != v->namelen + sizeof(struct in_addr) + 1)
777 			return NULL;
778 
779 		/* Check ospfStubTOS is zero. */
780 		if (name[*length - 1] != 0)
781 			return NULL;
782 
783 		oid2in_addr(name + v->namelen, sizeof(struct in_addr), addr);
784 
785 		area = ospf_area_lookup_by_area_id(ospf, *addr);
786 
787 		if (area && area->external_routing == OSPF_AREA_STUB)
788 			return area;
789 		else
790 			return NULL;
791 	} else {
792 		len = *length - v->namelen;
793 		if (len > 4)
794 			len = 4;
795 
796 		oid2in_addr(name + v->namelen, len, addr);
797 
798 		area = ospf_stub_area_lookup_next(addr, len == 0 ? 1 : 0);
799 
800 		if (area == NULL)
801 			return NULL;
802 
803 		oid_copy_addr(name + v->namelen, addr, sizeof(struct in_addr));
804 		/* Set TOS 0. */
805 		name[v->namelen + sizeof(struct in_addr)] = 0;
806 		*length = v->namelen + sizeof(struct in_addr) + 1;
807 
808 		return area;
809 	}
810 	return NULL;
811 }
812 
ospfStubAreaEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)813 static uint8_t *ospfStubAreaEntry(struct variable *v, oid *name, size_t *length,
814 				  int exact, size_t *var_len,
815 				  WriteMethod **write_method)
816 {
817 	struct ospf_area *area;
818 	struct in_addr addr;
819 
820 	if (smux_header_table(v, name, length, exact, var_len, write_method)
821 	    == MATCH_FAILED)
822 		return NULL;
823 
824 	memset(&addr, 0, sizeof(struct in_addr));
825 
826 	area = ospfStubAreaLookup(v, name, length, &addr, exact);
827 	if (!area)
828 		return NULL;
829 
830 	/* Return the current value of the variable */
831 	switch (v->magic) {
832 	case OSPFSTUBAREAID: /* 1 */
833 		/* OSPF stub area id. */
834 		return SNMP_IPADDRESS(area->area_id);
835 	case OSPFSTUBTOS: /* 2 */
836 		/* TOS value is not supported. */
837 		return SNMP_INTEGER(0);
838 	case OSPFSTUBMETRIC: /* 3 */
839 		/* Default cost to stub area. */
840 		return SNMP_INTEGER(area->default_cost);
841 	case OSPFSTUBSTATUS: /* 4 */
842 		/* Status of the stub area. */
843 		return SNMP_INTEGER(SNMP_VALID);
844 	case OSPFSTUBMETRICTYPE: /* 5 */
845 				 /* OSPF Metric type. */
846 #define OSPF_ospfMetric     1
847 #define OSPF_comparableCost 2
848 #define OSPF_nonComparable  3
849 		return SNMP_INTEGER(OSPF_ospfMetric);
850 	default:
851 		return NULL;
852 	}
853 	return NULL;
854 }
855 
lsdb_lookup_next(struct ospf_area * area,uint8_t * type,int type_next,struct in_addr * ls_id,int ls_id_next,struct in_addr * router_id,int router_id_next)856 static struct ospf_lsa *lsdb_lookup_next(struct ospf_area *area, uint8_t *type,
857 					 int type_next, struct in_addr *ls_id,
858 					 int ls_id_next,
859 					 struct in_addr *router_id,
860 					 int router_id_next)
861 {
862 	struct ospf_lsa *lsa;
863 	int i;
864 
865 	if (type_next)
866 		i = OSPF_MIN_LSA;
867 	else
868 		i = *type;
869 
870 	/* Sanity check, if LSA type unknwon
871 	   merley skip any LSA */
872 	if ((i < OSPF_MIN_LSA) || (i >= OSPF_MAX_LSA)) {
873 		zlog_debug("Strange request with LSA type %d", i);
874 		return NULL;
875 	}
876 
877 	for (; i < OSPF_MAX_LSA; i++) {
878 		*type = i;
879 
880 		lsa = ospf_lsdb_lookup_by_id_next(area->lsdb, *type, *ls_id,
881 						  *router_id, ls_id_next);
882 		if (lsa)
883 			return lsa;
884 
885 		ls_id_next = 1;
886 	}
887 	return NULL;
888 }
889 
ospfLsdbLookup(struct variable * v,oid * name,size_t * length,struct in_addr * area_id,uint8_t * type,struct in_addr * ls_id,struct in_addr * router_id,int exact)890 static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name,
891 				       size_t *length, struct in_addr *area_id,
892 				       uint8_t *type, struct in_addr *ls_id,
893 				       struct in_addr *router_id, int exact)
894 {
895 	struct ospf *ospf;
896 	struct ospf_area *area;
897 	struct ospf_lsa *lsa;
898 	int len;
899 	int type_next;
900 	int ls_id_next;
901 	int router_id_next;
902 	oid *offset;
903 	int offsetlen;
904 
905 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
906 
907 #define OSPF_LSDB_ENTRY_OFFSET (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE)
908 
909 	if (exact) {
910 		/* Area ID + Type + LS ID + Router ID. */
911 		if (*length - v->namelen != OSPF_LSDB_ENTRY_OFFSET)
912 			return NULL;
913 
914 		/* Set OID offset for Area ID. */
915 		offset = name + v->namelen;
916 
917 		/* Lookup area first. */
918 		oid2in_addr(offset, IN_ADDR_SIZE, area_id);
919 		area = ospf_area_lookup_by_area_id(ospf, *area_id);
920 		if (!area)
921 			return NULL;
922 		offset += IN_ADDR_SIZE;
923 
924 		/* Type. */
925 		*type = *offset;
926 		offset++;
927 
928 		/* LS ID. */
929 		oid2in_addr(offset, IN_ADDR_SIZE, ls_id);
930 		offset += IN_ADDR_SIZE;
931 
932 		/* Router ID. */
933 		oid2in_addr(offset, IN_ADDR_SIZE, router_id);
934 
935 		/* Lookup LSDB. */
936 		return ospf_lsdb_lookup_by_id(area->lsdb, *type, *ls_id,
937 					      *router_id);
938 	} else {
939 		/* Get variable length. */
940 		offset = name + v->namelen;
941 		offsetlen = *length - v->namelen;
942 		len = offsetlen;
943 
944 		if (len > (int)IN_ADDR_SIZE)
945 			len = IN_ADDR_SIZE;
946 
947 		oid2in_addr(offset, len, area_id);
948 
949 		/* First we search area. */
950 		if (len == IN_ADDR_SIZE)
951 			area = ospf_area_lookup_by_area_id(ospf, *area_id);
952 		else
953 			area = ospf_area_lookup_next(ospf, area_id, 1);
954 
955 		if (area == NULL)
956 			return NULL;
957 
958 		do {
959 			/* Next we lookup type. */
960 			offset += len;
961 			offsetlen -= len;
962 			len = offsetlen;
963 
964 			if (len <= 0)
965 				type_next = 1;
966 			else {
967 				type_next = 0;
968 				*type = *offset;
969 			}
970 
971 			/* LS ID. */
972 			offset++;
973 			offsetlen--;
974 			len = offsetlen;
975 
976 			if (len <= 0)
977 				ls_id_next = 1;
978 			else {
979 				ls_id_next = 0;
980 				if (len > (int)IN_ADDR_SIZE)
981 					len = IN_ADDR_SIZE;
982 
983 				oid2in_addr(offset, len, ls_id);
984 			}
985 
986 			/* Router ID. */
987 			offset += IN_ADDR_SIZE;
988 			offsetlen -= IN_ADDR_SIZE;
989 			len = offsetlen;
990 
991 			if (len <= 0)
992 				router_id_next = 1;
993 			else {
994 				router_id_next = 0;
995 				if (len > (int)IN_ADDR_SIZE)
996 					len = IN_ADDR_SIZE;
997 
998 				oid2in_addr(offset, len, router_id);
999 			}
1000 
1001 			lsa = lsdb_lookup_next(area, type, type_next, ls_id,
1002 					       ls_id_next, router_id,
1003 					       router_id_next);
1004 
1005 			if (lsa) {
1006 				/* Fill in length. */
1007 				*length = v->namelen + OSPF_LSDB_ENTRY_OFFSET;
1008 
1009 				/* Fill in value. */
1010 				offset = name + v->namelen;
1011 				oid_copy_addr(offset, area_id, IN_ADDR_SIZE);
1012 				offset += IN_ADDR_SIZE;
1013 				*offset = lsa->data->type;
1014 				offset++;
1015 				oid_copy_addr(offset, &lsa->data->id,
1016 					      IN_ADDR_SIZE);
1017 				offset += IN_ADDR_SIZE;
1018 				oid_copy_addr(offset, &lsa->data->adv_router,
1019 					      IN_ADDR_SIZE);
1020 
1021 				return lsa;
1022 			}
1023 		} while ((area = ospf_area_lookup_next(ospf, area_id, 0))
1024 			 != NULL);
1025 	}
1026 	return NULL;
1027 }
1028 
ospfLsdbEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)1029 static uint8_t *ospfLsdbEntry(struct variable *v, oid *name, size_t *length,
1030 			      int exact, size_t *var_len,
1031 			      WriteMethod **write_method)
1032 {
1033 	struct ospf_lsa *lsa;
1034 	struct lsa_header *lsah;
1035 	struct in_addr area_id;
1036 	uint8_t type;
1037 	struct in_addr ls_id;
1038 	struct in_addr router_id;
1039 	struct ospf *ospf;
1040 
1041 	if (smux_header_table(v, name, length, exact, var_len, write_method)
1042 	    == MATCH_FAILED)
1043 		return NULL;
1044 
1045 	/* INDEX { ospfLsdbAreaId, ospfLsdbType,
1046 	   ospfLsdbLsid, ospfLsdbRouterId } */
1047 
1048 	memset(&area_id, 0, sizeof(struct in_addr));
1049 	type = 0;
1050 	memset(&ls_id, 0, sizeof(struct in_addr));
1051 	memset(&router_id, 0, sizeof(struct in_addr));
1052 
1053 	/* Check OSPF instance. */
1054 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1055 	if (ospf == NULL)
1056 		return NULL;
1057 
1058 	lsa = ospfLsdbLookup(v, name, length, &area_id, &type, &ls_id,
1059 			     &router_id, exact);
1060 	if (!lsa)
1061 		return NULL;
1062 
1063 	lsah = lsa->data;
1064 
1065 	/* Return the current value of the variable */
1066 	switch (v->magic) {
1067 	case OSPFLSDBAREAID: /* 1 */
1068 		return SNMP_IPADDRESS(lsa->area->area_id);
1069 	case OSPFLSDBTYPE: /* 2 */
1070 		return SNMP_INTEGER(lsah->type);
1071 	case OSPFLSDBLSID: /* 3 */
1072 		return SNMP_IPADDRESS(lsah->id);
1073 	case OSPFLSDBROUTERID: /* 4 */
1074 		return SNMP_IPADDRESS(lsah->adv_router);
1075 	case OSPFLSDBSEQUENCE: /* 5 */
1076 		return SNMP_INTEGER(lsah->ls_seqnum);
1077 	case OSPFLSDBAGE: /* 6 */
1078 		return SNMP_INTEGER(lsah->ls_age);
1079 	case OSPFLSDBCHECKSUM: /* 7 */
1080 		return SNMP_INTEGER(lsah->checksum);
1081 	case OSPFLSDBADVERTISEMENT: /* 8 */
1082 		*var_len = ntohs(lsah->length);
1083 		return (uint8_t *)lsah;
1084 	default:
1085 		return NULL;
1086 	}
1087 	return NULL;
1088 }
1089 
ospfAreaRangeLookup(struct variable * v,oid * name,size_t * length,struct in_addr * area_id,struct in_addr * range_net,int exact)1090 static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v,
1091 						   oid *name, size_t *length,
1092 						   struct in_addr *area_id,
1093 						   struct in_addr *range_net,
1094 						   int exact)
1095 {
1096 	oid *offset;
1097 	int offsetlen;
1098 	int len;
1099 	struct ospf *ospf;
1100 	struct ospf_area *area;
1101 	struct ospf_area_range *range;
1102 	struct prefix_ipv4 p;
1103 	p.family = AF_INET;
1104 	p.prefixlen = IPV4_MAX_BITLEN;
1105 
1106 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1107 
1108 	if (exact) {
1109 		/* Area ID + Range Network. */
1110 		if (v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE != *length)
1111 			return NULL;
1112 
1113 		/* Set OID offset for Area ID. */
1114 		offset = name + v->namelen;
1115 
1116 		/* Lookup area first. */
1117 		oid2in_addr(offset, IN_ADDR_SIZE, area_id);
1118 
1119 		area = ospf_area_lookup_by_area_id(ospf, *area_id);
1120 		if (!area)
1121 			return NULL;
1122 
1123 		offset += IN_ADDR_SIZE;
1124 
1125 		/* Lookup area range. */
1126 		oid2in_addr(offset, IN_ADDR_SIZE, range_net);
1127 		p.prefix = *range_net;
1128 
1129 		return ospf_area_range_lookup(area, &p);
1130 	} else {
1131 		/* Set OID offset for Area ID. */
1132 		offset = name + v->namelen;
1133 		offsetlen = *length - v->namelen;
1134 
1135 		len = offsetlen;
1136 		if (len > (int)IN_ADDR_SIZE)
1137 			len = IN_ADDR_SIZE;
1138 
1139 		oid2in_addr(offset, len, area_id);
1140 
1141 		/* First we search area. */
1142 		if (len == IN_ADDR_SIZE)
1143 			area = ospf_area_lookup_by_area_id(ospf, *area_id);
1144 		else
1145 			area = ospf_area_lookup_next(ospf, area_id,
1146 						     len == 0 ? 1 : 0);
1147 
1148 		if (area == NULL)
1149 			return NULL;
1150 
1151 		do {
1152 			offset += IN_ADDR_SIZE;
1153 			offsetlen -= IN_ADDR_SIZE;
1154 			len = offsetlen;
1155 
1156 			if (len < 0)
1157 				len = 0;
1158 			if (len > (int)IN_ADDR_SIZE)
1159 				len = IN_ADDR_SIZE;
1160 
1161 			oid2in_addr(offset, len, range_net);
1162 
1163 			range = ospf_area_range_lookup_next(area, range_net,
1164 							    len == 0 ? 1 : 0);
1165 
1166 			if (range) {
1167 				/* Fill in length. */
1168 				*length = v->namelen + IN_ADDR_SIZE
1169 					  + IN_ADDR_SIZE;
1170 
1171 				/* Fill in value. */
1172 				offset = name + v->namelen;
1173 				oid_copy_addr(offset, area_id, IN_ADDR_SIZE);
1174 				offset += IN_ADDR_SIZE;
1175 				oid_copy_addr(offset, range_net, IN_ADDR_SIZE);
1176 
1177 				return range;
1178 			}
1179 		} while ((area = ospf_area_lookup_next(ospf, area_id, 0))
1180 			 != NULL);
1181 	}
1182 	return NULL;
1183 }
1184 
ospfAreaRangeEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)1185 static uint8_t *ospfAreaRangeEntry(struct variable *v, oid *name,
1186 				   size_t *length, int exact, size_t *var_len,
1187 				   WriteMethod **write_method)
1188 {
1189 	struct ospf_area_range *range;
1190 	struct in_addr area_id;
1191 	struct in_addr range_net;
1192 	struct in_addr mask;
1193 	struct ospf *ospf;
1194 
1195 	if (smux_header_table(v, name, length, exact, var_len, write_method)
1196 	    == MATCH_FAILED)
1197 		return NULL;
1198 
1199 	/* Check OSPF instance. */
1200 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1201 	if (ospf == NULL)
1202 		return NULL;
1203 
1204 	memset(&area_id, 0, IN_ADDR_SIZE);
1205 	memset(&range_net, 0, IN_ADDR_SIZE);
1206 
1207 	range = ospfAreaRangeLookup(v, name, length, &area_id, &range_net,
1208 				    exact);
1209 	if (!range)
1210 		return NULL;
1211 
1212 	/* Convert prefixlen to network mask format. */
1213 	masklen2ip(range->subst_masklen, &mask);
1214 
1215 	/* Return the current value of the variable */
1216 	switch (v->magic) {
1217 	case OSPFAREARANGEAREAID: /* 1 */
1218 		return SNMP_IPADDRESS(area_id);
1219 	case OSPFAREARANGENET: /* 2 */
1220 		return SNMP_IPADDRESS(range_net);
1221 	case OSPFAREARANGEMASK: /* 3 */
1222 		return SNMP_IPADDRESS(mask);
1223 	case OSPFAREARANGESTATUS: /* 4 */
1224 		return SNMP_INTEGER(SNMP_VALID);
1225 	case OSPFAREARANGEEFFECT: /* 5 */
1226 #define OSPF_advertiseMatching      1
1227 #define OSPF_doNotAdvertiseMatching 2
1228 		return SNMP_INTEGER(OSPF_advertiseMatching);
1229 	default:
1230 		return NULL;
1231 	}
1232 	return NULL;
1233 }
1234 
ospfHostLookup(struct variable * v,oid * name,size_t * length,struct in_addr * addr,int exact)1235 static struct ospf_nbr_nbma *ospfHostLookup(struct variable *v, oid *name,
1236 					    size_t *length,
1237 					    struct in_addr *addr, int exact)
1238 {
1239 	int len;
1240 	struct ospf_nbr_nbma *nbr_nbma;
1241 	struct ospf *ospf;
1242 
1243 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1244 	if (ospf == NULL)
1245 		return NULL;
1246 
1247 	if (exact) {
1248 		/* INDEX { ospfHostIpAddress, ospfHostTOS } */
1249 		if (*length != v->namelen + IN_ADDR_SIZE + 1)
1250 			return NULL;
1251 
1252 		/* Check ospfHostTOS. */
1253 		if (name[*length - 1] != 0)
1254 			return NULL;
1255 
1256 		oid2in_addr(name + v->namelen, IN_ADDR_SIZE, addr);
1257 
1258 		nbr_nbma = ospf_nbr_nbma_lookup(ospf, *addr);
1259 
1260 		return nbr_nbma;
1261 	} else {
1262 		len = *length - v->namelen;
1263 		if (len > 4)
1264 			len = 4;
1265 
1266 		oid2in_addr(name + v->namelen, len, addr);
1267 
1268 		nbr_nbma =
1269 			ospf_nbr_nbma_lookup_next(ospf, addr, len == 0 ? 1 : 0);
1270 
1271 		if (nbr_nbma == NULL)
1272 			return NULL;
1273 
1274 		oid_copy_addr(name + v->namelen, addr, IN_ADDR_SIZE);
1275 
1276 		/* Set TOS 0. */
1277 		name[v->namelen + IN_ADDR_SIZE] = 0;
1278 
1279 		*length = v->namelen + IN_ADDR_SIZE + 1;
1280 
1281 		return nbr_nbma;
1282 	}
1283 	return NULL;
1284 }
1285 
ospfHostEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)1286 static uint8_t *ospfHostEntry(struct variable *v, oid *name, size_t *length,
1287 			      int exact, size_t *var_len,
1288 			      WriteMethod **write_method)
1289 {
1290 	struct ospf_nbr_nbma *nbr_nbma;
1291 	struct ospf_interface *oi;
1292 	struct in_addr addr;
1293 	struct ospf *ospf;
1294 
1295 	if (smux_header_table(v, name, length, exact, var_len, write_method)
1296 	    == MATCH_FAILED)
1297 		return NULL;
1298 
1299 	/* Check OSPF instance. */
1300 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1301 	if (ospf == NULL)
1302 		return NULL;
1303 
1304 	memset(&addr, 0, sizeof(struct in_addr));
1305 
1306 	nbr_nbma = ospfHostLookup(v, name, length, &addr, exact);
1307 	if (nbr_nbma == NULL)
1308 		return NULL;
1309 
1310 	oi = nbr_nbma->oi;
1311 
1312 	/* Return the current value of the variable */
1313 	switch (v->magic) {
1314 	case OSPFHOSTIPADDRESS: /* 1 */
1315 		return SNMP_IPADDRESS(nbr_nbma->addr);
1316 	case OSPFHOSTTOS: /* 2 */
1317 		return SNMP_INTEGER(0);
1318 	case OSPFHOSTMETRIC: /* 3 */
1319 		if (oi)
1320 			return SNMP_INTEGER(oi->output_cost);
1321 		else
1322 			return SNMP_INTEGER(1);
1323 	case OSPFHOSTSTATUS: /* 4 */
1324 		return SNMP_INTEGER(SNMP_VALID);
1325 	case OSPFHOSTAREAID: /* 5 */
1326 		if (oi && oi->area)
1327 			return SNMP_IPADDRESS(oi->area->area_id);
1328 		else
1329 			return SNMP_IPADDRESS(ospf_empty_addr);
1330 	default:
1331 		return NULL;
1332 	}
1333 	return NULL;
1334 }
1335 
1336 static struct list *ospf_snmp_iflist;
1337 
1338 struct ospf_snmp_if {
1339 	struct in_addr addr;
1340 	ifindex_t ifindex;
1341 	struct interface *ifp;
1342 };
1343 
ospf_snmp_if_new(void)1344 static struct ospf_snmp_if *ospf_snmp_if_new(void)
1345 {
1346 	return XCALLOC(MTYPE_TMP, sizeof(struct ospf_snmp_if));
1347 }
1348 
ospf_snmp_if_free(struct ospf_snmp_if * osif)1349 static void ospf_snmp_if_free(struct ospf_snmp_if *osif)
1350 {
1351 	XFREE(MTYPE_TMP, osif);
1352 }
1353 
ospf_snmp_if_delete(struct interface * ifp)1354 static int ospf_snmp_if_delete(struct interface *ifp)
1355 {
1356 	struct listnode *node, *nnode;
1357 	struct ospf_snmp_if *osif;
1358 
1359 	for (ALL_LIST_ELEMENTS(ospf_snmp_iflist, node, nnode, osif)) {
1360 		if (osif->ifp == ifp) {
1361 			list_delete_node(ospf_snmp_iflist, node);
1362 			ospf_snmp_if_free(osif);
1363 			break;
1364 		}
1365 	}
1366 	return 0;
1367 }
1368 
ospf_snmp_if_update(struct interface * ifp)1369 static int ospf_snmp_if_update(struct interface *ifp)
1370 {
1371 	struct listnode *node;
1372 	struct listnode *pn;
1373 	struct connected *ifc;
1374 	struct prefix *p;
1375 	struct ospf_snmp_if *osif;
1376 	struct in_addr *addr;
1377 	ifindex_t ifindex;
1378 
1379 	ospf_snmp_if_delete(ifp);
1380 
1381 	p = NULL;
1382 	addr = NULL;
1383 	ifindex = 0;
1384 
1385 	/* Lookup first IPv4 address entry. */
1386 	for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
1387 		p = CONNECTED_ID(ifc);
1388 
1389 		if (p->family == AF_INET) {
1390 			addr = &p->u.prefix4;
1391 			break;
1392 		}
1393 	}
1394 	if (!addr)
1395 		ifindex = ifp->ifindex;
1396 
1397 	/* Add interface to the list. */
1398 	pn = NULL;
1399 	for (ALL_LIST_ELEMENTS_RO(ospf_snmp_iflist, node, osif)) {
1400 		if (addr) {
1401 			/* Usual interfaces --> Sort them based on interface
1402 			 * IPv4 addresses */
1403 			if (ntohl(osif->addr.s_addr) > ntohl(addr->s_addr))
1404 				break;
1405 		} else {
1406 			/* Unnumbered interfaces --> Sort them based on
1407 			 * interface indexes */
1408 			if (osif->addr.s_addr != 0 || osif->ifindex > ifindex)
1409 				break;
1410 		}
1411 		pn = node;
1412 	}
1413 
1414 	osif = ospf_snmp_if_new();
1415 	if (addr) /* Usual interface */
1416 	{
1417 		osif->addr = *addr;
1418 
1419 		/* This field is used for storing ospfAddressLessIf OID value,
1420 		 * conform to RFC1850 OSPF-MIB specification, it must be 0 for
1421 		 * usual interface */
1422 		osif->ifindex = 0;
1423 	} else /* Unnumbered interface */
1424 		osif->ifindex = ifindex;
1425 	osif->ifp = ifp;
1426 
1427 	listnode_add_after(ospf_snmp_iflist, pn, osif);
1428 	return 0;
1429 }
1430 
ospf_snmp_is_if_have_addr(struct interface * ifp)1431 static int ospf_snmp_is_if_have_addr(struct interface *ifp)
1432 {
1433 	struct listnode *nn;
1434 	struct connected *ifc;
1435 
1436 	/* Is this interface having any connected IPv4 address ? */
1437 	for (ALL_LIST_ELEMENTS_RO(ifp->connected, nn, ifc)) {
1438 		if (CONNECTED_PREFIX(ifc)->family == AF_INET)
1439 			return 1;
1440 	}
1441 
1442 	return 0;
1443 }
1444 
ospf_snmp_if_lookup(struct in_addr * ifaddr,ifindex_t * ifindex)1445 static struct ospf_interface *ospf_snmp_if_lookup(struct in_addr *ifaddr,
1446 						  ifindex_t *ifindex)
1447 {
1448 	struct listnode *node;
1449 	struct ospf_snmp_if *osif;
1450 	struct ospf_interface *oi = NULL;
1451 	struct ospf *ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1452 
1453 	for (ALL_LIST_ELEMENTS_RO(ospf_snmp_iflist, node, osif)) {
1454 		if (ifaddr->s_addr) {
1455 			if (IPV4_ADDR_SAME(&osif->addr, ifaddr))
1456 				oi = ospf_if_lookup_by_local_addr(
1457 					ospf, osif->ifp, *ifaddr);
1458 		} else {
1459 			if (osif->ifindex == *ifindex)
1460 				oi = ospf_if_lookup_by_local_addr(
1461 					ospf, osif->ifp, *ifaddr);
1462 		}
1463 	}
1464 	return oi;
1465 }
1466 
ospf_snmp_if_lookup_next(struct in_addr * ifaddr,ifindex_t * ifindex,int ifaddr_next,ifindex_t ifindex_next)1467 static struct ospf_interface *ospf_snmp_if_lookup_next(struct in_addr *ifaddr,
1468 						       ifindex_t *ifindex,
1469 						       int ifaddr_next,
1470 						       ifindex_t ifindex_next)
1471 {
1472 	struct ospf_snmp_if *osif;
1473 	struct listnode *nn;
1474 	struct ospf *ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1475 	struct ospf_interface *oi = NULL;
1476 
1477 	if (ospf == NULL)
1478 		return NULL;
1479 
1480 	/* No instance is specified --> Return the first OSPF interface */
1481 	if (ifaddr_next) {
1482 		for (ALL_LIST_ELEMENTS_RO(ospf_snmp_iflist, nn, osif)) {
1483 			osif = listgetdata(nn);
1484 			*ifaddr = osif->addr;
1485 			*ifindex = osif->ifindex;
1486 			/* Because no instance is specified, we don't care about
1487 			 * the kind of
1488 			 * interface (usual or unnumbered), just returning the
1489 			 * first valid
1490 			 * OSPF interface */
1491 			oi = ospf_if_lookup_by_local_addr(ospf, osif->ifp,
1492 							  *ifaddr);
1493 			if (oi)
1494 				return (oi);
1495 		}
1496 		return NULL;
1497 	}
1498 
1499 	/* An instance is specified --> Return the next OSPF interface */
1500 	for (ALL_LIST_ELEMENTS_RO(ospf_snmp_iflist, nn, osif)) {
1501 		/* Usual interface */
1502 		if (ifaddr->s_addr) {
1503 			/* The interface must have valid AF_INET connected
1504 			 * address */
1505 			/* it must have lager IPv4 address value than the lookup
1506 			 * entry */
1507 			if ((ospf_snmp_is_if_have_addr(osif->ifp))
1508 			    && (ntohl(osif->addr.s_addr)
1509 				> ntohl(ifaddr->s_addr))) {
1510 				*ifaddr = osif->addr;
1511 				*ifindex = osif->ifindex;
1512 
1513 				/* and it must be an OSPF interface */
1514 				oi = ospf_if_lookup_by_local_addr(
1515 					ospf, osif->ifp, *ifaddr);
1516 				if (oi)
1517 					return oi;
1518 			}
1519 		}
1520 		/* Unnumbered interface */
1521 		else
1522 			/* The interface must NOT have valid AF_INET connected
1523 			   address */
1524 			/* it must have lager interface index than the lookup
1525 			   entry */
1526 			if ((!ospf_snmp_is_if_have_addr(osif->ifp))
1527 			    && (osif->ifindex > *ifindex)) {
1528 			*ifaddr = osif->addr;
1529 			*ifindex = osif->ifindex;
1530 
1531 			/* and it must be an OSPF interface */
1532 			oi = ospf_if_lookup_by_local_addr(ospf, osif->ifp,
1533 							  *ifaddr);
1534 			if (oi)
1535 				return oi;
1536 		}
1537 	}
1538 	return NULL;
1539 }
1540 
ospf_snmp_iftype(struct interface * ifp)1541 static int ospf_snmp_iftype(struct interface *ifp)
1542 {
1543 #define ospf_snmp_iftype_broadcast         1
1544 #define ospf_snmp_iftype_nbma              2
1545 #define ospf_snmp_iftype_pointToPoint      3
1546 #define ospf_snmp_iftype_pointToMultipoint 5
1547 	if (if_is_broadcast(ifp))
1548 		return ospf_snmp_iftype_broadcast;
1549 	if (if_is_pointopoint(ifp))
1550 		return ospf_snmp_iftype_pointToPoint;
1551 	return ospf_snmp_iftype_broadcast;
1552 }
1553 
ospfIfLookup(struct variable * v,oid * name,size_t * length,struct in_addr * ifaddr,ifindex_t * ifindex,int exact)1554 static struct ospf_interface *ospfIfLookup(struct variable *v, oid *name,
1555 					   size_t *length,
1556 					   struct in_addr *ifaddr,
1557 					   ifindex_t *ifindex, int exact)
1558 {
1559 	unsigned int len;
1560 	int ifaddr_next = 0;
1561 	ifindex_t ifindex_next = 0;
1562 	struct ospf_interface *oi;
1563 	oid *offset;
1564 
1565 	if (exact) {
1566 		if (*length != v->namelen + IN_ADDR_SIZE + 1)
1567 			return NULL;
1568 
1569 		oid2in_addr(name + v->namelen, IN_ADDR_SIZE, ifaddr);
1570 		*ifindex = name[v->namelen + IN_ADDR_SIZE];
1571 
1572 		return ospf_snmp_if_lookup(ifaddr, ifindex);
1573 	} else {
1574 		len = *length - v->namelen;
1575 		if (len >= IN_ADDR_SIZE)
1576 			len = IN_ADDR_SIZE;
1577 		if (len == 0)
1578 			ifaddr_next = 1;
1579 
1580 		oid2in_addr(name + v->namelen, len, ifaddr);
1581 
1582 		len = *length - v->namelen - IN_ADDR_SIZE;
1583 		if (len >= 1)
1584 			len = 1;
1585 		else
1586 			ifindex_next = 1;
1587 
1588 		if (len == 1)
1589 			*ifindex = name[v->namelen + IN_ADDR_SIZE];
1590 
1591 		oi = ospf_snmp_if_lookup_next(ifaddr, ifindex, ifaddr_next,
1592 					      ifindex_next);
1593 		if (oi) {
1594 			*length = v->namelen + IN_ADDR_SIZE + 1;
1595 			offset = name + v->namelen;
1596 			oid_copy_addr(offset, ifaddr, IN_ADDR_SIZE);
1597 			offset += IN_ADDR_SIZE;
1598 			*offset = *ifindex;
1599 			return oi;
1600 		}
1601 	}
1602 	return NULL;
1603 }
1604 
ospfIfEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)1605 static uint8_t *ospfIfEntry(struct variable *v, oid *name, size_t *length,
1606 			    int exact, size_t *var_len,
1607 			    WriteMethod **write_method)
1608 {
1609 	ifindex_t ifindex;
1610 	struct in_addr ifaddr;
1611 	struct ospf_interface *oi;
1612 	struct ospf *ospf;
1613 
1614 	if (smux_header_table(v, name, length, exact, var_len, write_method)
1615 	    == MATCH_FAILED)
1616 		return NULL;
1617 
1618 	ifindex = 0;
1619 	memset(&ifaddr, 0, sizeof(struct in_addr));
1620 
1621 	/* Check OSPF instance. */
1622 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1623 	if (ospf == NULL)
1624 		return NULL;
1625 
1626 	oi = ospfIfLookup(v, name, length, &ifaddr, &ifindex, exact);
1627 	if (oi == NULL)
1628 		return NULL;
1629 
1630 	/* Return the current value of the variable */
1631 	switch (v->magic) {
1632 	case OSPFIFIPADDRESS: /* 1 */
1633 		return SNMP_IPADDRESS(ifaddr);
1634 	case OSPFADDRESSLESSIF: /* 2 */
1635 		return SNMP_INTEGER(ifindex);
1636 	case OSPFIFAREAID: /* 3 */
1637 		if (oi->area)
1638 			return SNMP_IPADDRESS(oi->area->area_id);
1639 		else
1640 			return SNMP_IPADDRESS(ospf_empty_addr);
1641 	case OSPFIFTYPE: /* 4 */
1642 		return SNMP_INTEGER(ospf_snmp_iftype(oi->ifp));
1643 	case OSPFIFADMINSTAT: /* 5 */
1644 		if (oi)
1645 			return SNMP_INTEGER(OSPF_STATUS_ENABLED);
1646 		else
1647 			return SNMP_INTEGER(OSPF_STATUS_DISABLED);
1648 	case OSPFIFRTRPRIORITY: /* 6 */
1649 		return SNMP_INTEGER(PRIORITY(oi));
1650 	case OSPFIFTRANSITDELAY: /* 7 */
1651 		return SNMP_INTEGER(OSPF_IF_PARAM(oi, transmit_delay));
1652 	case OSPFIFRETRANSINTERVAL: /* 8 */
1653 		return SNMP_INTEGER(OSPF_IF_PARAM(oi, retransmit_interval));
1654 	case OSPFIFHELLOINTERVAL: /* 9 */
1655 		return SNMP_INTEGER(OSPF_IF_PARAM(oi, v_hello));
1656 	case OSPFIFRTRDEADINTERVAL: /* 10 */
1657 		return SNMP_INTEGER(OSPF_IF_PARAM(oi, v_wait));
1658 	case OSPFIFPOLLINTERVAL: /* 11 */
1659 		return SNMP_INTEGER(OSPF_POLL_INTERVAL_DEFAULT);
1660 	case OSPFIFSTATE: /* 12 */
1661 		return SNMP_INTEGER(ISM_SNMP(oi->state));
1662 	case OSPFIFDESIGNATEDROUTER: /* 13 */
1663 		return SNMP_IPADDRESS(DR(oi));
1664 	case OSPFIFBACKUPDESIGNATEDROUTER: /* 14 */
1665 		return SNMP_IPADDRESS(BDR(oi));
1666 	case OSPFIFEVENTS: /* 15 */
1667 		return SNMP_INTEGER(oi->state_change);
1668 	case OSPFIFAUTHKEY: /* 16 */
1669 		*var_len = 0;
1670 		return (uint8_t *)OSPF_IF_PARAM(oi, auth_simple);
1671 	case OSPFIFSTATUS: /* 17 */
1672 		return SNMP_INTEGER(SNMP_VALID);
1673 	case OSPFIFMULTICASTFORWARDING: /* 18 */
1674 #define ospf_snmp_multiforward_blocked    1
1675 #define ospf_snmp_multiforward_multicast  2
1676 #define ospf_snmp_multiforward_unicast    3
1677 		return SNMP_INTEGER(ospf_snmp_multiforward_blocked);
1678 	case OSPFIFDEMAND: /* 19 */
1679 		return SNMP_INTEGER(SNMP_FALSE);
1680 	case OSPFIFAUTHTYPE: /* 20 */
1681 		if (oi->area)
1682 			return SNMP_INTEGER(oi->area->auth_type);
1683 		else
1684 			return SNMP_INTEGER(0);
1685 	default:
1686 		return NULL;
1687 	}
1688 	return NULL;
1689 }
1690 
1691 #define OSPF_SNMP_METRIC_VALUE 1
1692 
ospfIfMetricLookup(struct variable * v,oid * name,size_t * length,struct in_addr * ifaddr,ifindex_t * ifindex,int exact)1693 static struct ospf_interface *ospfIfMetricLookup(struct variable *v, oid *name,
1694 						 size_t *length,
1695 						 struct in_addr *ifaddr,
1696 						 ifindex_t *ifindex, int exact)
1697 {
1698 	unsigned int len;
1699 	int ifaddr_next = 0;
1700 	ifindex_t ifindex_next = 0;
1701 	struct ospf_interface *oi;
1702 	oid *offset;
1703 	int metric;
1704 
1705 	if (exact) {
1706 		if (*length != v->namelen + IN_ADDR_SIZE + 1 + 1)
1707 			return NULL;
1708 
1709 		oid2in_addr(name + v->namelen, IN_ADDR_SIZE, ifaddr);
1710 		*ifindex = name[v->namelen + IN_ADDR_SIZE];
1711 		metric = name[v->namelen + IN_ADDR_SIZE + 1];
1712 
1713 		if (metric != OSPF_SNMP_METRIC_VALUE)
1714 			return NULL;
1715 
1716 		return ospf_snmp_if_lookup(ifaddr, ifindex);
1717 	} else {
1718 		len = *length - v->namelen;
1719 		if (len >= IN_ADDR_SIZE)
1720 			len = IN_ADDR_SIZE;
1721 		else
1722 			ifaddr_next = 1;
1723 
1724 		oid2in_addr(name + v->namelen, len, ifaddr);
1725 
1726 		len = *length - v->namelen - IN_ADDR_SIZE;
1727 		if (len >= 1)
1728 			len = 1;
1729 		else
1730 			ifindex_next = 1;
1731 
1732 		if (len == 1)
1733 			*ifindex = name[v->namelen + IN_ADDR_SIZE];
1734 
1735 		oi = ospf_snmp_if_lookup_next(ifaddr, ifindex, ifaddr_next,
1736 					      ifindex_next);
1737 		if (oi) {
1738 			*length = v->namelen + IN_ADDR_SIZE + 1 + 1;
1739 			offset = name + v->namelen;
1740 			oid_copy_addr(offset, ifaddr, IN_ADDR_SIZE);
1741 			offset += IN_ADDR_SIZE;
1742 			*offset = *ifindex;
1743 			offset++;
1744 			*offset = OSPF_SNMP_METRIC_VALUE;
1745 			return oi;
1746 		}
1747 	}
1748 	return NULL;
1749 }
1750 
ospfIfMetricEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)1751 static uint8_t *ospfIfMetricEntry(struct variable *v, oid *name, size_t *length,
1752 				  int exact, size_t *var_len,
1753 				  WriteMethod **write_method)
1754 {
1755 	/* Currently we support metric 1 only. */
1756 	ifindex_t ifindex;
1757 	struct in_addr ifaddr;
1758 	struct ospf_interface *oi;
1759 	struct ospf *ospf;
1760 
1761 	if (smux_header_table(v, name, length, exact, var_len, write_method)
1762 	    == MATCH_FAILED)
1763 		return NULL;
1764 
1765 	ifindex = 0;
1766 	memset(&ifaddr, 0, sizeof(struct in_addr));
1767 
1768 	/* Check OSPF instance. */
1769 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
1770 	if (ospf == NULL)
1771 		return NULL;
1772 
1773 	oi = ospfIfMetricLookup(v, name, length, &ifaddr, &ifindex, exact);
1774 	if (oi == NULL)
1775 		return NULL;
1776 
1777 	/* Return the current value of the variable */
1778 	switch (v->magic) {
1779 	case OSPFIFMETRICIPADDRESS:
1780 		return SNMP_IPADDRESS(ifaddr);
1781 	case OSPFIFMETRICADDRESSLESSIF:
1782 		return SNMP_INTEGER(ifindex);
1783 	case OSPFIFMETRICTOS:
1784 		return SNMP_INTEGER(0);
1785 	case OSPFIFMETRICVALUE:
1786 		return SNMP_INTEGER(OSPF_SNMP_METRIC_VALUE);
1787 	case OSPFIFMETRICSTATUS:
1788 		return SNMP_INTEGER(1);
1789 	default:
1790 		return NULL;
1791 	}
1792 	return NULL;
1793 }
1794 
1795 static struct route_table *ospf_snmp_vl_table;
1796 
ospf_snmp_vl_add(struct ospf_vl_data * vl_data)1797 static int ospf_snmp_vl_add(struct ospf_vl_data *vl_data)
1798 {
1799 	struct prefix_ls lp;
1800 	struct route_node *rn;
1801 
1802 	memset(&lp, 0, sizeof(struct prefix_ls));
1803 	lp.family = 0;
1804 	lp.prefixlen = 64;
1805 	lp.id = vl_data->vl_area_id;
1806 	lp.adv_router = vl_data->vl_peer;
1807 
1808 	rn = route_node_get(ospf_snmp_vl_table, (struct prefix *)&lp);
1809 	if (rn->info)
1810 		route_unlock_node(rn);
1811 
1812 	rn->info = vl_data;
1813 	return 0;
1814 }
1815 
ospf_snmp_vl_delete(struct ospf_vl_data * vl_data)1816 static int ospf_snmp_vl_delete(struct ospf_vl_data *vl_data)
1817 {
1818 	struct prefix_ls lp;
1819 	struct route_node *rn;
1820 
1821 	memset(&lp, 0, sizeof(struct prefix_ls));
1822 	lp.family = 0;
1823 	lp.prefixlen = 64;
1824 	lp.id = vl_data->vl_area_id;
1825 	lp.adv_router = vl_data->vl_peer;
1826 
1827 	rn = route_node_lookup(ospf_snmp_vl_table, (struct prefix *)&lp);
1828 	if (!rn)
1829 		return 0;
1830 	rn->info = NULL;
1831 	route_unlock_node(rn);
1832 	route_unlock_node(rn);
1833 	return 0;
1834 }
1835 
ospf_snmp_vl_lookup(struct in_addr * area_id,struct in_addr * neighbor)1836 static struct ospf_vl_data *ospf_snmp_vl_lookup(struct in_addr *area_id,
1837 						struct in_addr *neighbor)
1838 {
1839 	struct prefix_ls lp;
1840 	struct route_node *rn;
1841 	struct ospf_vl_data *vl_data;
1842 
1843 	memset(&lp, 0, sizeof(struct prefix_ls));
1844 	lp.family = 0;
1845 	lp.prefixlen = 64;
1846 	lp.id = *area_id;
1847 	lp.adv_router = *neighbor;
1848 
1849 	rn = route_node_lookup(ospf_snmp_vl_table, (struct prefix *)&lp);
1850 	if (rn) {
1851 		vl_data = rn->info;
1852 		route_unlock_node(rn);
1853 		return vl_data;
1854 	}
1855 	return NULL;
1856 }
1857 
ospf_snmp_vl_lookup_next(struct in_addr * area_id,struct in_addr * neighbor,int first)1858 static struct ospf_vl_data *ospf_snmp_vl_lookup_next(struct in_addr *area_id,
1859 						     struct in_addr *neighbor,
1860 						     int first)
1861 {
1862 	struct prefix_ls lp;
1863 	struct route_node *rn;
1864 	struct ospf_vl_data *vl_data;
1865 
1866 	memset(&lp, 0, sizeof(struct prefix_ls));
1867 	lp.family = 0;
1868 	lp.prefixlen = 64;
1869 	lp.id = *area_id;
1870 	lp.adv_router = *neighbor;
1871 
1872 	if (first)
1873 		rn = route_top(ospf_snmp_vl_table);
1874 	else {
1875 		rn = route_node_get(ospf_snmp_vl_table, (struct prefix *)&lp);
1876 		rn = route_next(rn);
1877 	}
1878 
1879 	for (; rn; rn = route_next(rn))
1880 		if (rn->info)
1881 			break;
1882 
1883 	if (rn && rn->info) {
1884 		vl_data = rn->info;
1885 		*area_id = vl_data->vl_area_id;
1886 		*neighbor = vl_data->vl_peer;
1887 		route_unlock_node(rn);
1888 		return vl_data;
1889 	}
1890 	return NULL;
1891 }
1892 
1893 static struct ospf_vl_data *
ospfVirtIfLookup(struct variable * v,oid * name,size_t * length,struct in_addr * area_id,struct in_addr * neighbor,int exact)1894 ospfVirtIfLookup(struct variable *v, oid *name, size_t *length,
1895 		 struct in_addr *area_id, struct in_addr *neighbor, int exact)
1896 {
1897 	int first;
1898 	unsigned int len;
1899 	struct ospf_vl_data *vl_data;
1900 
1901 	if (exact) {
1902 		if (*length != v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE)
1903 			return NULL;
1904 
1905 		oid2in_addr(name + v->namelen, IN_ADDR_SIZE, area_id);
1906 		oid2in_addr(name + v->namelen + IN_ADDR_SIZE, IN_ADDR_SIZE,
1907 			    neighbor);
1908 
1909 		return ospf_snmp_vl_lookup(area_id, neighbor);
1910 	} else {
1911 		first = 0;
1912 
1913 		len = *length - v->namelen;
1914 		if (len == 0)
1915 			first = 1;
1916 		if (len > IN_ADDR_SIZE)
1917 			len = IN_ADDR_SIZE;
1918 		oid2in_addr(name + v->namelen, len, area_id);
1919 
1920 		len = *length - v->namelen - IN_ADDR_SIZE;
1921 		if (len > IN_ADDR_SIZE)
1922 			len = IN_ADDR_SIZE;
1923 		oid2in_addr(name + v->namelen + IN_ADDR_SIZE, len, neighbor);
1924 
1925 		vl_data = ospf_snmp_vl_lookup_next(area_id, neighbor, first);
1926 
1927 		if (vl_data) {
1928 			*length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE;
1929 			oid_copy_addr(name + v->namelen, area_id, IN_ADDR_SIZE);
1930 			oid_copy_addr(name + v->namelen + IN_ADDR_SIZE,
1931 				      neighbor, IN_ADDR_SIZE);
1932 			return vl_data;
1933 		}
1934 	}
1935 	return NULL;
1936 }
1937 
ospfVirtIfEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)1938 static uint8_t *ospfVirtIfEntry(struct variable *v, oid *name, size_t *length,
1939 				int exact, size_t *var_len,
1940 				WriteMethod **write_method)
1941 {
1942 	struct ospf_vl_data *vl_data;
1943 	struct ospf_interface *oi;
1944 	struct in_addr area_id;
1945 	struct in_addr neighbor;
1946 
1947 	if (smux_header_table(v, name, length, exact, var_len, write_method)
1948 	    == MATCH_FAILED)
1949 		return NULL;
1950 
1951 	memset(&area_id, 0, sizeof(struct in_addr));
1952 	memset(&neighbor, 0, sizeof(struct in_addr));
1953 
1954 	vl_data = ospfVirtIfLookup(v, name, length, &area_id, &neighbor, exact);
1955 	if (!vl_data)
1956 		return NULL;
1957 	oi = vl_data->vl_oi;
1958 	if (!oi)
1959 		return NULL;
1960 
1961 	/* Return the current value of the variable */
1962 	switch (v->magic) {
1963 	case OSPFVIRTIFAREAID:
1964 		return SNMP_IPADDRESS(area_id);
1965 	case OSPFVIRTIFNEIGHBOR:
1966 		return SNMP_IPADDRESS(neighbor);
1967 	case OSPFVIRTIFTRANSITDELAY:
1968 		return SNMP_INTEGER(OSPF_IF_PARAM(oi, transmit_delay));
1969 	case OSPFVIRTIFRETRANSINTERVAL:
1970 		return SNMP_INTEGER(OSPF_IF_PARAM(oi, retransmit_interval));
1971 	case OSPFVIRTIFHELLOINTERVAL:
1972 		return SNMP_INTEGER(OSPF_IF_PARAM(oi, v_hello));
1973 	case OSPFVIRTIFRTRDEADINTERVAL:
1974 		return SNMP_INTEGER(OSPF_IF_PARAM(oi, v_wait));
1975 	case OSPFVIRTIFSTATE:
1976 		return SNMP_INTEGER(oi->state);
1977 	case OSPFVIRTIFEVENTS:
1978 		return SNMP_INTEGER(oi->state_change);
1979 	case OSPFVIRTIFAUTHKEY:
1980 		*var_len = 0;
1981 		return (uint8_t *)OSPF_IF_PARAM(oi, auth_simple);
1982 	case OSPFVIRTIFSTATUS:
1983 		return SNMP_INTEGER(SNMP_VALID);
1984 	case OSPFVIRTIFAUTHTYPE:
1985 		if (oi->area)
1986 			return SNMP_INTEGER(oi->area->auth_type);
1987 		else
1988 			return SNMP_INTEGER(0);
1989 	default:
1990 		return NULL;
1991 	}
1992 	return NULL;
1993 }
1994 
ospf_snmp_nbr_lookup(struct ospf * ospf,struct in_addr * nbr_addr,ifindex_t * ifindex)1995 static struct ospf_neighbor *ospf_snmp_nbr_lookup(struct ospf *ospf,
1996 						  struct in_addr *nbr_addr,
1997 						  ifindex_t *ifindex)
1998 {
1999 	struct listnode *node, *nnode;
2000 	struct ospf_interface *oi;
2001 	struct ospf_neighbor *nbr;
2002 	struct route_node *rn;
2003 
2004 	for (ALL_LIST_ELEMENTS(ospf->oiflist, node, nnode, oi)) {
2005 		for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
2006 			if ((nbr = rn->info) != NULL && nbr != oi->nbr_self
2007 			    /* If EXACT match is needed, provide ALL entry found
2008 					&& nbr->state != NSM_Down
2009 			     */
2010 			    && nbr->src.s_addr != 0) {
2011 				if (IPV4_ADDR_SAME(&nbr->src, nbr_addr)) {
2012 					route_unlock_node(rn);
2013 					return nbr;
2014 				}
2015 			}
2016 	}
2017 	return NULL;
2018 }
2019 
ospf_snmp_nbr_lookup_next(struct in_addr * nbr_addr,ifindex_t * ifindex,int first)2020 static struct ospf_neighbor *ospf_snmp_nbr_lookup_next(struct in_addr *nbr_addr,
2021 						       ifindex_t *ifindex,
2022 						       int first)
2023 {
2024 	struct listnode *nn;
2025 	struct ospf_interface *oi;
2026 	struct ospf_neighbor *nbr;
2027 	struct route_node *rn;
2028 	struct ospf_neighbor *min = NULL;
2029 	struct ospf *ospf;
2030 
2031 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
2032 
2033 	for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, nn, oi)) {
2034 		for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
2035 			if ((nbr = rn->info) != NULL && nbr != oi->nbr_self
2036 			    && nbr->state != NSM_Down && nbr->src.s_addr != 0) {
2037 				if (first) {
2038 					if (!min)
2039 						min = nbr;
2040 					else if (ntohl(nbr->src.s_addr)
2041 						 < ntohl(min->src.s_addr))
2042 						min = nbr;
2043 				} else if (ntohl(nbr->src.s_addr)
2044 					   > ntohl(nbr_addr->s_addr)) {
2045 					if (!min)
2046 						min = nbr;
2047 					else if (ntohl(nbr->src.s_addr)
2048 						 < ntohl(min->src.s_addr))
2049 						min = nbr;
2050 				}
2051 			}
2052 	}
2053 	if (min) {
2054 		*nbr_addr = min->src;
2055 		*ifindex = 0;
2056 		return min;
2057 	}
2058 	return NULL;
2059 }
2060 
ospfNbrLookup(struct variable * v,oid * name,size_t * length,struct in_addr * nbr_addr,ifindex_t * ifindex,int exact)2061 static struct ospf_neighbor *ospfNbrLookup(struct variable *v, oid *name,
2062 					   size_t *length,
2063 					   struct in_addr *nbr_addr,
2064 					   ifindex_t *ifindex, int exact)
2065 {
2066 	unsigned int len;
2067 	int first;
2068 	struct ospf_neighbor *nbr;
2069 	struct ospf *ospf;
2070 
2071 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
2072 
2073 	if (!ospf)
2074 		return NULL;
2075 
2076 	if (exact) {
2077 		if (*length != v->namelen + IN_ADDR_SIZE + 1)
2078 			return NULL;
2079 
2080 		oid2in_addr(name + v->namelen, IN_ADDR_SIZE, nbr_addr);
2081 		*ifindex = name[v->namelen + IN_ADDR_SIZE];
2082 
2083 		return ospf_snmp_nbr_lookup(ospf, nbr_addr, ifindex);
2084 	} else {
2085 		first = 0;
2086 		len = *length - v->namelen;
2087 
2088 		if (len == 0)
2089 			first = 1;
2090 
2091 		if (len > IN_ADDR_SIZE)
2092 			len = IN_ADDR_SIZE;
2093 
2094 		oid2in_addr(name + v->namelen, len, nbr_addr);
2095 
2096 		len = *length - v->namelen - IN_ADDR_SIZE;
2097 		if (len >= 1)
2098 			*ifindex = name[v->namelen + IN_ADDR_SIZE];
2099 
2100 		nbr = ospf_snmp_nbr_lookup_next(nbr_addr, ifindex, first);
2101 
2102 		if (nbr) {
2103 			*length = v->namelen + IN_ADDR_SIZE + 1;
2104 			oid_copy_addr(name + v->namelen, nbr_addr,
2105 				      IN_ADDR_SIZE);
2106 			name[v->namelen + IN_ADDR_SIZE] = *ifindex;
2107 			return nbr;
2108 		}
2109 	}
2110 	return NULL;
2111 }
2112 
2113 /* map internal quagga neighbor states to official MIB values:
2114 
2115 ospfNbrState OBJECT-TYPE
2116 	SYNTAX   INTEGER    {
2117 		    down (1),
2118 		    attempt (2),
2119 		    init (3),
2120 		    twoWay (4),
2121 		    exchangeStart (5),
2122 		    exchange (6),
2123 		    loading (7),
2124 		    full (8)
2125 		  }
2126 */
ospf_snmp_neighbor_state(uint8_t nst)2127 static int32_t ospf_snmp_neighbor_state(uint8_t nst)
2128 {
2129 	switch (nst) {
2130 	case NSM_Attempt:
2131 		return 2;
2132 	case NSM_Init:
2133 		return 3;
2134 	case NSM_TwoWay:
2135 		return 4;
2136 	case NSM_ExStart:
2137 		return 5;
2138 	case NSM_Exchange:
2139 		return 6;
2140 	case NSM_Loading:
2141 		return 7;
2142 	case NSM_Full:
2143 		return 8;
2144 	default:
2145 		return 1; /* down */
2146 	}
2147 }
2148 
ospfNbrEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)2149 static uint8_t *ospfNbrEntry(struct variable *v, oid *name, size_t *length,
2150 			     int exact, size_t *var_len,
2151 			     WriteMethod **write_method)
2152 {
2153 	struct in_addr nbr_addr;
2154 	ifindex_t ifindex;
2155 	struct ospf_neighbor *nbr;
2156 	struct ospf_interface *oi;
2157 
2158 	if (smux_header_table(v, name, length, exact, var_len, write_method)
2159 	    == MATCH_FAILED)
2160 		return NULL;
2161 
2162 	memset(&nbr_addr, 0, sizeof(struct in_addr));
2163 	ifindex = 0;
2164 
2165 	nbr = ospfNbrLookup(v, name, length, &nbr_addr, &ifindex, exact);
2166 	if (!nbr)
2167 		return NULL;
2168 	oi = nbr->oi;
2169 
2170 	/* Return the current value of the variable */
2171 	switch (v->magic) {
2172 	case OSPFNBRIPADDR:
2173 		return SNMP_IPADDRESS(nbr_addr);
2174 	case OSPFNBRADDRESSLESSINDEX:
2175 		return SNMP_INTEGER(ifindex);
2176 	case OSPFNBRRTRID:
2177 		return SNMP_IPADDRESS(nbr->router_id);
2178 	case OSPFNBROPTIONS:
2179 		return SNMP_INTEGER(oi->nbr_self->options);
2180 	case OSPFNBRPRIORITY:
2181 		return SNMP_INTEGER(nbr->priority);
2182 	case OSPFNBRSTATE:
2183 		return SNMP_INTEGER(ospf_snmp_neighbor_state(nbr->state));
2184 	case OSPFNBREVENTS:
2185 		return SNMP_INTEGER(nbr->state_change);
2186 	case OSPFNBRLSRETRANSQLEN:
2187 		return SNMP_INTEGER(ospf_ls_retransmit_count(nbr));
2188 	case OSPFNBMANBRSTATUS:
2189 		return SNMP_INTEGER(SNMP_VALID);
2190 	case OSPFNBMANBRPERMANENCE:
2191 		return SNMP_INTEGER(2);
2192 	case OSPFNBRHELLOSUPPRESSED:
2193 		return SNMP_INTEGER(SNMP_FALSE);
2194 	default:
2195 		return NULL;
2196 	}
2197 	return NULL;
2198 }
2199 
ospfVirtNbrEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)2200 static uint8_t *ospfVirtNbrEntry(struct variable *v, oid *name, size_t *length,
2201 				 int exact, size_t *var_len,
2202 				 WriteMethod **write_method)
2203 {
2204 	struct ospf_vl_data *vl_data;
2205 	struct in_addr area_id;
2206 	struct in_addr neighbor;
2207 	struct ospf *ospf;
2208 
2209 	if (smux_header_table(v, name, length, exact, var_len, write_method)
2210 	    == MATCH_FAILED)
2211 		return NULL;
2212 
2213 	memset(&area_id, 0, sizeof(struct in_addr));
2214 	memset(&neighbor, 0, sizeof(struct in_addr));
2215 
2216 	/* Check OSPF instance. */
2217 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
2218 	if (ospf == NULL)
2219 		return NULL;
2220 
2221 	vl_data = ospfVirtIfLookup(v, name, length, &area_id, &neighbor, exact);
2222 	if (!vl_data)
2223 		return NULL;
2224 
2225 	/* Return the current value of the variable */
2226 	switch (v->magic) {
2227 	case OSPFVIRTNBRAREA:
2228 		return (uint8_t *)NULL;
2229 	case OSPFVIRTNBRRTRID:
2230 		return (uint8_t *)NULL;
2231 	case OSPFVIRTNBRIPADDR:
2232 		return (uint8_t *)NULL;
2233 	case OSPFVIRTNBROPTIONS:
2234 		return (uint8_t *)NULL;
2235 	case OSPFVIRTNBRSTATE:
2236 		return (uint8_t *)NULL;
2237 	case OSPFVIRTNBREVENTS:
2238 		return (uint8_t *)NULL;
2239 	case OSPFVIRTNBRLSRETRANSQLEN:
2240 		return (uint8_t *)NULL;
2241 	case OSPFVIRTNBRHELLOSUPPRESSED:
2242 		return (uint8_t *)NULL;
2243 	default:
2244 		return NULL;
2245 	}
2246 	return NULL;
2247 }
2248 
ospfExtLsdbLookup(struct variable * v,oid * name,size_t * length,uint8_t * type,struct in_addr * ls_id,struct in_addr * router_id,int exact)2249 static struct ospf_lsa *ospfExtLsdbLookup(struct variable *v, oid *name,
2250 					  size_t *length, uint8_t *type,
2251 					  struct in_addr *ls_id,
2252 					  struct in_addr *router_id, int exact)
2253 {
2254 	int first;
2255 	oid *offset;
2256 	int offsetlen;
2257 	uint8_t lsa_type;
2258 	unsigned int len;
2259 	struct ospf_lsa *lsa;
2260 	struct ospf *ospf;
2261 
2262 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
2263 	if (exact) {
2264 		if (*length != v->namelen + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE)
2265 			return NULL;
2266 
2267 		offset = name + v->namelen;
2268 
2269 		/* Make it sure given value match to type. */
2270 		lsa_type = *offset;
2271 		offset++;
2272 
2273 		if (lsa_type != *type)
2274 			return NULL;
2275 
2276 		/* LS ID. */
2277 		oid2in_addr(offset, IN_ADDR_SIZE, ls_id);
2278 		offset += IN_ADDR_SIZE;
2279 
2280 		/* Router ID. */
2281 		oid2in_addr(offset, IN_ADDR_SIZE, router_id);
2282 
2283 		return ospf_lsdb_lookup_by_id(ospf->lsdb, *type, *ls_id,
2284 					      *router_id);
2285 	} else {
2286 		/* Get variable length. */
2287 		first = 0;
2288 		offset = name + v->namelen;
2289 		offsetlen = *length - v->namelen;
2290 
2291 		/* LSA type value. */
2292 		lsa_type = *offset;
2293 		offset++;
2294 		offsetlen--;
2295 
2296 		if (offsetlen <= 0 || lsa_type < OSPF_AS_EXTERNAL_LSA)
2297 			first = 1;
2298 
2299 		/* LS ID. */
2300 		len = offsetlen;
2301 		if (len > IN_ADDR_SIZE)
2302 			len = IN_ADDR_SIZE;
2303 
2304 		oid2in_addr(offset, len, ls_id);
2305 
2306 		offset += IN_ADDR_SIZE;
2307 		offsetlen -= IN_ADDR_SIZE;
2308 
2309 		/* Router ID. */
2310 		len = offsetlen;
2311 		if (len > IN_ADDR_SIZE)
2312 			len = IN_ADDR_SIZE;
2313 
2314 		oid2in_addr(offset, len, router_id);
2315 
2316 		lsa = ospf_lsdb_lookup_by_id_next(ospf->lsdb, *type, *ls_id,
2317 						  *router_id, first);
2318 
2319 		if (lsa) {
2320 			/* Fill in length. */
2321 			*length = v->namelen + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE;
2322 
2323 			/* Fill in value. */
2324 			offset = name + v->namelen;
2325 
2326 			*offset = OSPF_AS_EXTERNAL_LSA;
2327 			offset++;
2328 			oid_copy_addr(offset, &lsa->data->id, IN_ADDR_SIZE);
2329 			offset += IN_ADDR_SIZE;
2330 			oid_copy_addr(offset, &lsa->data->adv_router,
2331 				      IN_ADDR_SIZE);
2332 
2333 			return lsa;
2334 		}
2335 	}
2336 	return NULL;
2337 }
2338 
ospfExtLsdbEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)2339 static uint8_t *ospfExtLsdbEntry(struct variable *v, oid *name, size_t *length,
2340 				 int exact, size_t *var_len,
2341 				 WriteMethod **write_method)
2342 {
2343 	struct ospf_lsa *lsa;
2344 	struct lsa_header *lsah;
2345 	uint8_t type;
2346 	struct in_addr ls_id;
2347 	struct in_addr router_id;
2348 	struct ospf *ospf;
2349 
2350 	if (smux_header_table(v, name, length, exact, var_len, write_method)
2351 	    == MATCH_FAILED)
2352 		return NULL;
2353 
2354 	type = OSPF_AS_EXTERNAL_LSA;
2355 	memset(&ls_id, 0, sizeof(struct in_addr));
2356 	memset(&router_id, 0, sizeof(struct in_addr));
2357 
2358 	/* Check OSPF instance. */
2359 	ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
2360 	if (ospf == NULL)
2361 		return NULL;
2362 
2363 	lsa = ospfExtLsdbLookup(v, name, length, &type, &ls_id, &router_id,
2364 				exact);
2365 	if (!lsa)
2366 		return NULL;
2367 
2368 	lsah = lsa->data;
2369 
2370 	/* Return the current value of the variable */
2371 	switch (v->magic) {
2372 	case OSPFEXTLSDBTYPE:
2373 		return SNMP_INTEGER(OSPF_AS_EXTERNAL_LSA);
2374 	case OSPFEXTLSDBLSID:
2375 		return SNMP_IPADDRESS(lsah->id);
2376 	case OSPFEXTLSDBROUTERID:
2377 		return SNMP_IPADDRESS(lsah->adv_router);
2378 	case OSPFEXTLSDBSEQUENCE:
2379 		return SNMP_INTEGER(lsah->ls_seqnum);
2380 	case OSPFEXTLSDBAGE:
2381 		return SNMP_INTEGER(lsah->ls_age);
2382 	case OSPFEXTLSDBCHECKSUM:
2383 		return SNMP_INTEGER(lsah->checksum);
2384 	case OSPFEXTLSDBADVERTISEMENT:
2385 		*var_len = ntohs(lsah->length);
2386 		return (uint8_t *)lsah;
2387 	default:
2388 		return NULL;
2389 	}
2390 	return NULL;
2391 }
2392 
ospfAreaAggregateEntry(struct variable * v,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)2393 static uint8_t *ospfAreaAggregateEntry(struct variable *v, oid *name,
2394 				       size_t *length, int exact,
2395 				       size_t *var_len,
2396 				       WriteMethod **write_method)
2397 {
2398 	if (smux_header_table(v, name, length, exact, var_len, write_method)
2399 	    == MATCH_FAILED)
2400 		return NULL;
2401 
2402 	/* Return the current value of the variable */
2403 	switch (v->magic) {
2404 	case OSPFAREAAGGREGATEAREAID:
2405 		return (uint8_t *)NULL;
2406 	case OSPFAREAAGGREGATELSDBTYPE:
2407 		return (uint8_t *)NULL;
2408 	case OSPFAREAAGGREGATENET:
2409 		return (uint8_t *)NULL;
2410 	case OSPFAREAAGGREGATEMASK:
2411 		return (uint8_t *)NULL;
2412 	case OSPFAREAAGGREGATESTATUS:
2413 		return (uint8_t *)NULL;
2414 	case OSPFAREAAGGREGATEEFFECT:
2415 		return (uint8_t *)NULL;
2416 	default:
2417 		return NULL;
2418 	}
2419 	return NULL;
2420 }
2421 
2422 /* OSPF Traps. */
2423 #define IFSTATECHANGE      16
2424 #define VIRTIFSTATECHANGE   1
2425 #define NBRSTATECHANGE      2
2426 #define VIRTNBRSTATECHANGE  3
2427 
2428 static struct trap_object ospfNbrTrapList[] = {{-2, {1, OSPFROUTERID}},
2429 					       {3, {10, 1, OSPFNBRIPADDR}},
2430 					       {3, {10, 1, OSPFNBRRTRID}},
2431 					       {3, {10, 1, OSPFNBRSTATE}}};
2432 
2433 
2434 static struct trap_object ospfVirtNbrTrapList[] = {
2435 	{-2, {1, 1}},
2436 	{3, {11, 1, OSPFVIRTNBRAREA}},
2437 	{3, {11, 1, OSPFVIRTNBRRTRID}},
2438 	{3, {11, 1, OSPFVIRTNBRSTATE}}};
2439 
2440 static struct trap_object ospfIfTrapList[] = {{-2, {1, OSPFROUTERID}},
2441 					      {3, {7, 1, OSPFIFIPADDRESS}},
2442 					      {3, {7, 1, OSPFADDRESSLESSIF}},
2443 					      {3, {7, 1, OSPFIFSTATE}}};
2444 
2445 static struct trap_object ospfVirtIfTrapList[] = {
2446 	{-2, {1, OSPFROUTERID}},
2447 	{3, {9, 1, OSPFVIRTIFAREAID}},
2448 	{3, {9, 1, OSPFVIRTIFNEIGHBOR}},
2449 	{3, {9, 1, OSPFVIRTIFSTATE}}};
2450 
ospfTrapNbrStateChange(struct ospf_neighbor * on)2451 static void ospfTrapNbrStateChange(struct ospf_neighbor *on)
2452 {
2453 	oid index[sizeof(oid) * (IN_ADDR_SIZE + 1)];
2454 	char msgbuf[16];
2455 
2456 	ospf_nbr_state_message(on, msgbuf, sizeof(msgbuf));
2457 	if (IS_DEBUG_OSPF_EVENT)
2458 		zlog_info("%s: trap sent: %s now %s", __func__,
2459 			  inet_ntoa(on->address.u.prefix4), msgbuf);
2460 
2461 	oid_copy_addr(index, &(on->address.u.prefix4), IN_ADDR_SIZE);
2462 	index[IN_ADDR_SIZE] = 0;
2463 
2464 	smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid,
2465 		  array_size(ospf_trap_oid), ospf_oid,
2466 		  sizeof(ospf_oid) / sizeof(oid), index, IN_ADDR_SIZE + 1,
2467 		  ospfNbrTrapList, array_size(ospfNbrTrapList), NBRSTATECHANGE);
2468 }
2469 
ospfTrapVirtNbrStateChange(struct ospf_neighbor * on)2470 static void ospfTrapVirtNbrStateChange(struct ospf_neighbor *on)
2471 {
2472 	oid index[sizeof(oid) * (IN_ADDR_SIZE + 1)];
2473 
2474 	zlog_info("ospfTrapVirtNbrStateChange trap sent");
2475 
2476 	oid_copy_addr(index, &(on->address.u.prefix4), IN_ADDR_SIZE);
2477 	index[IN_ADDR_SIZE] = 0;
2478 
2479 	smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid,
2480 		  array_size(ospf_trap_oid), ospf_oid,
2481 		  sizeof(ospf_oid) / sizeof(oid), index, IN_ADDR_SIZE + 1,
2482 		  ospfVirtNbrTrapList, array_size(ospfVirtNbrTrapList),
2483 		  VIRTNBRSTATECHANGE);
2484 }
2485 
ospf_snmp_nsm_change(struct ospf_neighbor * nbr,int next_state,int old_state)2486 static int ospf_snmp_nsm_change(struct ospf_neighbor *nbr, int next_state,
2487 				int old_state)
2488 {
2489 	/* Terminal state or regression */
2490 	if ((next_state == NSM_Full) || (next_state == NSM_TwoWay)
2491 	    || (next_state < old_state)) {
2492 		/* ospfVirtNbrStateChange */
2493 		if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK)
2494 			ospfTrapVirtNbrStateChange(nbr);
2495 		/* ospfNbrStateChange trap  */
2496 		else
2497 			/* To/From FULL, only managed by DR */
2498 			if (((next_state != NSM_Full)
2499 			     && (nbr->state != NSM_Full))
2500 			    || (nbr->oi->state == ISM_DR))
2501 			ospfTrapNbrStateChange(nbr);
2502 	}
2503 	return 0;
2504 }
2505 
ospfTrapIfStateChange(struct ospf_interface * oi)2506 static void ospfTrapIfStateChange(struct ospf_interface *oi)
2507 {
2508 	oid index[sizeof(oid) * (IN_ADDR_SIZE + 1)];
2509 
2510 	if (IS_DEBUG_OSPF_EVENT)
2511 		zlog_info("%s: trap sent: %s now %s", __func__,
2512 			  inet_ntoa(oi->address->u.prefix4),
2513 			  lookup_msg(ospf_ism_state_msg, oi->state, NULL));
2514 
2515 	oid_copy_addr(index, &(oi->address->u.prefix4), IN_ADDR_SIZE);
2516 	index[IN_ADDR_SIZE] = 0;
2517 
2518 	smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid,
2519 		  array_size(ospf_trap_oid), ospf_oid,
2520 		  sizeof(ospf_oid) / sizeof(oid), index, IN_ADDR_SIZE + 1,
2521 		  ospfIfTrapList, array_size(ospfIfTrapList), IFSTATECHANGE);
2522 }
2523 
ospfTrapVirtIfStateChange(struct ospf_interface * oi)2524 static void ospfTrapVirtIfStateChange(struct ospf_interface *oi)
2525 {
2526 	oid index[sizeof(oid) * (IN_ADDR_SIZE + 1)];
2527 
2528 	zlog_info("ospfTrapVirtIfStateChange trap sent");
2529 
2530 	oid_copy_addr(index, &(oi->address->u.prefix4), IN_ADDR_SIZE);
2531 	index[IN_ADDR_SIZE] = 0;
2532 
2533 	smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid,
2534 		  array_size(ospf_trap_oid), ospf_oid,
2535 		  sizeof(ospf_oid) / sizeof(oid), index, IN_ADDR_SIZE + 1,
2536 		  ospfVirtIfTrapList, array_size(ospfVirtIfTrapList),
2537 		  VIRTIFSTATECHANGE);
2538 }
2539 
ospf_snmp_ism_change(struct ospf_interface * oi,int state,int old_state)2540 static int ospf_snmp_ism_change(struct ospf_interface *oi, int state,
2541 				int old_state)
2542 {
2543 	/* Terminal state or regression */
2544 	if ((state == ISM_DR) || (state == ISM_Backup) || (state == ISM_DROther)
2545 	    || (state == ISM_PointToPoint) || (state < old_state)) {
2546 		/* ospfVirtIfStateChange */
2547 		if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
2548 			ospfTrapVirtIfStateChange(oi);
2549 		/* ospfIfStateChange */
2550 		else
2551 			ospfTrapIfStateChange(oi);
2552 	}
2553 	return 0;
2554 }
2555 
2556 /* Register OSPF2-MIB. */
ospf_snmp_init(struct thread_master * tm)2557 static int ospf_snmp_init(struct thread_master *tm)
2558 {
2559 	ospf_snmp_iflist = list_new();
2560 	ospf_snmp_vl_table = route_table_init();
2561 	smux_init(tm);
2562 	REGISTER_MIB("mibII/ospf", ospf_variables, variable, ospf_oid);
2563 	return 0;
2564 }
2565 
ospf_snmp_module_init(void)2566 static int ospf_snmp_module_init(void)
2567 {
2568 	hook_register(ospf_if_update, ospf_snmp_if_update);
2569 	hook_register(ospf_if_delete, ospf_snmp_if_delete);
2570 	hook_register(ospf_vl_add, ospf_snmp_vl_add);
2571 	hook_register(ospf_vl_delete, ospf_snmp_vl_delete);
2572 	hook_register(ospf_ism_change, ospf_snmp_ism_change);
2573 	hook_register(ospf_nsm_change, ospf_snmp_nsm_change);
2574 
2575 	hook_register(frr_late_init, ospf_snmp_init);
2576 	return 0;
2577 }
2578 
2579 FRR_MODULE_SETUP(.name = "ospfd_snmp", .version = FRR_VERSION,
2580 		 .description = "ospfd AgentX SNMP module",
2581 		 .init = ospf_snmp_module_init, )
2582