Initial import of OsmocomBB into git repository
[osmocom-bb.git] / src / host / layer2 / src / layer2_main.c
1 /* Main method of the layer2 stack */
2 /* (C) 2010 by Holger Hans Peter Freyther
3  *
4  * All Rights Reserved
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  */
21
22 #include <osmocom/osmocom_layer2.h>
23 #include <osmocom/osmocom_data.h>
24
25 #include <osmocom/debug.h>
26 #include <osmocom/msgb.h>
27 #include <osmocom/talloc.h>
28
29 #include <arpa/inet.h>
30
31 #include <sys/socket.h>
32 #include <sys/un.h>
33
34 #define _GNU_SOURCE
35 #include <getopt.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <fcntl.h>
40
41 #define GSM_L2_LENGTH 256
42
43 static void *l2_ctx = NULL;
44 static char *socket_path = "/tmp/osmocom_l2";
45 static struct osmocom_ms *ms = NULL;
46
47 static int layer2_read(struct bsc_fd *fd, unsigned int flags)
48 {
49         struct msgb *msg;
50         u_int16_t len;
51         int rc;
52
53         msg = msgb_alloc(GSM_L2_LENGTH, "Layer2");
54         if (!msg) {
55                 fprintf(stderr, "Failed to allocate msg.\n");
56                 return -1;
57         }
58
59         rc = read(fd->fd, &len, sizeof(len));
60         if (rc < sizeof(len)) {
61                 fprintf(stderr, "Short read. Error.\n");
62                 exit(2);
63         }
64
65         if (ntohs(len) > GSM_L2_LENGTH) {
66                 fprintf(stderr, "Length is too big: %u\n", ntohs(len));
67                 msgb_free(msg);
68                 return -1;
69         }
70
71
72         /* blocking read for the poor... we can starve in here... */
73         msg->l2h = msgb_put(msg, ntohs(len));
74         rc = read(fd->fd, msg->l2h, msgb_l2len(msg));
75         if (rc != msgb_l2len(msg)) {
76                 fprintf(stderr, "Can not read data: rc: %d errno: %d\n", rc, errno);
77                 msgb_free(msg);
78                 return -1;
79         }
80
81         osmo_recv((struct osmocom_ms *) fd->data, msg);
82         msgb_free(msg);
83         return 0;
84 }
85
86 int osmo_send_l1(struct osmocom_ms *ms, struct msgb *msg)
87 {
88         int rc;
89         uint16_t *len;
90
91         LOGP(DMUX, LOGL_INFO, "Sending: '%s'\n", hexdump(msg->data, msg->len));
92
93         
94         len = (uint16_t *) msgb_push(msg, sizeof(*len));
95         *len = htons(msg->len - sizeof(*len));
96
97         /* TODO: just enqueue the message and wait for ready write.. */
98         rc = write(ms->bfd.fd, msg->data, msg->len);
99         if (rc != msg->len) {
100                 fprintf(stderr, "Failed to write data: rc: %d\n", rc);
101                 msgb_free(msg);
102                 return -1;
103         }
104
105         msgb_free(msg);
106         return 0;
107 }
108
109 static void print_usage()
110 {
111         printf("Usage: ./layer2\n");
112 }
113
114 static void print_help()
115 {
116         printf(" Some help...\n");
117         printf("  -h --help this text\n");
118         printf("  -s --socket /tmp/osmocom_l2. Path to the unix domain socket\n");
119         printf("  -a --arfcn NR. The ARFCN to be used for layer2.\n");
120 }
121
122 static void handle_options(int argc, char **argv)
123 {
124         while (1) {
125                 int option_index = 0, c;
126                 static struct option long_options[] = {
127                         {"help", 0, 0, 'h'},
128                         {"socket", 1, 0, 's'},
129                         {"arfcn", 1, 0, 'a'},
130                         {0, 0, 0, 0},
131                 };
132
133                 c = getopt_long(argc, argv, "hs:a:",
134                                 long_options, &option_index);
135                 if (c == -1)
136                         break;
137
138                 switch (c) {
139                 case 'h':
140                         print_usage();
141                         print_help();
142                         exit(0);
143                         break;
144                 case 's':
145                         socket_path = talloc_strdup(l2_ctx, optarg);
146                         break;
147                 case 'a':
148                         ms->arfcn = atoi(optarg);
149                         break;
150                 default:
151                         break;
152                 }
153         }
154 }
155
156 int main(int argc, char **argv)
157 {
158         int rc;
159         struct sockaddr_un local;
160
161         l2_ctx = talloc_named_const(NULL, 1, "layer2 context");
162
163         ms = talloc_zero(l2_ctx, struct osmocom_ms);
164         if (!ms) {
165                 fprintf(stderr, "Failed to allocate MS\n");
166                 exit(1);
167         }
168
169         ms->arfcn = 871;
170
171         handle_options(argc, argv);
172
173         ms->bfd.fd = socket(AF_UNIX, SOCK_STREAM, 0);
174         if (ms->bfd.fd < 0) {
175                 fprintf(stderr, "Failed to create unix domain socket.\n");
176                 exit(1);
177         }
178
179         local.sun_family = AF_UNIX;
180         strncpy(local.sun_path, socket_path, sizeof(local.sun_path));
181         local.sun_path[sizeof(local.sun_path) - 1] = '\0';
182
183         rc = connect(ms->bfd.fd, (struct sockaddr *) &local,
184                      sizeof(local.sun_family) + strlen(local.sun_path));
185         if (rc < 0) {
186                 fprintf(stderr, "Failed to connect to '%s'.\n", local.sun_path);
187                 exit(1);
188         }
189
190         ms->bfd.when = BSC_FD_READ;
191         ms->bfd.cb = layer2_read;
192         ms->bfd.data = ms;
193
194         if (bsc_register_fd(&ms->bfd) != 0) {
195                 fprintf(stderr, "Failed to register fd.\n");
196                 exit(1);
197         }
198
199         while (1) {
200                 bsc_select_main(0);
201         }
202
203
204         return 0;
205 }