Create new 'gprs-sgsn' branch on top of 'gprs-conf'

This branch contains the partial SGSN/GGSN implementation that
was originally developed as part of the gprs branch.
diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c
index 8a8a198..fae9428 100644
--- a/openbsc/src/input/ipaccess.c
+++ b/openbsc/src/input/ipaccess.c
@@ -53,6 +53,7 @@
 struct ia_e1_handle {
 	struct bsc_fd listen_fd;
 	struct bsc_fd rsl_listen_fd;
+	struct bsc_fd gprs_fd;
 	struct gsm_network *gsmnet;
 };
 
@@ -602,6 +603,87 @@
 	return rc;
 }
 
+/* declare this as a weak symbol to ensure code will still build
+ * even if it does not provide this function */
+extern int gprs_ns_rcvmsg(struct msgb *msg) __attribute__((weak));
+
+static struct msgb *read_gprs_msg(struct bsc_fd *bfd, int *error)
+{
+	struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "Abis/IP/GPRS");
+	int ret = 0;
+
+	if (!msg) {
+		*error = -ENOMEM;
+		return NULL;
+	}
+
+	ret = recv(bfd->fd, msg->data, TS1_ALLOC_SIZE, 0);
+	if (ret < 0) {
+		fprintf(stderr, "recv error  %s\n", strerror(errno));
+		msgb_free(msg);
+		*error = ret;
+		return NULL;
+	} else if (ret == 0) {
+		msgb_free(msg);
+		*error = ret;
+		return NULL;
+	}
+
+	msg->l2h = msg->data;
+	msgb_put(msg, ret);
+
+	return msg;
+}
+
+static int handle_gprs_read(struct bsc_fd *bfd)
+{
+	int error;
+	struct msgb *msg = read_gprs_msg(bfd, &error);
+
+	if (!msg)
+		return error;
+
+	if (gprs_ns_rcvmsg)
+		return gprs_ns_rcvmsg(msg);
+	else {
+		msgb_free(msg);
+		return 0;
+	}
+}
+
+static int handle_gprs_write(struct bsc_fd *bfd)
+{
+}
+
+int ipac_gprs_send(struct msgb *msg)
+{
+	struct sockaddr_in sin;
+	int rc;
+
+	sin.sin_family = AF_INET;
+	inet_aton("192.168.100.111", &sin.sin_addr);
+	sin.sin_port = htons(23000);
+
+	rc = sendto(e1h->gprs_fd.fd, msg->data, msg->len, 0,
+		  (struct sockaddr *)&sin, sizeof(sin));
+
+	talloc_free(msg);
+
+	return rc;
+}
+
+/* UDP Port 23000 carries the LLC-in-BSSGP-in-NS protocol stack */
+static int gprs_fd_cb(struct bsc_fd *bfd, unsigned int what)
+{
+	int rc;
+
+	if (what & BSC_FD_READ)
+		rc = handle_gprs_read(bfd);
+	if (what & BSC_FD_WRITE)
+		rc = handle_gprs_write(bfd);
+
+	return rc;
+}
 
 struct e1inp_driver ipaccess_driver = {
 	.name = "ip.access",
@@ -708,13 +790,17 @@
 	return 0;
 }
 
-static int make_sock(struct bsc_fd *bfd, u_int16_t port,
+static int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port,
 		     int (*cb)(struct bsc_fd *fd, unsigned int what))
 {
 	struct sockaddr_in addr;
 	int ret, on = 1;
+	int type = SOCK_STREAM;
+
+	if (proto == IPPROTO_UDP)
+		type = SOCK_DGRAM;
 	
-	bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	bfd->fd = socket(AF_INET, type, proto);
 	bfd->cb = cb;
 	bfd->when = BSC_FD_READ;
 	//bfd->data = line;
@@ -739,11 +825,12 @@
 		return -EIO;
 	}
 
-	ret = listen(bfd->fd, 1);
-	if (ret < 0) {
-		perror("listen");
-		close(bfd->fd);
-		return ret;
+	if (proto != IPPROTO_UDP) {
+		ret = listen(bfd->fd, 1);
+		if (ret < 0) {
+			perror("listen");
+			return ret;
+		}
 	}
 	
 	ret = bsc_register_fd(bfd);
@@ -811,12 +898,19 @@
 	e1h->gsmnet = gsmnet;
 
 	/* Listen for OML connections */
-	ret = make_sock(&e1h->listen_fd, IPA_TCP_PORT_OML, listen_fd_cb);
+	ret = make_sock(&e1h->listen_fd, IPPROTO_TCP, IPA_TCP_PORT_OML,
+			listen_fd_cb);
 	if (ret < 0)
 		return ret;
 
 	/* Listen for RSL connections */
-	ret = make_sock(&e1h->rsl_listen_fd, IPA_TCP_PORT_RSL, rsl_listen_fd_cb);
+	ret = make_sock(&e1h->rsl_listen_fd, IPPROTO_TCP,
+			IPA_TCP_PORT_RSL, rsl_listen_fd_cb);
+	if (ret < 0)
+		return ret;
+
+	/* Listen for incoming GPRS packets */
+	ret = make_sock(&e1h->gprs_fd, IPPROTO_UDP, 23000, gprs_fd_cb);
 
 	return ret;
 }