1 /*
2  * Client side of OSPF API.
3  * Copyright (C) 2001, 2002, 2003 Ralph Keller
4  *
5  * This file is part of GNU Zebra.
6  *
7  * GNU Zebra is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published
9  * by the Free Software Foundation; either version 2, or (at your
10  * option) any later version.
11  *
12  * GNU Zebra is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; see the file COPYING; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include <zebra.h>
23 
24 #include <lib/version.h>
25 #include "getopt.h"
26 #include "thread.h"
27 #include "prefix.h"
28 #include "linklist.h"
29 #include "if.h"
30 #include "vector.h"
31 #include "vty.h"
32 #include "command.h"
33 #include "filter.h"
34 #include "stream.h"
35 #include "log.h"
36 #include "memory.h"
37 
38 /* work around gcc bug 69981, disable MTYPEs in libospf */
39 #define _QUAGGA_OSPF_MEMORY_H
40 
41 #include "ospfd/ospfd.h"
42 #include "ospfd/ospf_interface.h"
43 #include "ospfd/ospf_asbr.h"
44 #include "ospfd/ospf_lsa.h"
45 #include "ospfd/ospf_opaque.h"
46 #include "ospfd/ospf_lsdb.h"
47 #include "ospfd/ospf_neighbor.h"
48 #include "ospfd/ospf_dump.h"
49 #include "ospfd/ospf_route.h"
50 #include "ospfd/ospf_zebra.h"
51 #include "ospfd/ospf_api.h"
52 
53 #include "ospf_apiclient.h"
54 
55 /* *sigh* ... can't find a better way to hammer this into automake */
56 #include "ospfd/ospf_dump_api.c"
57 #include "ospfd/ospf_api.c"
58 
59 DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient")
60 DEFINE_MTYPE_STATIC(OSPFCLIENT, OSPF_APICLIENT, "OSPF-API client")
61 
62 /* Backlog for listen */
63 #define BACKLOG 5
64 
65 /* -----------------------------------------------------------
66  * Forward declarations
67  * -----------------------------------------------------------
68  */
69 
70 void ospf_apiclient_handle_reply(struct ospf_apiclient *oclient,
71 				 struct msg *msg);
72 void ospf_apiclient_handle_update_notify(struct ospf_apiclient *oclient,
73 					 struct msg *msg);
74 void ospf_apiclient_handle_delete_notify(struct ospf_apiclient *oclient,
75 					 struct msg *msg);
76 
77 /* -----------------------------------------------------------
78  * Initialization
79  * -----------------------------------------------------------
80  */
81 
ospf_apiclient_getport(void)82 static unsigned short ospf_apiclient_getport(void)
83 {
84 	struct servent *sp = getservbyname("ospfapi", "tcp");
85 
86 	return sp ? ntohs(sp->s_port) : OSPF_API_SYNC_PORT;
87 }
88 
89 /* -----------------------------------------------------------
90  * Followings are functions for connection management
91  * -----------------------------------------------------------
92  */
93 
ospf_apiclient_connect(char * host,int syncport)94 struct ospf_apiclient *ospf_apiclient_connect(char *host, int syncport)
95 {
96 	struct sockaddr_in myaddr_sync;
97 	struct sockaddr_in myaddr_async;
98 	struct sockaddr_in peeraddr;
99 	struct hostent *hp;
100 	struct ospf_apiclient *new;
101 	int size = 0;
102 	unsigned int peeraddrlen;
103 	int async_server_sock;
104 	int fd1, fd2;
105 	int ret;
106 	int on = 1;
107 
108 	/* There are two connections between the client and the server.
109 	   First the client opens a connection for synchronous requests/replies
110 	   to the server. The server will accept this connection and
111 	   as a reaction open a reverse connection channel for
112 	   asynchronous messages. */
113 
114 	async_server_sock = socket(AF_INET, SOCK_STREAM, 0);
115 	if (async_server_sock < 0) {
116 		fprintf(stderr,
117 			"ospf_apiclient_connect: creating async socket failed\n");
118 		return NULL;
119 	}
120 
121 	/* Prepare socket for asynchronous messages */
122 	/* Initialize async address structure */
123 	memset(&myaddr_async, 0, sizeof(struct sockaddr_in));
124 	myaddr_async.sin_family = AF_INET;
125 	myaddr_async.sin_addr.s_addr = htonl(INADDR_ANY);
126 	myaddr_async.sin_port = htons(syncport + 1);
127 	size = sizeof(struct sockaddr_in);
128 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
129 	myaddr_async.sin_len = size;
130 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
131 
132 	/* This is a server socket, reuse addr and port */
133 	ret = setsockopt(async_server_sock, SOL_SOCKET, SO_REUSEADDR,
134 			 (void *)&on, sizeof(on));
135 	if (ret < 0) {
136 		fprintf(stderr,
137 			"ospf_apiclient_connect: SO_REUSEADDR failed\n");
138 		close(async_server_sock);
139 		return NULL;
140 	}
141 
142 #ifdef SO_REUSEPORT
143 	ret = setsockopt(async_server_sock, SOL_SOCKET, SO_REUSEPORT,
144 			 (void *)&on, sizeof(on));
145 	if (ret < 0) {
146 		fprintf(stderr,
147 			"ospf_apiclient_connect: SO_REUSEPORT failed\n");
148 		close(async_server_sock);
149 		return NULL;
150 	}
151 #endif /* SO_REUSEPORT */
152 
153 	/* Bind socket to address structure */
154 	ret = bind(async_server_sock, (struct sockaddr *)&myaddr_async, size);
155 	if (ret < 0) {
156 		fprintf(stderr,
157 			"ospf_apiclient_connect: bind async socket failed\n");
158 		close(async_server_sock);
159 		return NULL;
160 	}
161 
162 	/* Wait for reverse channel connection establishment from server */
163 	ret = listen(async_server_sock, BACKLOG);
164 	if (ret < 0) {
165 		fprintf(stderr, "ospf_apiclient_connect: listen: %s\n",
166 			safe_strerror(errno));
167 		close(async_server_sock);
168 		return NULL;
169 	}
170 
171 	/* Make connection for synchronous requests and connect to server */
172 	/* Resolve address of server */
173 	hp = gethostbyname(host);
174 	if (!hp) {
175 		fprintf(stderr, "ospf_apiclient_connect: no such host %s\n",
176 			host);
177 		close(async_server_sock);
178 		return NULL;
179 	}
180 
181 	fd1 = socket(AF_INET, SOCK_STREAM, 0);
182 	if (fd1 < 0) {
183 		close(async_server_sock);
184 		fprintf(stderr,
185 			"ospf_apiclient_connect: creating sync socket failed\n");
186 		return NULL;
187 	}
188 
189 
190 	/* Reuse addr and port */
191 	ret = setsockopt(fd1, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
192 			 sizeof(on));
193 	if (ret < 0) {
194 		fprintf(stderr,
195 			"ospf_apiclient_connect: SO_REUSEADDR failed\n");
196 		close(fd1);
197 		close(async_server_sock);
198 		return NULL;
199 	}
200 
201 #ifdef SO_REUSEPORT
202 	ret = setsockopt(fd1, SOL_SOCKET, SO_REUSEPORT, (void *)&on,
203 			 sizeof(on));
204 	if (ret < 0) {
205 		fprintf(stderr,
206 			"ospf_apiclient_connect: SO_REUSEPORT failed\n");
207 		close(fd1);
208 		close(async_server_sock);
209 		return NULL;
210 	}
211 #endif /* SO_REUSEPORT */
212 
213 
214 	/* Bind sync socket to address structure. This is needed since we
215 	   want the sync port number on a fixed port number. The reverse
216 	   async channel will be at this port+1 */
217 
218 	memset(&myaddr_sync, 0, sizeof(struct sockaddr_in));
219 	myaddr_sync.sin_family = AF_INET;
220 	myaddr_sync.sin_port = htons(syncport);
221 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
222 	myaddr_sync.sin_len = sizeof(struct sockaddr_in);
223 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
224 
225 	ret = bind(fd1, (struct sockaddr *)&myaddr_sync, size);
226 	if (ret < 0) {
227 		fprintf(stderr,
228 			"ospf_apiclient_connect: bind sync socket failed\n");
229 		close(fd1);
230 		close(async_server_sock);
231 		return NULL;
232 	}
233 
234 	/* Prepare address structure for connect */
235 	memcpy(&myaddr_sync.sin_addr, hp->h_addr, hp->h_length);
236 	myaddr_sync.sin_family = AF_INET;
237 	myaddr_sync.sin_port = htons(ospf_apiclient_getport());
238 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
239 	myaddr_sync.sin_len = sizeof(struct sockaddr_in);
240 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
241 
242 	/* Now establish synchronous channel with OSPF daemon */
243 	ret = connect(fd1, (struct sockaddr *)&myaddr_sync,
244 		      sizeof(struct sockaddr_in));
245 	if (ret < 0) {
246 		fprintf(stderr,
247 			"ospf_apiclient_connect: sync connect failed\n");
248 		close(async_server_sock);
249 		close(fd1);
250 		return NULL;
251 	}
252 
253 	/* Accept reverse connection */
254 	peeraddrlen = sizeof(struct sockaddr_in);
255 	memset(&peeraddr, 0, peeraddrlen);
256 
257 	fd2 = accept(async_server_sock, (struct sockaddr *)&peeraddr,
258 		     &peeraddrlen);
259 	if (fd2 < 0) {
260 		fprintf(stderr,
261 			"ospf_apiclient_connect: accept async failed\n");
262 		close(async_server_sock);
263 		close(fd1);
264 		close(fd2);
265 		return NULL;
266 	}
267 
268 	/* Server socket is not needed anymore since we are not accepting more
269 	   connections */
270 	close(async_server_sock);
271 
272 	/* Create new client-side instance */
273 	new = XCALLOC(MTYPE_OSPF_APICLIENT, sizeof(struct ospf_apiclient));
274 
275 	/* Initialize socket descriptors for sync and async channels */
276 	new->fd_sync = fd1;
277 	new->fd_async = fd2;
278 
279 	return new;
280 }
281 
ospf_apiclient_close(struct ospf_apiclient * oclient)282 int ospf_apiclient_close(struct ospf_apiclient *oclient)
283 {
284 
285 	if (oclient->fd_sync >= 0) {
286 		close(oclient->fd_sync);
287 	}
288 
289 	if (oclient->fd_async >= 0) {
290 		close(oclient->fd_async);
291 	}
292 
293 	/* Free client structure */
294 	XFREE(MTYPE_OSPF_APICLIENT, oclient);
295 	return 0;
296 }
297 
298 /* -----------------------------------------------------------
299  * Followings are functions to send a request to OSPFd
300  * -----------------------------------------------------------
301  */
302 
303 /* Send synchronous request, wait for reply */
ospf_apiclient_send_request(struct ospf_apiclient * oclient,struct msg * msg)304 static int ospf_apiclient_send_request(struct ospf_apiclient *oclient,
305 				       struct msg *msg)
306 {
307 	uint32_t reqseq;
308 	struct msg_reply *msgreply;
309 	int rc;
310 
311 	/* NB: Given "msg" is freed inside this function. */
312 
313 	/* Remember the sequence number of the request */
314 	reqseq = ntohl(msg->hdr.msgseq);
315 
316 	/* Write message to OSPFd */
317 	rc = msg_write(oclient->fd_sync, msg);
318 	msg_free(msg);
319 
320 	if (rc < 0) {
321 		return -1;
322 	}
323 
324 	/* Wait for reply */ /* NB: New "msg" is allocated by "msg_read()". */
325 	msg = msg_read(oclient->fd_sync);
326 	if (!msg)
327 		return -1;
328 
329 	assert(msg->hdr.msgtype == MSG_REPLY);
330 	assert(ntohl(msg->hdr.msgseq) == reqseq);
331 
332 	msgreply = (struct msg_reply *)STREAM_DATA(msg->s);
333 	rc = msgreply->errcode;
334 	msg_free(msg);
335 
336 	return rc;
337 }
338 
339 
340 /* -----------------------------------------------------------
341  * Helper functions
342  * -----------------------------------------------------------
343  */
344 
ospf_apiclient_get_seqnr(void)345 static uint32_t ospf_apiclient_get_seqnr(void)
346 {
347 	static uint32_t seqnr = MIN_SEQ;
348 	uint32_t tmp;
349 
350 	tmp = seqnr;
351 	/* Increment sequence number */
352 	if (seqnr < MAX_SEQ) {
353 		seqnr++;
354 	} else {
355 		seqnr = MIN_SEQ;
356 	}
357 	return tmp;
358 }
359 
360 /* -----------------------------------------------------------
361  * API to access OSPF daemon by client applications.
362  * -----------------------------------------------------------
363  */
364 
365 /*
366  * Synchronous request to register opaque type.
367  */
ospf_apiclient_register_opaque_type(struct ospf_apiclient * cl,uint8_t ltype,uint8_t otype)368 int ospf_apiclient_register_opaque_type(struct ospf_apiclient *cl,
369 					uint8_t ltype, uint8_t otype)
370 {
371 	struct msg *msg;
372 	int rc;
373 
374 	/* just put 1 as a sequence number. */
375 	msg = new_msg_register_opaque_type(ospf_apiclient_get_seqnr(), ltype,
376 					   otype);
377 	if (!msg) {
378 		fprintf(stderr, "new_msg_register_opaque_type failed\n");
379 		return -1;
380 	}
381 
382 	rc = ospf_apiclient_send_request(cl, msg);
383 	return rc;
384 }
385 
386 /*
387  * Synchronous request to synchronize with OSPF's LSDB.
388  * Two steps required: register_event in order to get
389  * dynamic updates and LSDB_Sync.
390  */
ospf_apiclient_sync_lsdb(struct ospf_apiclient * oclient)391 int ospf_apiclient_sync_lsdb(struct ospf_apiclient *oclient)
392 {
393 	struct msg *msg;
394 	int rc;
395 	struct lsa_filter_type filter;
396 
397 	filter.typemask = 0xFFFF; /* all LSAs */
398 	filter.origin = ANY_ORIGIN;
399 	filter.num_areas = 0; /* all Areas. */
400 
401 	msg = new_msg_register_event(ospf_apiclient_get_seqnr(), &filter);
402 	if (!msg) {
403 		fprintf(stderr, "new_msg_register_event failed\n");
404 		return -1;
405 	}
406 	rc = ospf_apiclient_send_request(oclient, msg);
407 
408 	if (rc != 0)
409 		goto out;
410 
411 	msg = new_msg_sync_lsdb(ospf_apiclient_get_seqnr(), &filter);
412 	if (!msg) {
413 		fprintf(stderr, "new_msg_sync_lsdb failed\n");
414 		return -1;
415 	}
416 	rc = ospf_apiclient_send_request(oclient, msg);
417 
418 out:
419 	return rc;
420 }
421 
422 /*
423  * Synchronous request to originate or update an LSA.
424  */
425 
ospf_apiclient_lsa_originate(struct ospf_apiclient * oclient,struct in_addr ifaddr,struct in_addr area_id,uint8_t lsa_type,uint8_t opaque_type,uint32_t opaque_id,void * opaquedata,int opaquelen)426 int ospf_apiclient_lsa_originate(struct ospf_apiclient *oclient,
427 				 struct in_addr ifaddr, struct in_addr area_id,
428 				 uint8_t lsa_type, uint8_t opaque_type,
429 				 uint32_t opaque_id, void *opaquedata,
430 				 int opaquelen)
431 {
432 	struct msg *msg;
433 	int rc;
434 	uint8_t buf[OSPF_MAX_LSA_SIZE];
435 	struct lsa_header *lsah;
436 	uint32_t tmp;
437 
438 
439 	/* We can only originate opaque LSAs */
440 	if (!IS_OPAQUE_LSA(lsa_type)) {
441 		fprintf(stderr, "Cannot originate non-opaque LSA type %d\n",
442 			lsa_type);
443 		return OSPF_API_ILLEGALLSATYPE;
444 	}
445 
446 	/* Make a new LSA from parameters */
447 	lsah = (struct lsa_header *)buf;
448 	lsah->ls_age = 0;
449 	lsah->options = 0;
450 	lsah->type = lsa_type;
451 
452 	tmp = SET_OPAQUE_LSID(opaque_type, opaque_id);
453 	lsah->id.s_addr = htonl(tmp);
454 	lsah->adv_router.s_addr = INADDR_ANY;
455 	lsah->ls_seqnum = 0;
456 	lsah->checksum = 0;
457 	lsah->length = htons(sizeof(struct lsa_header) + opaquelen);
458 
459 	memcpy(((uint8_t *)lsah) + sizeof(struct lsa_header), opaquedata,
460 	       opaquelen);
461 
462 	msg = new_msg_originate_request(ospf_apiclient_get_seqnr(), ifaddr,
463 					area_id, lsah);
464 	if (!msg) {
465 		fprintf(stderr, "new_msg_originate_request failed\n");
466 		return OSPF_API_NOMEMORY;
467 	}
468 
469 	rc = ospf_apiclient_send_request(oclient, msg);
470 	return rc;
471 }
472 
ospf_apiclient_lsa_delete(struct ospf_apiclient * oclient,struct in_addr area_id,uint8_t lsa_type,uint8_t opaque_type,uint32_t opaque_id)473 int ospf_apiclient_lsa_delete(struct ospf_apiclient *oclient,
474 			      struct in_addr area_id, uint8_t lsa_type,
475 			      uint8_t opaque_type, uint32_t opaque_id)
476 {
477 	struct msg *msg;
478 	int rc;
479 
480 	/* Only opaque LSA can be deleted */
481 	if (!IS_OPAQUE_LSA(lsa_type)) {
482 		fprintf(stderr, "Cannot delete non-opaque LSA type %d\n",
483 			lsa_type);
484 		return OSPF_API_ILLEGALLSATYPE;
485 	}
486 
487 	/* opaque_id is in host byte order and will be converted
488 	 * to network byte order by new_msg_delete_request */
489 	msg = new_msg_delete_request(ospf_apiclient_get_seqnr(), area_id,
490 				     lsa_type, opaque_type, opaque_id);
491 
492 	rc = ospf_apiclient_send_request(oclient, msg);
493 	return rc;
494 }
495 
496 /* -----------------------------------------------------------
497  * Followings are handlers for messages from OSPF daemon
498  * -----------------------------------------------------------
499  */
500 
ospf_apiclient_handle_ready(struct ospf_apiclient * oclient,struct msg * msg)501 static void ospf_apiclient_handle_ready(struct ospf_apiclient *oclient,
502 					struct msg *msg)
503 {
504 	struct msg_ready_notify *r;
505 	r = (struct msg_ready_notify *)STREAM_DATA(msg->s);
506 
507 	/* Invoke registered callback function. */
508 	if (oclient->ready_notify) {
509 		(oclient->ready_notify)(r->lsa_type, r->opaque_type, r->addr);
510 	}
511 }
512 
ospf_apiclient_handle_new_if(struct ospf_apiclient * oclient,struct msg * msg)513 static void ospf_apiclient_handle_new_if(struct ospf_apiclient *oclient,
514 					 struct msg *msg)
515 {
516 	struct msg_new_if *n;
517 	n = (struct msg_new_if *)STREAM_DATA(msg->s);
518 
519 	/* Invoke registered callback function. */
520 	if (oclient->new_if) {
521 		(oclient->new_if)(n->ifaddr, n->area_id);
522 	}
523 }
524 
ospf_apiclient_handle_del_if(struct ospf_apiclient * oclient,struct msg * msg)525 static void ospf_apiclient_handle_del_if(struct ospf_apiclient *oclient,
526 					 struct msg *msg)
527 {
528 	struct msg_del_if *d;
529 	d = (struct msg_del_if *)STREAM_DATA(msg->s);
530 
531 	/* Invoke registered callback function. */
532 	if (oclient->del_if) {
533 		(oclient->del_if)(d->ifaddr);
534 	}
535 }
536 
ospf_apiclient_handle_ism_change(struct ospf_apiclient * oclient,struct msg * msg)537 static void ospf_apiclient_handle_ism_change(struct ospf_apiclient *oclient,
538 					     struct msg *msg)
539 {
540 	struct msg_ism_change *m;
541 	m = (struct msg_ism_change *)STREAM_DATA(msg->s);
542 
543 	/* Invoke registered callback function. */
544 	if (oclient->ism_change) {
545 		(oclient->ism_change)(m->ifaddr, m->area_id, m->status);
546 	}
547 }
548 
ospf_apiclient_handle_nsm_change(struct ospf_apiclient * oclient,struct msg * msg)549 static void ospf_apiclient_handle_nsm_change(struct ospf_apiclient *oclient,
550 					     struct msg *msg)
551 {
552 	struct msg_nsm_change *m;
553 	m = (struct msg_nsm_change *)STREAM_DATA(msg->s);
554 
555 	/* Invoke registered callback function. */
556 	if (oclient->nsm_change) {
557 		(oclient->nsm_change)(m->ifaddr, m->nbraddr, m->router_id,
558 				      m->status);
559 	}
560 }
561 
ospf_apiclient_handle_lsa_update(struct ospf_apiclient * oclient,struct msg * msg)562 static void ospf_apiclient_handle_lsa_update(struct ospf_apiclient *oclient,
563 					     struct msg *msg)
564 {
565 	struct msg_lsa_change_notify *cn;
566 	struct lsa_header *lsa;
567 	int lsalen;
568 
569 	cn = (struct msg_lsa_change_notify *)STREAM_DATA(msg->s);
570 
571 	/* Extract LSA from message */
572 	lsalen = ntohs(cn->data.length);
573 	lsa = XMALLOC(MTYPE_OSPF_APICLIENT, lsalen);
574 
575 	memcpy(lsa, &(cn->data), lsalen);
576 
577 	/* Invoke registered update callback function */
578 	if (oclient->update_notify) {
579 		(oclient->update_notify)(cn->ifaddr, cn->area_id,
580 					 cn->is_self_originated, lsa);
581 	}
582 
583 	/* free memory allocated by ospf apiclient library */
584 	XFREE(MTYPE_OSPF_APICLIENT, lsa);
585 }
586 
ospf_apiclient_handle_lsa_delete(struct ospf_apiclient * oclient,struct msg * msg)587 static void ospf_apiclient_handle_lsa_delete(struct ospf_apiclient *oclient,
588 					     struct msg *msg)
589 {
590 	struct msg_lsa_change_notify *cn;
591 	struct lsa_header *lsa;
592 	int lsalen;
593 
594 	cn = (struct msg_lsa_change_notify *)STREAM_DATA(msg->s);
595 
596 	/* Extract LSA from message */
597 	lsalen = ntohs(cn->data.length);
598 	lsa = XMALLOC(MTYPE_OSPF_APICLIENT, lsalen);
599 
600 	memcpy(lsa, &(cn->data), lsalen);
601 
602 	/* Invoke registered update callback function */
603 	if (oclient->delete_notify) {
604 		(oclient->delete_notify)(cn->ifaddr, cn->area_id,
605 					 cn->is_self_originated, lsa);
606 	}
607 
608 	/* free memory allocated by ospf apiclient library */
609 	XFREE(MTYPE_OSPF_APICLIENT, lsa);
610 }
611 
ospf_apiclient_msghandle(struct ospf_apiclient * oclient,struct msg * msg)612 static void ospf_apiclient_msghandle(struct ospf_apiclient *oclient,
613 				     struct msg *msg)
614 {
615 	/* Call message handler function. */
616 	switch (msg->hdr.msgtype) {
617 	case MSG_READY_NOTIFY:
618 		ospf_apiclient_handle_ready(oclient, msg);
619 		break;
620 	case MSG_NEW_IF:
621 		ospf_apiclient_handle_new_if(oclient, msg);
622 		break;
623 	case MSG_DEL_IF:
624 		ospf_apiclient_handle_del_if(oclient, msg);
625 		break;
626 	case MSG_ISM_CHANGE:
627 		ospf_apiclient_handle_ism_change(oclient, msg);
628 		break;
629 	case MSG_NSM_CHANGE:
630 		ospf_apiclient_handle_nsm_change(oclient, msg);
631 		break;
632 	case MSG_LSA_UPDATE_NOTIFY:
633 		ospf_apiclient_handle_lsa_update(oclient, msg);
634 		break;
635 	case MSG_LSA_DELETE_NOTIFY:
636 		ospf_apiclient_handle_lsa_delete(oclient, msg);
637 		break;
638 	default:
639 		fprintf(stderr,
640 			"ospf_apiclient_read: Unknown message type: %d\n",
641 			msg->hdr.msgtype);
642 		break;
643 	}
644 }
645 
646 /* -----------------------------------------------------------
647  * Callback handler registration
648  * -----------------------------------------------------------
649  */
650 
ospf_apiclient_register_callback(struct ospf_apiclient * oclient,void (* ready_notify)(uint8_t lsa_type,uint8_t opaque_type,struct in_addr addr),void (* new_if)(struct in_addr ifaddr,struct in_addr area_id),void (* del_if)(struct in_addr ifaddr),void (* ism_change)(struct in_addr ifaddr,struct in_addr area_id,uint8_t status),void (* nsm_change)(struct in_addr ifaddr,struct in_addr nbraddr,struct in_addr router_id,uint8_t status),void (* update_notify)(struct in_addr ifaddr,struct in_addr area_id,uint8_t self_origin,struct lsa_header * lsa),void (* delete_notify)(struct in_addr ifaddr,struct in_addr area_id,uint8_t self_origin,struct lsa_header * lsa))651 void ospf_apiclient_register_callback(
652 	struct ospf_apiclient *oclient,
653 	void (*ready_notify)(uint8_t lsa_type, uint8_t opaque_type,
654 			     struct in_addr addr),
655 	void (*new_if)(struct in_addr ifaddr, struct in_addr area_id),
656 	void (*del_if)(struct in_addr ifaddr),
657 	void (*ism_change)(struct in_addr ifaddr, struct in_addr area_id,
658 			   uint8_t status),
659 	void (*nsm_change)(struct in_addr ifaddr, struct in_addr nbraddr,
660 			   struct in_addr router_id, uint8_t status),
661 	void (*update_notify)(struct in_addr ifaddr, struct in_addr area_id,
662 			      uint8_t self_origin, struct lsa_header *lsa),
663 	void (*delete_notify)(struct in_addr ifaddr, struct in_addr area_id,
664 			      uint8_t self_origin, struct lsa_header *lsa))
665 {
666 	assert(oclient);
667 	assert(update_notify);
668 
669 	/* Register callback function */
670 	oclient->ready_notify = ready_notify;
671 	oclient->new_if = new_if;
672 	oclient->del_if = del_if;
673 	oclient->ism_change = ism_change;
674 	oclient->nsm_change = nsm_change;
675 	oclient->update_notify = update_notify;
676 	oclient->delete_notify = delete_notify;
677 }
678 
679 /* -----------------------------------------------------------
680  * Asynchronous message handling
681  * -----------------------------------------------------------
682  */
683 
ospf_apiclient_handle_async(struct ospf_apiclient * oclient)684 int ospf_apiclient_handle_async(struct ospf_apiclient *oclient)
685 {
686 	struct msg *msg;
687 
688 	/* Get a message */
689 	msg = msg_read(oclient->fd_async);
690 
691 	if (!msg) {
692 		/* Connection broke down */
693 		return -1;
694 	}
695 
696 	/* Handle message */
697 	ospf_apiclient_msghandle(oclient, msg);
698 
699 	/* Don't forget to free this message */
700 	msg_free(msg);
701 
702 	return 0;
703 }
704