ia64/xen-unstable

view tools/x2d2/minixend.c @ 3697:0156bb4ae3d7

bitkeeper revision 1.1159.212.112 (4207b382VvZgSA3Pg79SQESssYJbHQ)

More x86_64 fixes.
Signed-off-by: keir.fraser@cl.cam.ac.uk
author kaf24@scramble.cl.cam.ac.uk
date Mon Feb 07 18:29:22 2005 +0000 (2005-02-07)
parents f5a6b3a8c9b9
children 0a4b76b6b5a0
line source
1 #define _GNU_SOURCE
3 #include <sys/types.h>
4 #include <sys/fcntl.h>
5 #include <sys/ioctl.h>
6 #include <sys/mman.h>
7 #include <sys/select.h>
8 #include <sys/socket.h>
9 #include <sys/wait.h>
10 #include <asm/page.h>
11 #include <assert.h>
12 #include <ctype.h>
13 #include <err.h>
14 #include <errno.h>
15 #include <netinet/in.h>
16 #include <printf.h>
17 #include <pthread.h>
18 #include <sched.h>
19 #include <stdarg.h>
20 #include <stddef.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
26 #include "minixend.h"
28 #define NETWORK_SCRIPT "/etc/xen/scripts/network"
29 #define VIFBRIDGE_SCRIPT "/etc/xen/scripts/vif-bridge"
31 #define MINIXEND_PORT 5123
33 #define mb() asm volatile ("" ::: "memory")
35 static void send_control_message(int type, int subtype, int id,
36 int size, void *payload,
37 struct domain *target);
39 struct list_head
40 head_domain = LIST_HEAD(&head_domain);
42 static struct list_head
43 head_connection = LIST_HEAD(&head_connection);
45 struct list_head
46 head_console = LIST_HEAD(&head_console);
48 #define foreach_open_connection(d) \
49 foreach_item(d, &head_connection, struct open_connection, connection_list)
51 /* Not modified after initial start up */
52 static struct domain *dom0;
53 unsigned xc_handle;
54 static int listen_fd;
55 int evtchn_fd;
57 static struct list_head
58 head_event_receiver = LIST_HEAD(&head_event_receiver);
60 struct event_receiver {
61 struct list_head list;
62 int id;
63 pthread_cond_t cond;
64 };
66 /* We're protected by the dom0 mutex in here */
67 static struct event_receiver *
68 allocate_event_receiver(struct domain *d)
69 {
70 static int next_message_id;
71 struct event_receiver *work;
73 assert(d == dom0);
74 work = xmalloc(sizeof(*work));
75 work->id = next_message_id++;
76 pthread_cond_init(&work->cond, NULL);
78 list_insert_after(&work->list, &head_event_receiver);
80 return work;
81 }
83 static struct event_receiver *
84 find_event_receiver(int id)
85 {
86 struct event_receiver *work;
87 foreach_item(work, &head_event_receiver, struct event_receiver, list)
88 if (work->id == id)
89 return work;
90 return NULL;
91 }
93 static void
94 release_event_receiver(struct event_receiver *w)
95 {
96 list_remove(&w->list);
97 pthread_cond_destroy(&w->cond);
98 free(w);
99 }
101 /* Send a message to dom0, and then block awaiting a reply. */
102 /* Make sure we don't hold any domain mutexs */
103 static void
104 send_dom0_message_block(control_msg_t *msg)
105 {
106 CONTROL_RING_IDX c;
107 struct event_receiver *er;
108 control_msg_t buf;
110 PRINTF(0, "sending message to dom0 and blocking for reply.\n");
111 pthread_mutex_lock(&dom0->mux);
112 PRINTF(0, "got dom0 lock.\n");
113 er = allocate_event_receiver(dom0);
114 PRINTF(0, "allocated evetn receiver.\n");
115 msg->id = er->id;
116 PRINTF(1, "sending message with id %d\n", msg->id);
117 send_control_message(msg->type, msg->subtype,
118 msg->id, msg->length, msg->msg, dom0);
119 xc_evtchn_send(xc_handle, dom0->control_evtchn);
121 PRINTF(0, "waiting for reply\n");
122 pthread_cond_wait(&er->cond, &dom0->mux);
123 PRINTF(0, "got reply\n");
125 c = dom0->rx_resp_cons % CONTROL_RING_SIZE;
126 memcpy(&buf, &dom0->ctrl_if->rx_ring[c], sizeof(buf));
127 assert(msg->id == buf.id);
128 assert(msg->type == buf.type);
129 assert(msg->subtype == buf.subtype);
130 memcpy(msg, &buf, sizeof(*msg));
131 dom0->rx_resp_cons++;
133 release_event_receiver(er);
135 pthread_mutex_unlock(&dom0->mux);
137 PRINTF(1, "got reply to message with id %d\n", msg->id);
138 }
140 /* Allocate an interdomain event channel. event_ports[0] is the
141 local event port number, event_ports[1] the remote */
142 int
143 allocate_event_channel(struct domain *d, int event_ports[2])
144 {
145 return xc_evtchn_bind_interdomain(xc_handle, DOMID_SELF,
146 d->domid, event_ports,
147 event_ports+1);
148 }
150 static void
151 accept_new_connection(void)
152 {
153 int fd;
154 struct open_connection *oc;
156 fd = accept(listen_fd, NULL, NULL);
157 if (fd < 0)
158 return;
159 oc = xmalloc(sizeof(*oc));
160 oc->fd = fd;
161 oc->state = OC_STATE_CONNECTED;
162 oc->buf_used = 0;
163 oc->buf_allocated = 16;
164 oc->buf = xmalloc(oc->buf_allocated);
165 list_insert_after(&oc->connection_list, &head_connection);
166 }
168 static void
169 closedown_connection(struct open_connection *oc)
170 {
171 close(oc->fd);
172 assert(oc->buf);
173 free(oc->buf);
174 free(oc);
175 }
177 #if 0
178 /* Hackl for the benefit of domain replay */
179 static unsigned
180 report_work(u32 *ptr, u32 val, unsigned dom, int do_direct)
181 {
182 if (!do_direct) {
183 int rc;
184 asm("int $0x80" : "=a" (rc)
185 : "0" (264), "b" (ptr), "c" (val), "d" (dom));
186 if (rc < 0) {
187 errno = -rc;
188 rc = -1;
189 }
190 return rc;
191 } else {
192 *ptr = val;
193 return 0;
194 }
195 }
196 #else
197 static unsigned
198 report_work(u32 *ptr, u32 val, unsigned dom, int do_direct)
199 {
200 *ptr = val;
201 return 0;
202 }
203 #endif
205 static void
206 send_control_reply(const control_msg_t *msg, struct domain *d)
207 {
208 CONTROL_RING_IDX c;
210 PRINTF(3,"Control reply, type %d:%d, length %d.\n",
211 msg->type, msg->subtype, msg->length);
212 c = d->ctrl_if->tx_resp_prod % CONTROL_RING_SIZE;
213 memcpy(&d->ctrl_if->tx_ring[c], msg, sizeof(*msg));
214 report_work(&d->ctrl_if->tx_resp_prod,
215 d->ctrl_if->tx_resp_prod + 1,
216 d->domid,
217 0);
218 PRINTF(4,"tx_resp_prod %ld.\n", d->ctrl_if->tx_resp_prod);
219 assert(!d->plugged);
220 }
222 static void
223 send_trivial_control_reply(const control_msg_t *msg, struct domain *d)
224 {
225 control_msg_t rep;
227 memset(&rep, 0, sizeof(rep));
228 rep.type = msg->type;
229 rep.subtype = msg->subtype;
230 rep.id = msg->id;
231 send_control_reply(&rep, d);
232 }
234 static void
235 process_console_control_message(control_msg_t *m, struct domain *d)
236 {
237 int off;
238 int r;
240 if (m->subtype != CMSG_CONSOLE_DATA) {
241 warnx("unknown console message subtype %d",
242 m->subtype);
243 return;
244 }
246 if (m->length > 60) {
247 warnx("truncating message from domain %d (was length %d)",
248 d->domid, m->length);
249 m->length = 60;
250 }
251 PRINTF(1, "DOM%d: %.*s\n", d->domid, m->length, m->msg);
252 send_trivial_control_reply(m, d);
254 if (d->cc) {
255 PRINTF(5, "Have a console connection.\n");
256 if (d->cc->state == CC_STATE_CONNECTED) {
257 PRINTF(5, "Console is connected, sending directly.\n");
258 for (off = 0; off < m->length; off += r) {
259 r = write(d->cc->fd, m->msg + off,
260 m->length - off);
261 if (r <= 0) {
262 d->cc->state = CC_STATE_ERROR;
263 break;
264 }
265 }
266 } else {
267 PRINTF(5, "Console not connected, buffering.\n");
268 if (d->cc->buf_allocated == 0) {
269 d->cc->buf_allocated = 60;
270 d->cc->buf = xmalloc(d->cc->buf_allocated);
271 d->cc->buf_used = 0;
272 } else if (d->cc->buf_allocated <
273 d->cc->buf_used + m->length) {
274 d->cc->buf_allocated += 60;
275 d->cc->buf = xrealloc(d->cc->buf,
276 d->cc->buf_allocated);
277 }
278 assert(d->cc->buf_allocated >=
279 d->cc->buf_used + m->length);
280 memcpy(d->cc->buf + d->cc->buf_used,
281 m->msg,
282 m->length);
283 d->cc->buf_used += m->length;
284 }
285 }
286 }
288 static void
289 process_blkif_fe_message(control_msg_t *m, struct domain *d)
290 {
291 switch (m->subtype) {
292 default:
293 warnx("unknown blkif front end message subtype %d",
294 m->subtype);
295 }
296 }
298 static void
299 send_control_message(int type, int subtype, int id,
300 int size, void *payload, struct domain *target)
301 {
302 control_msg_t msg;
303 CONTROL_RING_IDX c;
305 msg.type = type;
306 msg.subtype = subtype;
307 msg.id = id;
308 msg.length = size;
309 memcpy(msg.msg, payload, size);
311 c = target->ctrl_if->rx_req_prod % CONTROL_RING_SIZE;
312 memcpy(&target->ctrl_if->rx_ring[c], &msg, sizeof(msg));
313 report_work(&target->ctrl_if->rx_req_prod,
314 target->ctrl_if->rx_req_prod + 1,
315 target->domid,
316 0);
317 assert(!target->plugged);
318 }
320 /* Procedure for bringing a new netif front end up:
322 -- Front end sends us NETIF_FE_DRIVER_STATUS_CHANGED
323 -- We send back end NETIF_BE_CREATE, wait for a reply
324 -- Back end creates a new netif for us, replies
325 -- We send front end a NETIF_FE_DRIVER_STATUS_CHANGED message saying
326 how many interfaces we've created for it
327 -- We send front end a NETIF_FE_INTERFACE_STATUS_CHANGED for each
328 netif created
329 -- Front end sends us a NETIF_FE_INTERFACE_CONNECT for each netif
330 */
331 static void
332 handle_netif_fe_driver_status(control_msg_t *m,
333 netif_fe_driver_status_t *sh,
334 struct domain *d)
335 {
336 netif_fe_interface_status_t if_s;
337 control_msg_t be_msg;
338 netif_be_create_t *be = (void *)be_msg.msg;
339 int r;
341 switch (sh->status) {
342 case NETIF_DRIVER_STATUS_UP:
343 /* Tell the back end about the new interface coming
344 * up. */
345 if (d->created_netif_backend) {
346 send_control_reply(m, d);
347 send_control_message(CMSG_NETIF_FE,
348 CMSG_NETIF_FE_DRIVER_STATUS,
349 1,
350 sizeof(*sh),
351 sh,
352 d);
353 return;
354 }
355 be_msg.type = CMSG_NETIF_BE;
356 be_msg.subtype = CMSG_NETIF_BE_CREATE;
357 be_msg.id = d->domid;
358 be_msg.length = sizeof(*be);
359 be->domid = d->domid;
360 be->netif_handle = 0;
361 memcpy(be->mac, d->netif_mac, 6);
363 PRINTF(2,"Telling back end about new front end.\n");
364 pthread_mutex_unlock(&d->mux);
365 send_dom0_message_block(&be_msg);
366 pthread_mutex_lock(&d->mux);
367 PRINTF(3,"Done.\n");
369 if (be->status != NETIF_BE_STATUS_OKAY) {
370 /* Uh oh... can't bring back end
371 * up. */
372 send_control_reply(m, d);
373 send_control_message(CMSG_NETIF_FE,
374 CMSG_NETIF_FE_DRIVER_STATUS,
375 1,
376 sizeof(*sh),
377 sh,
378 d);
379 return;
380 }
381 d->created_netif_backend = 1;
383 r = our_system(VIFBRIDGE_SCRIPT " up domain=%s mac=%.02x:%.02x:%.02x:%.02x:%.02x:%.02x vif=vif%d.0 bridge=xen-br0",
384 d->name,
385 d->netif_mac[0],
386 d->netif_mac[1],
387 d->netif_mac[2],
388 d->netif_mac[3],
389 d->netif_mac[4],
390 d->netif_mac[5],
391 d->domid);
392 if (r != 0)
393 warn("error %d running " VIFBRIDGE_SCRIPT, r);
395 /* Tell domain how many interfaces it has to deal
396 * with. */
397 send_control_reply(m, d);
398 send_control_message(CMSG_NETIF_FE,
399 CMSG_NETIF_FE_DRIVER_STATUS,
400 1,
401 sizeof(*sh),
402 sh,
403 d);
405 PRINTF(2,"Telling front end about its interfaces.\n");
406 if_s.handle = 0;
407 if_s.status = NETIF_INTERFACE_STATUS_DISCONNECTED;
408 send_control_message(CMSG_NETIF_FE,
409 CMSG_NETIF_FE_INTERFACE_STATUS,
410 1,
411 sizeof(if_s),
412 &if_s,
413 d);
414 PRINTF(3,"Done.\n");
416 break;
417 default:
418 warnx("unknown netif status %ld", sh->status);
419 break;
420 }
421 }
423 static void
424 handle_netif_fe_interface_connect(control_msg_t *m,
425 netif_fe_interface_connect_t *ic,
426 struct domain *d)
427 {
428 control_msg_t be_msg;
429 netif_be_connect_t *bmsg = (void *)be_msg.msg;
430 netif_fe_interface_status_t fmsg = {0};
431 int evtchn_ports[2];
432 int r;
434 PRINTF(4, "front end sent us an interface connect message.\n");
435 send_trivial_control_reply(m, d);
437 r = xc_evtchn_bind_interdomain(xc_handle,
438 dom0->domid,
439 d->domid,
440 &evtchn_ports[0],
441 &evtchn_ports[1]);
442 if (r < 0)
443 err(1, "allocating network event channel");
445 be_msg.type = CMSG_NETIF_BE;
446 be_msg.subtype = CMSG_NETIF_BE_CONNECT;
447 be_msg.id = 0;
448 be_msg.length = sizeof(*bmsg);
449 bmsg->domid = d->domid;
450 bmsg->netif_handle = ic->handle;
451 bmsg->tx_shmem_frame = ic->tx_shmem_frame;
452 bmsg->rx_shmem_frame = ic->rx_shmem_frame;
453 bmsg->evtchn = evtchn_ports[0];
455 pthread_mutex_unlock(&d->mux);
456 send_dom0_message_block(&be_msg);
457 pthread_mutex_lock(&d->mux);
459 if (bmsg->status != NETIF_BE_STATUS_OKAY) {
460 PRINTF(2, "error connected backend netif: %ld\n",
461 bmsg->status);
462 abort(); /* Need to handle this */
463 } else {
464 PRINTF(3, "connect backend netif\n");
466 /* Tell the domain that we've connected it up. */
467 fmsg.handle = ic->handle;
468 fmsg.status = NETIF_INTERFACE_STATUS_CONNECTED;
469 fmsg.evtchn = evtchn_ports[1];
470 memcpy(fmsg.mac, d->netif_mac, 6);
472 send_control_message(CMSG_NETIF_FE,
473 CMSG_NETIF_FE_INTERFACE_STATUS,
474 0,
475 sizeof(fmsg),
476 &fmsg,
477 d);
478 }
479 }
481 static void
482 process_netif_fe_message(control_msg_t *m, struct domain *d)
483 {
484 switch (m->subtype) {
485 case CMSG_NETIF_FE_DRIVER_STATUS:
486 {
487 netif_fe_driver_status_t *sh =
488 (netif_fe_driver_status_t *)m->msg;
489 handle_netif_fe_driver_status(m, sh, d);
490 break;
491 }
492 case CMSG_NETIF_FE_INTERFACE_CONNECT:
493 {
494 netif_fe_interface_connect_t *ic =
495 (netif_fe_interface_connect_t *)m->msg;
496 handle_netif_fe_interface_connect(m, ic, d);
497 break;
498 }
499 default:
500 warnx("unknown netif front end message subtype %d",
501 m->subtype);
502 }
503 }
505 static void
506 process_control_message(control_msg_t *msg, struct domain *d)
507 {
508 control_msg_t m;
510 /* Don't want a malicous domain messing us about, so copy the
511 control mesasge into a local buffer. */
512 memcpy(&m, msg, sizeof(m));
513 switch (m.type) {
514 case CMSG_CONSOLE:
515 process_console_control_message(&m, d);
516 break;
517 case CMSG_BLKIF_FE:
518 process_blkif_fe_message(&m, d);
519 break;
520 case CMSG_NETIF_FE:
521 process_netif_fe_message(&m, d);
522 break;
523 default:
524 warnx("unknown control message type %d", m.type);
525 }
526 }
528 static void
529 domain_did_control_event(struct domain *d)
530 {
531 CONTROL_RING_IDX c;
533 /* Pick up and process control ring messages. */
534 while (d->tx_req_cons != d->ctrl_if->tx_req_prod) {
535 c = d->tx_req_cons % CONTROL_RING_SIZE;
536 process_control_message(&d->ctrl_if->tx_ring[c], d);
537 d->tx_req_cons++;
538 assert(d->tx_req_cons <= d->ctrl_if->tx_req_prod);
539 PRINTF(5, "req_cons %ld, req_prod %ld.\n",
540 d->tx_req_cons, d->ctrl_if->tx_req_prod);
541 }
543 /* Take any replies off, and discard them. */
544 if (d->rx_resp_cons != d->ctrl_if->rx_resp_prod)
545 PRINTF(1, "discard %ld events\n",
546 d->ctrl_if->rx_resp_prod -
547 d->rx_resp_cons);
548 d->rx_resp_cons = d->ctrl_if->rx_resp_prod;
549 }
551 /* This is the main function for domain control threads */
552 void *
553 domain_thread_func(void *D)
554 {
555 struct domain *d = D;
556 int r;
557 CONTROL_RING_IDX old_resp_prod, old_req_prod;
559 pthread_mutex_lock(&d->mux);
560 for (;;) {
561 pthread_cond_wait(&d->cond, &d->mux);
563 old_resp_prod = d->ctrl_if->tx_resp_prod;
564 old_req_prod = d->ctrl_if->rx_req_prod;
566 domain_did_control_event(d);
567 if (d->cc && d->cc->in_buf_used != 0 && d->plugged == 0) {
568 r = d->cc->in_buf_used;
569 if (r > 60)
570 r = 60;
571 PRINTF(1, "Sending to domain: %.*s\n",
572 r, d->cc->in_buf);
573 send_control_message(CMSG_CONSOLE,
574 CMSG_CONSOLE_DATA,
575 0,
576 r,
577 d->cc->in_buf,
578 d);
579 memmove(d->cc->in_buf, d->cc->in_buf + r,
580 d->cc->in_buf_used - r);
581 d->cc->in_buf_used -= r;
582 }
584 if (d->ctrl_if->tx_resp_prod != old_resp_prod ||
585 d->ctrl_if->rx_req_prod != old_req_prod)
586 xc_evtchn_send(xc_handle, d->control_evtchn);
587 }
588 }
590 /* This is the only thing you can do with a domain structure if you're
591 not in the thread which controls that domain. Domain 0 is
592 special. */
593 void
594 signal_domain(struct domain *d)
595 {
596 CONTROL_RING_IDX c;
597 int id;
598 struct event_receiver *evt;
600 pthread_mutex_lock(&d->mux);
601 if (d == dom0) {
602 /* Take events off of dom0's control ring, and send
603 them to the event receivers. */
604 while (d->tx_req_cons != d->ctrl_if->tx_req_prod) {
605 c = d->tx_req_cons % CONTROL_RING_SIZE;
606 id = d->ctrl_if->tx_ring[c].id;
607 evt = find_event_receiver(id);
608 if (evt != NULL) {
609 PRINTF(1, "delivering event id %d\n", evt->id);
610 pthread_cond_broadcast(&evt->cond);
611 pthread_mutex_unlock(&d->mux);
612 sched_yield();
613 pthread_mutex_lock(&d->mux);
614 } else {
615 warnx("unexpected message id %d discarded",
616 id);
617 d->tx_req_cons++;
618 }
619 }
620 while (d->rx_resp_cons != d->ctrl_if->rx_resp_prod) {
621 c = d->rx_resp_cons % CONTROL_RING_SIZE;
622 id = d->ctrl_if->rx_ring[c].id;
623 evt = find_event_receiver(id);
624 if (evt != NULL) {
625 PRINTF(1, "delivering event rep id %d\n", evt->id);
626 pthread_cond_broadcast(&evt->cond);
627 pthread_mutex_unlock(&d->mux);
628 sched_yield();
629 pthread_mutex_lock(&d->mux);
630 } else {
631 warnx("unexpected message reply id %d discarded",
632 id);
633 d->rx_resp_cons++;
634 }
635 }
636 } else {
637 if (d->plugged) {
638 d->event_pending = 1;
639 } else {
640 pthread_cond_broadcast(&d->cond);
641 }
642 }
643 pthread_mutex_unlock(&d->mux);
644 }
646 static void
647 handle_evtchn_event(void)
648 {
649 short port;
650 struct domain *d;
652 read(evtchn_fd, &port, sizeof(short));
653 write(evtchn_fd, &port, sizeof(short));
654 foreach_domain (d) {
655 if (d->control_evtchn == port) {
656 signal_domain(d);
657 return;
658 }
659 }
660 warnx("got an event on an unknown port %d", port);
661 }
663 void *
664 map_domain_mem(struct domain *d, unsigned long mfn)
665 {
666 return xc_map_foreign_range(xc_handle, d->domid,
667 PAGE_SIZE, PROT_READ | PROT_WRITE,
668 mfn);
669 }
671 static void
672 handle_console_event(struct console_connection *cc)
673 {
674 int r;
675 int fd;
677 switch (cc->state) {
678 case CC_STATE_ERROR:
679 /* Errors shouldn't get here. */
680 abort();
681 case CC_STATE_PENDING:
682 fd = accept(cc->fd, NULL, NULL);
683 if (fd >= 0) {
684 PRINTF(3, "Accepted console connection for domain %d",
685 cc->dom->domid);
686 close(cc->fd);
687 cc->fd = fd;
688 cc->state = CC_STATE_CONNECTED;
689 while (cc->buf_used != 0) {
690 r = write(cc->fd,
691 cc->buf,
692 cc->buf_used);
693 if (r <= 0) {
694 cc->state = CC_STATE_ERROR;
695 break;
696 }
697 memmove(cc->buf,
698 cc->buf + r,
699 cc->buf_used - r);
700 cc->buf_used -= r;
701 }
702 free(cc->buf);
703 cc->buf = NULL;
704 cc->buf_allocated = 0;
705 } else {
706 PRINTF(1, "error %s accepting console", strerror(errno));
707 }
708 pthread_mutex_unlock(&cc->dom->mux);
709 break;
710 case CC_STATE_CONNECTED:
711 if (cc->in_buf_allocated == 0) {
712 assert(cc->in_buf_used == 0);
713 cc->in_buf_allocated = 128;
714 cc->in_buf = xmalloc(cc->in_buf_allocated);
715 }
716 if (cc->in_buf_used == cc->in_buf_allocated) {
717 cc->in_buf_allocated *= 2;
718 cc->in_buf = xrealloc(cc->in_buf, cc->in_buf_allocated);
719 }
720 r = read(cc->fd, cc->in_buf + cc->in_buf_used,
721 cc->in_buf_allocated - cc->in_buf_used);
722 if (r <= 0) {
723 cc->state = CC_STATE_ERROR;
724 } else {
725 cc->in_buf_used += r;
726 }
727 pthread_mutex_unlock(&cc->dom->mux);
728 signal_domain(cc->dom);
729 break;
730 }
731 }
733 static void
734 handle_connection_event(struct open_connection *oc)
735 {
736 int r;
738 /* We know that some amount of data is ready and waiting for
739 us. Slurp it in. */
740 if (oc->buf_used == oc->buf_allocated) {
741 oc->buf_allocated *= 2;
742 oc->buf = xrealloc(oc->buf, oc->buf_allocated);
743 }
744 r = read(oc->fd, oc->buf + oc->buf_used,
745 oc->buf_allocated - oc->buf_used);
746 if (r < 0) {
747 warn("reading command from remote");
748 oc->state = OC_STATE_ERROR;
749 } else if (r == 0) {
750 warnx("reading command from remote");
751 oc->state = OC_STATE_ERROR;
752 } else {
753 oc->buf_used += r;
754 if (strchr(oc->buf, '\n'))
755 oc->state = OC_STATE_COMMAND_PENDING;
756 }
757 }
759 static void
760 get_and_process_event(void)
761 {
762 fd_set read_fds, except_fds;
763 struct open_connection *oc;
764 struct console_connection *cc;
765 int max_fd = listen_fd;
766 int r;
767 struct list_head *li, *temp_li;
769 FD_ZERO(&read_fds);
770 FD_ZERO(&except_fds);
771 FD_SET(listen_fd, &read_fds);
772 FD_SET(evtchn_fd, &read_fds);
773 if (evtchn_fd > max_fd)
774 max_fd = evtchn_fd;
775 foreach_open_connection(oc) {
776 FD_SET(oc->fd, &read_fds);
777 FD_SET(oc->fd, &except_fds);
778 if (oc->fd > max_fd)
779 max_fd = oc->fd;
780 }
781 foreach_console_connection(cc) {
782 FD_SET(cc->fd, &read_fds);
783 FD_SET(cc->fd, &except_fds);
784 if (cc->fd > max_fd)
785 max_fd = cc->fd;
786 }
788 r = select(max_fd + 1, &read_fds, NULL, &except_fds, NULL);
789 if (r < 0)
790 err(1, "select");
791 if (FD_ISSET(listen_fd, &read_fds)) {
792 accept_new_connection();
793 } else if (FD_ISSET(evtchn_fd, &read_fds))
794 handle_evtchn_event();
797 foreach_open_connection(oc) {
798 if (FD_ISSET(oc->fd, &read_fds))
799 handle_connection_event(oc);
800 if (FD_ISSET(oc->fd, &except_fds))
801 oc->state = OC_STATE_ERROR;
802 }
803 list_foreach_safe(&head_console, li, temp_li) {
804 cc = list_item(li, struct console_connection, list);
805 if (FD_ISSET(cc->fd, &read_fds))
806 handle_console_event(cc);
807 if (FD_ISSET(cc->fd, &except_fds) ||
808 cc->state == CC_STATE_ERROR) {
809 PRINTF(1, "Cleaning up console connection");
810 cc->dom->cc = NULL;
811 list_remove(&cc->list);
812 close(cc->fd);
813 if (cc->buf_allocated != 0)
814 free(cc->buf);
815 if (cc->in_buf_allocated != 0)
816 free(cc->in_buf);
817 free(cc);
818 }
819 }
821 /* Run pending stuff on the open connections. */
822 list_foreach_safe(&head_connection, li, temp_li) {
823 oc = list_item(li, struct open_connection, connection_list);
824 switch (oc->state) {
825 case OC_STATE_ERROR:
826 list_remove(&oc->connection_list);
827 closedown_connection(oc);
828 break;
829 case OC_STATE_COMMAND_PENDING:
830 process_command(oc);
831 break;
832 case OC_STATE_CONNECTED:
833 /* Don't need to do anything */
834 break;
835 }
836 }
837 }
839 static int
840 start_listening(void)
841 {
842 int sock;
843 struct sockaddr_in inaddr;
845 sock = socket(PF_INET, SOCK_STREAM, 0);
846 if (sock < 0)
847 err(1, "creating socket");
848 memset(&inaddr, 0, sizeof(inaddr));
849 inaddr.sin_family = AF_INET;
850 inaddr.sin_port = htons(MINIXEND_PORT);
852 if (bind(sock, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0)
853 err(1, "binding to port %d", MINIXEND_PORT);
854 if (listen(sock, 5) < 0)
855 err(1, "listening for connections");
857 return sock;
858 }
860 static struct domain *
861 find_dom0(void)
862 {
863 int r;
864 xc_dominfo_t info;
865 struct domain *work;
867 r = xc_domain_getinfo(xc_handle, 0, 1, &info);
868 if (r < 0)
869 err(1, "getting domain 0 information");
870 work = xmalloc(sizeof(*work));
871 work->control_evtchn = 2;
872 if (ioctl(evtchn_fd, EVTCHN_BIND, 2) < 0)
873 err(1, "binding to domain 0 control event channel");
875 work->domid = 0;
876 work->name = strdup("dom0");
877 work->mem_kb = info.max_memkb;
878 work->state = DOM_STATE_RUNNING;
879 work->shared_info_mfn = info.shared_info_frame;
881 work->shared_info = map_domain_mem(work, info.shared_info_frame);
882 work->ctrl_if = (control_if_t *)((unsigned)work->shared_info + 2048);
883 work->tx_req_cons = work->ctrl_if->tx_req_prod;
884 work->rx_resp_cons = work->ctrl_if->rx_resp_prod;
886 pthread_mutex_init(&work->mux, NULL);
887 pthread_cond_init(&work->cond, NULL);
889 list_insert_after(&work->domain_list, &head_domain);
891 return work;
892 }
894 int
895 main(int argc, char *argv[])
896 {
897 int r;
899 r = our_system(NETWORK_SCRIPT " start antispoof=no");
900 if (r < 0)
901 err(1, "running " NETWORK_SCRIPT);
902 if (!WIFEXITED(r)) {
903 if (WIFSIGNALED(r)) {
904 errx(1, NETWORK_SCRIPT " killed by signal %d",
905 WTERMSIG(r));
906 }
907 errx(1, NETWORK_SCRIPT " terminated abnormally");
908 }
909 if (WEXITSTATUS(r) != 0)
910 errx(1, NETWORK_SCRIPT " returned error status %d",
911 WEXITSTATUS(r));
913 xc_handle = xc_interface_open();
915 listen_fd = start_listening();
917 evtchn_fd = open("/dev/xen/evtchn", O_RDWR);
918 if (evtchn_fd < 0)
919 err(1, "openning /dev/xen/evtchn");
921 dom0 = find_dom0();
923 while (1) {
924 get_and_process_event();
926 PRINTF(5, "Dom0 ring state:\n");
927 PRINTF(5, "RX: req_prod %ld, resp_prod %ld, resp_cons %ld\n",
928 dom0->ctrl_if->rx_req_prod,
929 dom0->ctrl_if->rx_resp_prod,
930 dom0->rx_resp_cons);
931 PRINTF(5, "TX: req_prod %ld, resp_prod %ld, req_cons %ld\n",
932 dom0->ctrl_if->tx_req_prod,
933 dom0->ctrl_if->tx_resp_prod,
934 dom0->tx_req_cons);
935 }
937 return 0;
938 }