Skip to content

Commit 7f64793

Browse files
add: INPORTW, INPORTD, INPORT, OUTPORT, OUTPORTW, OUTPORTD, UDPBIND, UDPUNBIND, UDPREAD$, UDPWRITE
1 parent 7633c99 commit 7f64793

12 files changed

Lines changed: 242 additions & 1 deletion

File tree

include/basic/context.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
#include <stdbool.h>
88
#include "buddy_allocator.h"
99

10+
typedef struct {
11+
uint16_t source_port;
12+
const char* ip;
13+
const char* data;
14+
uint64_t length;
15+
struct queued_udp_packet* prev;
16+
struct queued_udp_packet* next;
17+
} queued_udp_packet;
1018

1119
/**
1220
* @brief BASIC program context.
@@ -321,6 +329,13 @@ typedef struct basic_ctx {
321329
* The allocator is used to manage dynamic memory for the program's variables and data structures.
322330
*/
323331
buddy_allocator_t* allocator;
332+
333+
queued_udp_packet* udp_packets[65536];
334+
queued_udp_packet* udp_list_tail[65536];
335+
336+
spinlock_t udp_read_lock;
337+
338+
queued_udp_packet last_packet;
324339
} basic_ctx;
325340

326341
/**

include/basic/lowlevel.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,15 @@ char* basic_intoasc(struct basic_ctx* ctx);
104104
* @return The CPUID result of the specified register.
105105
*/
106106
int64_t basic_cpuid(struct basic_ctx* ctx);
107+
108+
void outport_statement(struct basic_ctx* ctx);
109+
110+
void outportw_statement(struct basic_ctx* ctx);
111+
112+
void outportd_statement(struct basic_ctx* ctx);
113+
114+
int64_t basic_inport(struct basic_ctx* ctx);
115+
116+
int64_t basic_inportw(struct basic_ctx* ctx);
117+
118+
int64_t basic_inportd(struct basic_ctx* ctx);

include/basic/sockets.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,11 @@ void connect_statement(struct basic_ctx* ctx);
9191
* @param ctx BASIC context.
9292
*/
9393
void sockread_statement(struct basic_ctx* ctx);
94+
95+
void udpwrite_statement(struct basic_ctx* ctx);
96+
97+
void udpbind_statement(struct basic_ctx* ctx);
98+
99+
void udpunbind_statement(struct basic_ctx* ctx);
100+
101+
char* basic_udpread(struct basic_ctx* ctx);

include/basic/tokenizer.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@
148148
T(ENDWHILE) \
149149
T(SLEEP) \
150150
T(CONTINUE) \
151+
T(UDPBIND) \
152+
T(UDPUNBIND) \
153+
T(UDPWRITE) \
154+
T(OUTPORT) \
155+
T(OUTPORTW) \
156+
T(OUTPORTD) \
151157
T(KGET)
152158

153159
GENERATE_ENUM_LIST(TOKEN, token_t)

include/udp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,5 @@ void udp_handle_packet([[maybe_unused]] ip_packet_t* encap_packet, udp_packet_t*
5959
* @return port number that was allocated
6060
*/
6161
uint16_t udp_register_daemon(uint16_t dst_port, udp_daemon_handler handler, void* opaque);
62+
63+
bool udp_unregister_daemon(uint16_t dst_port, udp_daemon_handler handler);

src/basic/function.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ struct basic_int_fn builtin_int[] =
6565
{ basic_getweekday, "WEEKDAY" },
6666
{ basic_getyear, "YEAR" },
6767
{ basic_get_day_of_year, "YDAY" },
68+
{ basic_inportw, "INPORTW" },
69+
{ basic_inportd, "INPORTD" },
70+
{ basic_inport, "INPORT" },
6871
{ NULL, NULL },
6972
};
7073

@@ -129,6 +132,7 @@ struct basic_str_fn builtin_str[] =
129132
{ basic_date, "DATE$" },
130133
{ basic_time, "TIME$" },
131134
{ basic_get_upstr, "UPTIME$" },
135+
{ basic_udpread, "UDPREAD$" },
132136
{ NULL, NULL },
133137
};
134138

src/basic/lowlevel.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,57 @@ int64_t basic_cpuid(struct basic_ctx* ctx)
159159
return get_cpuid_reg(ctx, reg);
160160
}
161161

162+
int64_t basic_inport(struct basic_ctx* ctx)
163+
{
164+
PARAMS_START;
165+
PARAMS_GET_ITEM(BIP_INT);
166+
int64_t port = intval;
167+
PARAMS_END("INPORT", -1);
168+
return inb(port);
169+
}
170+
171+
int64_t basic_inportw(struct basic_ctx* ctx)
172+
{
173+
PARAMS_START;
174+
PARAMS_GET_ITEM(BIP_INT);
175+
int64_t port = intval;
176+
PARAMS_END("INPORTW", -1);
177+
return inw(port);
178+
}
179+
180+
int64_t basic_inportd(struct basic_ctx* ctx)
181+
{
182+
PARAMS_START;
183+
PARAMS_GET_ITEM(BIP_INT);
184+
int64_t port = intval;
185+
PARAMS_END("INPORTD", -1);
186+
return inl(port);
187+
}
188+
189+
void outport_statement(struct basic_ctx* ctx) {
190+
accept_or_return(OUTPORT, ctx);
191+
int64_t port = expr(ctx);
192+
accept_or_return(COMMA, ctx);
193+
int64_t value = expr(ctx) & 0xFF;
194+
accept_or_return(NEWLINE, ctx);
195+
outb(port, value);
196+
}
197+
198+
void outportw_statement(struct basic_ctx* ctx) {
199+
accept_or_return(OUTPORTW, ctx);
200+
int64_t port = expr(ctx);
201+
accept_or_return(COMMA, ctx);
202+
int64_t value = expr(ctx) & 0xFFFF;
203+
accept_or_return(NEWLINE, ctx);
204+
outw(port, value);
205+
}
206+
207+
void outportd_statement(struct basic_ctx* ctx) {
208+
accept_or_return(OUTPORTD, ctx);
209+
int64_t port = expr(ctx);
210+
accept_or_return(COMMA, ctx);
211+
int64_t value = expr(ctx) & 0xFFFFFFFF;
212+
accept_or_return(NEWLINE, ctx);
213+
outl(port, value);
214+
}
215+

src/basic/main.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ struct basic_ctx *basic_init(const char *program, uint32_t pid, const char *file
171171
ctx->debug_status = 0;
172172
ctx->debug_breakpoints = NULL;
173173
ctx->debug_breakpoint_count = 0;
174+
memset(ctx->udp_packets, 0, sizeof(ctx->udp_packets));
175+
memset(ctx->udp_list_tail, 0, sizeof(ctx->udp_list_tail));
176+
memset(&ctx->last_packet, 0, sizeof(ctx->last_packet));
177+
init_spinlock(&ctx->udp_read_lock);
174178
ctx->if_nest_level = 0;
175179
ctx->errored = false;
176180
ctx->error_handler = NULL;
@@ -382,6 +386,10 @@ struct basic_ctx *basic_clone(struct basic_ctx *old) {
382386
ctx->current_token = NO_TOKEN;
383387
ctx->error_handler = old->error_handler;
384388
ctx->sleep_until = old->sleep_until;
389+
memset(ctx->udp_packets, 0, sizeof(ctx->udp_packets));
390+
memset(ctx->udp_list_tail, 0, sizeof(ctx->udp_list_tail));
391+
memset(&ctx->last_packet, 0, sizeof(ctx->last_packet));
392+
init_spinlock(&ctx->udp_read_lock);
385393
ctx->int_variables = old->int_variables;
386394
ctx->str_variables = old->str_variables;
387395
ctx->eval_linenum = old->eval_linenum;

src/basic/sockets.c

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,4 +242,109 @@ void sockwrite_statement(struct basic_ctx* ctx)
242242
}
243243

244244
static void basic_udp_handle_packet(uint32_t src_ip, uint16_t src_port, uint16_t dst_port, void* data, uint32_t length, void* opaque) {
245-
}
245+
basic_ctx* ctx = (basic_ctx*)opaque;
246+
if (!opaque) {
247+
return;
248+
}
249+
queued_udp_packet* packet = buddy_malloc(ctx->allocator, sizeof(queued_udp_packet));
250+
char ip[MAX_STRINGLEN];
251+
get_ip_str(ip, src_ip);
252+
packet->length = length;
253+
packet->data = buddy_strdup(ctx->allocator, data);
254+
packet->ip = buddy_strdup(ctx->allocator, ip);
255+
packet->source_port = src_port;
256+
packet->next = NULL;
257+
uint64_t flags;
258+
lock_spinlock_irq(&ctx->udp_read_lock, &flags);
259+
packet->prev = (struct queued_udp_packet*)ctx->udp_list_tail[dst_port];
260+
if (ctx->udp_list_tail[dst_port] == NULL) {
261+
ctx->udp_list_tail[dst_port] = packet;
262+
ctx->udp_packets[dst_port] = packet;
263+
} else {
264+
ctx->udp_list_tail[dst_port]->next = (struct queued_udp_packet*)packet;
265+
ctx->udp_list_tail[dst_port] = packet;
266+
}
267+
unlock_spinlock_irq(&ctx->udp_read_lock, flags);
268+
}
269+
270+
void udpwrite_statement(struct basic_ctx* ctx) {
271+
accept_or_return(UDPWRITE, ctx);
272+
const char* dest_ip = str_expr(ctx);
273+
accept_or_return(COMMA, ctx);
274+
int64_t source_port = expr(ctx);
275+
accept_or_return(COMMA, ctx);
276+
int64_t dest_port = expr(ctx);
277+
accept_or_return(COMMA, ctx);
278+
const char* data = str_expr(ctx);
279+
accept_or_return(NEWLINE, ctx);
280+
if (source_port > 65535 || source_port < 0 || dest_port > 65535 || dest_port < 0) {
281+
tokenizer_error_print(ctx, "Invalid UDP port number");
282+
}
283+
if (strlen(data) == 0 || strlen(data) > 65530) {
284+
tokenizer_error_print(ctx, "Invalid UDP packet length");
285+
}
286+
udp_send_packet(str_to_ip(dest_ip), source_port, dest_port, (void*)data, strlen(data));
287+
}
288+
289+
void udpbind_statement(struct basic_ctx* ctx) {
290+
accept_or_return(UDPBIND, ctx);
291+
const char* bind_ip = str_expr(ctx);
292+
(void)bind_ip;
293+
accept_or_return(COMMA, ctx);
294+
int64_t port = expr(ctx);
295+
if (port > 65535 || port < 0) {
296+
tokenizer_error_print(ctx, "Invalid UDP port number");
297+
}
298+
accept_or_return(NEWLINE, ctx);
299+
udp_register_daemon(port, &basic_udp_handle_packet, ctx);
300+
}
301+
302+
void udpunbind_statement(struct basic_ctx* ctx) {
303+
accept_or_return(UDPUNBIND, ctx);
304+
const char* bind_ip = str_expr(ctx);
305+
(void)bind_ip;
306+
accept_or_return(COMMA, ctx);
307+
int64_t port = expr(ctx);
308+
if (port > 65535 || port < 0) {
309+
tokenizer_error_print(ctx, "Invalid UDP port number");
310+
}
311+
accept_or_return(NEWLINE, ctx);
312+
udp_unregister_daemon(port, &basic_udp_handle_packet);
313+
}
314+
315+
char* basic_udpread(struct basic_ctx* ctx) {
316+
PARAMS_START;
317+
PARAMS_GET_ITEM(BIP_INT);
318+
PARAMS_END("UDPREAD$","");
319+
int64_t port = intval;
320+
if (port > 65535 || port < 0) {
321+
tokenizer_error_print(ctx, "Invalid UDP port number");
322+
}
323+
if (ctx->last_packet.ip) {
324+
buddy_free(ctx->allocator, ctx->last_packet.ip);
325+
}
326+
if (ctx->last_packet.data) {
327+
buddy_free(ctx->allocator, ctx->last_packet.data);
328+
}
329+
memset(&ctx->last_packet, 0, sizeof(ctx->last_packet));
330+
uint64_t flags;
331+
lock_spinlock_irq(&ctx->udp_read_lock, &flags);
332+
queued_udp_packet* queue = ctx->udp_packets[port];
333+
if (queue) {
334+
ctx->last_packet = *queue;
335+
if (queue == ctx->udp_list_tail[port]) {
336+
/* This packet is the tail packet */
337+
ctx->udp_list_tail[port] = (queued_udp_packet *)ctx->udp_list_tail[port]->prev;
338+
if (ctx->udp_list_tail[port]) {
339+
ctx->udp_list_tail[port]->next = NULL;
340+
}
341+
}
342+
ctx->udp_packets[port] = (queued_udp_packet *)queue->next;
343+
if (ctx->udp_packets[port]) {
344+
ctx->udp_packets[port]->prev = NULL;
345+
}
346+
buddy_free(ctx->allocator, queue);
347+
}
348+
unlock_spinlock_irq(&ctx->udp_read_lock, flags);
349+
return ctx->last_packet.data ? (char*)ctx->last_packet.data : "";
350+
}

src/basic/statement.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ void statement(struct basic_ctx* ctx)
8383
return connect_statement(ctx);
8484
case SOCKCLOSE:
8585
return sockclose_statement(ctx);
86+
case OUTPORT:
87+
return outport_statement(ctx);
88+
case OUTPORTW:
89+
return outportw_statement(ctx);
90+
case OUTPORTD:
91+
return outportd_statement(ctx);
8692
case POINT:
8793
return point_statement(ctx);
8894
case CLS:
@@ -158,6 +164,12 @@ void statement(struct basic_ctx* ctx)
158164
return off_statement(ctx);
159165
case SLEEP:
160166
return sleep_statement(ctx);
167+
case UDPWRITE:
168+
return udpwrite_statement(ctx);
169+
case UDPBIND:
170+
return udpbind_statement(ctx);
171+
case UDPUNBIND:
172+
return udpunbind_statement(ctx);
161173
case NEWLINE:
162174
/* Blank trailing line at end of program, ignore */
163175
return;

0 commit comments

Comments
 (0)