aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--external/mambo/Makefile8
-rw-r--r--external/mambo/mambo-socket-proxy.c359
3 files changed, 368 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 22565a0..2778552 100644
--- a/.gitignore
+++ b/.gitignore
@@ -69,6 +69,7 @@ debian-jessie-initrd.gz
external/dump_trace
external/mambo/skiboot-boot_test.dump
external/mambo/skiboot-hello_world.dump
+external/mambo/mambo-socket-proxy
external/memboot/memboot
hdata/test/hdata_to_dt
hdata/test/hdata_to_dt-gcov
diff --git a/external/mambo/Makefile b/external/mambo/Makefile
new file mode 100644
index 0000000..fbc696e
--- /dev/null
+++ b/external/mambo/Makefile
@@ -0,0 +1,8 @@
+CFLAGS=-O2 -m64 -pthread -Werror -Wall
+
+CC=$(CROSS)gcc
+
+all: mambo-socket-proxy
+
+clean:
+ rm -rf mambo-socket-proxy
diff --git a/external/mambo/mambo-socket-proxy.c b/external/mambo/mambo-socket-proxy.c
new file mode 100644
index 0000000..f3a1a2f
--- /dev/null
+++ b/external/mambo/mambo-socket-proxy.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2017 Michael Neuling <mikey@neuling.org>, IBM
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Compile with:
+ * gcc -static -O2 mambo-socket-proxy.c -o mambo-socket-proxy -pthread
+ * Run inside the simulator:
+ * - to forward host ssh connections to sim ssh server
+ * ./mambo-socket-proxy -h 10022 -s 22
+ * Then connect to port 10022 on your host
+ * ssh -p 10022 localhost
+ * - to allow http proxy access from inside the sim to local http proxy
+ * ./mambo-socket-proxy -b proxy.mynetwork -h 3128 -s 3128
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+#include <getopt.h>
+
+#define CALL_TCL 86
+#define BOGUS_SOCKET_CONN_PROBE_CODE 224
+#define BOGUS_SOCKET_CONN_SEND_CODE 225
+#define BOGUS_SOCKET_CONN_RECV_CODE 226
+
+static inline int callthru2(int command, unsigned long arg1, unsigned long arg2)
+{
+ register int c asm("r3") = command;
+ register unsigned long a1 asm("r4") = arg1;
+ register unsigned long a2 asm("r5") = arg2;
+ asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2));
+ return (c);
+}
+
+static inline int callthru3(int command, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3)
+{
+ register int c asm("r3") = command;
+ register unsigned long a1 asm("r4") = arg1;
+ register unsigned long a2 asm("r5") = arg2;
+ register unsigned long a3 asm("r6") = arg3;
+ asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2),
+ "r"(a3));
+ return (c);
+}
+
+static inline int callthru4(int command, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4)
+{
+ register int c asm("r3") = command;
+ register unsigned long a1 asm("r4") = arg1;
+ register unsigned long a2 asm("r5") = arg2;
+ register unsigned long a3 asm("r6") = arg3;
+ register unsigned long a4 asm("r7") = arg4;
+ asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2),
+ "r"(a3), "r"(a4));
+ return (c);
+}
+
+static inline int callthru5(int command, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4, unsigned long arg5)
+{
+ register int c asm("r3") = command;
+ register unsigned long a1 asm("r4") = arg1;
+ register unsigned long a2 asm("r5") = arg2;
+ register unsigned long a3 asm("r6") = arg3;
+ register unsigned long a4 asm("r7") = arg4;
+ register unsigned long a5 asm("r8") = arg5;
+ asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2),
+ "r"(a3), "r"(a4), "r"(a5));
+ return (c);
+}
+
+unsigned long callthru_tcl(const char *str, int strlen)
+{
+ return callthru2(CALL_TCL, (unsigned long)str,
+ (unsigned long)strlen);
+}
+
+unsigned long bogus_socket_conn_probe(int dev, void *addr, int conn)
+{
+ return callthru3(BOGUS_SOCKET_CONN_PROBE_CODE,
+ (unsigned long)dev,
+ (unsigned long)addr,
+ (unsigned long)conn);
+}
+
+unsigned long bogus_socket_conn_recv(int dev, void *addr, int maxlen, int conn)
+{
+ return callthru4(BOGUS_SOCKET_CONN_RECV_CODE,
+ (unsigned long)dev,
+ (unsigned long)addr,
+ (unsigned long)maxlen,
+ (unsigned long)conn);
+}
+
+unsigned long bogus_socket_conn_send(int dev, void *addr, int maxlen, int conn)
+{
+ return callthru5(BOGUS_SOCKET_CONN_SEND_CODE,
+ (unsigned long)dev,
+ (unsigned long)addr,
+ (unsigned long)maxlen,
+ 0,
+ (unsigned long)conn);
+}
+
+#define BUF_MAX 1024
+
+struct sock_info {
+ char *host;
+ int sock;
+ int dev;
+ int open;
+ int conn;
+};
+
+void *recv_thread(void *ptr)
+{
+ struct timeval timeout;
+ struct sock_info *si = ptr;
+ char buf[BUF_MAX];
+ int len;
+ fd_set set;
+
+ /* 1 sec */
+
+
+ while(1) {
+ FD_ZERO(&set);
+ FD_SET(si->sock, &set);
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ /* Set timeout to 1 second */
+ len = select(si->sock+1, &set, NULL, NULL, &timeout);
+ if (len <= 0) /* timeout */
+ len = -1;
+ else /* Receive from mambo tcp server */
+ len = recv(si->sock, &buf, BUF_MAX, 0);
+ if (len == 0) {
+ si->open = 0;
+ return NULL; /* closed */
+ }
+ if (len != -1) {
+ bogus_socket_conn_send(si->dev, &buf, len, si->conn);
+ }
+ if (!si->open)
+ return NULL;
+ }
+}
+
+#define POLL_MAX_NS 10000000
+
+void *send_thread(void *ptr)
+{
+ struct sock_info *si = ptr;
+ char buf[BUF_MAX];
+ int len;
+ struct timespec t;
+ int fault_retry = 16;
+
+ t.tv_sec = 0;
+ t.tv_nsec = POLL_MAX_NS;
+
+ while(1) {
+ /* Send to mambo tcp server */
+ len = bogus_socket_conn_recv(si->dev, &buf, BUF_MAX, si->conn);
+ if (len == -3 && fault_retry--) {
+ /* Page fault. Touch the buf and try again */
+ memset(buf, 0, BUF_MAX);
+ continue;
+ }
+ fault_retry = 16;
+
+ if (len == -1) /* EAGAIN */
+ nanosleep(&t , NULL);
+ else if (len > 0)
+ send(si->sock, &buf, len, 0);
+ else {
+ si->open = 0;
+ return NULL; /* closed */
+ }
+ if (!si->open)
+ return NULL;
+ }
+
+}
+
+void *connect_sockets(void *ptr)
+{
+ struct sock_info *si = ptr;
+ pthread_t recv, send;
+ unsigned long rc = 0;
+
+ if (pthread_create(&recv, NULL, recv_thread, si) ||
+ pthread_create(&send, NULL, send_thread, si)) {
+ rc = -1;
+ goto out;
+ }
+
+ if (pthread_join(recv, NULL) || pthread_join(send, NULL)) {
+ rc = -1;
+ goto out;
+ }
+
+out:
+ /* FIXME: Do shutdown better */
+ shutdown(si->sock, SHUT_WR);
+ si->open = 0;
+ free(si);
+ return (void *)rc;
+}
+
+void print_usage() {
+ printf("Usage:\n");
+ printf(" mambo-socket-proxy [-b <host>] -h <host port> -s <sim port>\n");
+ printf("\n");
+ printf(" -h <host port> : Port on the host to forward\n");
+ printf(" -s <host port> : Port in the sim to forward\n");
+ printf(" -b <host machine> : Connect sim port to host network\n");
+ printf("\n");
+}
+
+int main (int argc, char *argv[])
+{
+ char cmd[128];
+ struct sockaddr_in ser, client;
+ pthread_t sockets_thread;
+ struct sock_info *si;
+ int sock, conn, rc = 0, option = 0, one_shot = 0, c, sock_desc = 0;
+ char *host = NULL;
+ int host_port = -1, sim_port = -1;
+ int dev = 1; /* backwards starts at 1 so forwards can use 0 */
+
+ while ((option = getopt(argc, argv,"rb:h:s:")) != -1) {
+ switch (option) {
+ case 'b' :
+ host = optarg;
+ break;
+ case 'h' :
+ host_port = atoi(optarg);
+ break;
+ case 's' :
+ sim_port = atoi(optarg);
+ break;
+ default:
+ print_usage();
+ exit(1);
+ }
+ }
+
+ if (host_port == -1 || sim_port ==-1) {
+ print_usage();
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * A host/backwards connection will use dev=0 and conn >= 0.
+ * The forwards connection will use dev >= 1 and conn=0
+ */
+ if (host) {
+ sock_desc = socket(PF_INET, SOCK_STREAM, 0);
+ ser.sin_family = AF_INET;
+ ser.sin_addr.s_addr = INADDR_ANY;
+ ser.sin_port = htons(sim_port);
+
+ if (bind(sock_desc, (struct sockaddr *) &ser, sizeof(ser)) < 0) {
+ perror("Can't connect to sim port");
+ rc = -1;
+ goto out;
+ }
+
+ listen(sock_desc, 3);
+ } else {
+ /*
+ * Cleaning up old bogus socket.
+ */
+ sprintf(cmd, "mysim bogus socket cleanup");
+ callthru_tcl(cmd, strlen(cmd));
+ sleep(1); /* Cleanup takes a while */
+ sprintf(cmd, "mysim bogus socket init 0 server "
+ "127.0.0.1 %i poll 0 nonblock", host_port);
+ callthru_tcl(cmd, strlen(cmd));
+ }
+
+ while (1) {
+
+ if (host) {
+ sock = accept(sock_desc, (struct sockaddr *)&client, (socklen_t*)&c);
+ if (sock < 0) {
+ perror("accept failed");
+ rc = -1;
+ goto out;
+ }
+
+ sprintf(cmd, "mysim bogus socket init %i client %s %i poll 0",
+ dev, host, host_port);
+ callthru_tcl(cmd, strlen(cmd));
+ while (bogus_socket_conn_probe(dev, NULL, 0) == -1)
+ sleep(1);
+ } else {
+ struct timespec t;
+ t.tv_sec = 0;
+ t.tv_nsec = 10000000;
+ do {
+ conn = bogus_socket_conn_probe(0, NULL, -1);
+ nanosleep(&t , NULL);
+ } while (conn == -1);
+
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ ser.sin_family = AF_INET;
+ ser.sin_port = htons(sim_port);
+ ser.sin_addr.s_addr = inet_addr("127.0.0.1");
+ memset(ser.sin_zero, '\0', sizeof ser.sin_zero);
+
+ if (connect(sock, (struct sockaddr *) &ser, sizeof(ser))) {
+ perror("Can't connect to sim port");
+ rc = -1;
+ goto out;
+ }
+ }
+
+ si = malloc(sizeof(struct sock_info));
+ si->host = host;
+ si->sock = sock;
+ si->dev = host?dev:0;
+ si->open = 1;
+ si->conn = host?0:conn;
+
+ if (pthread_create(&sockets_thread, NULL, connect_sockets, si)) {
+ rc = -1;
+ goto out;
+ }
+
+ if (one_shot)
+ break;
+ ++dev; // FIXME: do a real allocator
+ }
+out:
+ exit(rc);
+}