📄 udp.c
字号:
/*udp.c*/#include "inet.h"#include "assert.h"#include "buf.h"#include "clock.h"#include "io.h"#include "ip.h"#include "sr.h"#include "type.h"#include "udp.h"INIT_PANIC();#define UDP_PORT_NR 1#define UDP_FD_NR 32typedef struct udp_port{ int up_flags; int up_state; int up_ipfd; int up_minor; int up_ipdev; acc_t *up_wr_pack; ipaddr_t up_ipaddr; struct udp_fd *up_next_fd; struct udp_fd *up_write_fd;} udp_port_t;#define UPF_EMPTY 0x0#define UPF_WRITE_IP 0x1#define UPF_WRITE_SP 0x2#define UPF_READ_IP 0x4#define UPF_READ_SP 0x8#define UPF_SUSPEND 0x10#define UPF_MORE2WRITE 0x20#define UPS_EMPTY 0#define UPS_SETPROTO 1#define UPS_GETCONF 2#define UPS_MAIN 3#define UPS_ERROR 4typedef struct udp_fd{ int uf_flags; udp_port_t *uf_port; int uf_ioreq; int uf_srfd; nwio_udpopt_t uf_udpopt; get_userdata_t uf_get_userdata; put_userdata_t uf_put_userdata; acc_t *uf_pack; acc_t *uf_rd_buf; size_t uf_rd_count; size_t uf_wr_count; time_t uf_exp_tim;} udp_fd_t;#define UFF_EMPTY 0x0#define UFF_INUSE 0x1#define UFF_IOCTL_IP 0x2#define UFF_READ_IP 0x4#define UFF_WRITE_IP 0x8#define UFF_OPTSET 0x10FORWARD void read_ip_packets ARGS(( udp_port_t *udp_port ));FORWARD void udp_buffree ARGS(( int priority, size_t reqsize ));FORWARD void udp_main ARGS(( udp_port_t *udp_port ));FORWARD acc_t *udp_get_data ARGS(( int fd, size_t offset, size_t count, int for_ioctl ));FORWARD int udp_put_data ARGS(( int fd, size_t offset, acc_t *data, int for_ioctl ));FORWARD void udp_restart_write_port ARGS(( udp_port_t *udp_port ));FORWARD void process_inc_fragm ARGS(( udp_port_t *udp_port, acc_t *data ));FORWARD int reply_thr_put ARGS(( udp_fd_t *ucp_fd, int reply, int for_ioctl ));FORWARD void reply_thr_get ARGS(( udp_fd_t *udp_fd, int reply, int for_ioctl ));FORWARD int udp_setopt ARGS(( udp_fd_t *udp_fd ));FORWARD udpport_t find_unused_port ARGS(( int fd ));FORWARD int is_unused_port ARGS(( Udpport_t port ));FORWARD int udp_packet2user ARGS(( udp_fd_t *udp_fd ));FORWARD void restart_write_fd ARGS(( udp_fd_t *udp_fd ));FORWARD u16_t pack_oneCsum ARGS(( acc_t *pack ));PRIVATE udp_port_t udp_port_table[UDP_PORT_NR];PRIVATE udp_fd_t udp_fd_table[UDP_FD_NR];PUBLIC void udp_init(){ udp_fd_t *udp_fd; udp_port_t *udp_port; int i, result; assert (BUF_S >= sizeof(struct nwio_ipopt)); assert (BUF_S >= sizeof(struct nwio_ipconf)); assert (BUF_S >= sizeof(struct nwio_udpopt)); assert (BUF_S >= sizeof(struct udp_io_hdr)); assert (UDP_HDR_SIZE == sizeof(udp_hdr_t)); assert (UDP_IO_HDR_SIZE == sizeof(udp_io_hdr_t)); udp_port_table[0].up_minor= UDP_DEV0; udp_port_table[0].up_ipdev= IP0; for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++) { udp_fd->uf_flags= UFF_EMPTY; } bf_logon(udp_buffree); for (i= 0, udp_port= udp_port_table; i<UDP_PORT_NR; i++, udp_port++) { udp_port->up_flags= UPF_EMPTY; udp_port->up_state= UPS_EMPTY; udp_port->up_next_fd= udp_fd_table; udp_port->up_write_fd= NULL; result= sr_add_minor (udp_port->up_minor, udp_port-udp_port_table, udp_open, udp_close, udp_read, udp_write, udp_ioctl, udp_cancel); assert (result >= 0); udp_main(udp_port); }}PRIVATE void udp_main(udp_port)udp_port_t *udp_port;{ udp_fd_t *udp_fd; int result, i; switch (udp_port->up_state) { case UPS_EMPTY: udp_port->up_state= UPS_SETPROTO; udp_port->up_ipfd= ip_open(udp_port->up_ipdev, udp_port-udp_port_table, udp_get_data, udp_put_data); if (udp_port->up_ipfd < 0) { udp_port->up_state= UPS_ERROR; printf("%s, %d: unable to open ip port\n", __FILE__, __LINE__); return; } result= ip_ioctl(udp_port->up_ipfd, NWIOSIPOPT); if (result == NW_SUSPEND) udp_port->up_flags |= UPF_SUSPEND; if (result<0) { return; } if (udp_port->up_state != UPS_GETCONF) return; /* drops through */ case UPS_GETCONF: udp_port->up_flags &= ~UPF_SUSPEND; result= ip_ioctl(udp_port->up_ipfd, NWIOGIPCONF); if (result == NW_SUSPEND) udp_port->up_flags |= UPF_SUSPEND; if (result<0) { return; } if (udp_port->up_state != UPS_MAIN) return; /* drops through */ case UPS_MAIN: udp_port->up_flags &= ~UPF_SUSPEND; for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++) { if (!(udp_fd->uf_flags & UFF_INUSE)) continue; if (udp_fd->uf_port != udp_port) continue; if (udp_fd->uf_flags & UFF_IOCTL_IP) udp_ioctl(i, udp_fd->uf_ioreq); } read_ip_packets(udp_port); return; default:#if DEBUG { where(); printf("udp_port_table[%d].up_state= %d\n", udp_port-udp_port_table, udp_port->up_state); }#endif ip_panic(( "unknown state" )); break; }}int udp_open (port, srfd, get_userdata, put_userdata)int port;int srfd;get_userdata_t get_userdata;put_userdata_t put_userdata;{ int i; udp_fd_t *udp_fd; for (i= 0; i<UDP_FD_NR && (udp_fd_table[i].uf_flags & UFF_INUSE); i++); if (i>= UDP_FD_NR) {#if DEBUG { where(); printf("out of fds\n"); }#endif return EOUTOFBUFS; } udp_fd= &udp_fd_table[i]; udp_fd->uf_flags= UFF_INUSE; udp_fd->uf_port= &udp_port_table[port]; udp_fd->uf_srfd= srfd; udp_fd->uf_udpopt.nwuo_flags= UDP_DEF_OPT; udp_fd->uf_get_userdata= get_userdata; udp_fd->uf_put_userdata= put_userdata; udp_fd->uf_pack= 0; return i;}PRIVATE acc_t *udp_get_data (port, offset, count, for_ioctl)int port;size_t offset;size_t count;int for_ioctl;{ udp_port_t *udp_port; udp_fd_t *udp_fd; int result; udp_port= &udp_port_table[port]; switch(udp_port->up_state) { case UPS_SETPROTO:assert (for_ioctl); if (!count) { result= (int)offset; if (result<0) { udp_port->up_state= UPS_ERROR; break; } udp_port->up_state= UPS_GETCONF; if (udp_port->up_flags & UPF_SUSPEND) udp_main(udp_port); return NULL; } else { struct nwio_ipopt *ipopt; acc_t *acc;assert (!offset);assert (count == sizeof(*ipopt)); acc= bf_memreq(sizeof(*ipopt)); ipopt= (struct nwio_ipopt *)ptr2acc_data(acc); ipopt->nwio_flags= NWIO_COPY | NWIO_EN_LOC | NWIO_EN_BROAD | NWIO_REMANY | NWIO_PROTOSPEC | NWIO_HDR_O_ANY | NWIO_RWDATALL; ipopt->nwio_proto= IPPROTO_UDP; return acc; } case UPS_MAIN:assert (!for_ioctl);assert (udp_port->up_flags & UPF_WRITE_IP); if (!count) { result= (int)offset;#if DEBUG & 256 { where(); printf("result of ip_write is %d\n", result); }#endifassert (udp_port->up_wr_pack); bf_afree(udp_port->up_wr_pack); udp_port->up_wr_pack= 0; if (udp_port->up_flags & UPF_WRITE_SP) { if (udp_port->up_write_fd) { udp_fd= udp_port->up_write_fd; udp_port->up_write_fd= NULL; udp_fd->uf_flags &= ~UFF_WRITE_IP; reply_thr_get(udp_fd, result, FALSE); } udp_port->up_flags &= ~(UPF_WRITE_SP | UPF_WRITE_IP); if (udp_port->up_flags & UPF_MORE2WRITE) { udp_restart_write_port(udp_port); } } else udp_port->up_flags &= ~UPF_WRITE_IP; } else { return bf_cut (udp_port->up_wr_pack, offset, count); } break; default: printf("udp_get_data(%d, 0x%x, 0x%x) called but up_state= 0x%x\n", port, offset, count, udp_port->up_state); break; } return NULL;}PRIVATE int udp_put_data (fd, offset, data, for_ioctl)int fd;size_t offset;acc_t *data;int for_ioctl;{ udp_port_t *udp_port; int result; udp_port= &udp_port_table[fd]; switch (udp_port->up_state) { case UPS_GETCONF: if (!data) { result= (int)offset; if (result<0) { udp_port->up_state= UPS_ERROR; return NW_OK; } udp_port->up_state= UPS_MAIN; if (udp_port->up_flags & UPF_SUSPEND) udp_main(udp_port); } else { struct nwio_ipconf *ipconf; data= bf_packIffLess(data, sizeof(*ipconf)); ipconf= (struct nwio_ipconf *)ptr2acc_data(data);assert (ipconf->nwic_flags & NWIC_IPADDR_SET); udp_port->up_ipaddr= ipconf->nwic_ipaddr; bf_afree(data); } break; case UPS_MAIN:assert (udp_port->up_flags & UPF_READ_IP); if (!data) { result= (int)offset;compare (result, >=, 0); if (udp_port->up_flags & UPF_READ_SP) { udp_port->up_flags &= ~(UPF_READ_SP| UPF_READ_IP); read_ip_packets(udp_port); } else udp_port->up_flags &= ~UPF_READ_IP; } else {assert (!offset); /* This isn't a valid assertion but ip sends only * whole datagrams up */ process_inc_fragm(udp_port, data); } break; default: ip_panic(( "udp_put_data(%d, 0x%x, 0x%x) called but up_state= 0x%x\n", fd, offset, data, udp_port->up_state )); } return NW_OK;}int udp_ioctl (fd, req)int fd;int req;{ udp_fd_t *udp_fd; udp_port_t *udp_port; nwio_udpopt_t *udp_opt; acc_t *opt_acc; int type; int result; udp_fd= &udp_fd_table[fd]; type= req & IOCTYPE_MASK;assert (udp_fd->uf_flags & UFF_INUSE); udp_port= udp_fd->uf_port; udp_fd->uf_flags |= UFF_IOCTL_IP; udp_fd->uf_ioreq= req; if (udp_port->up_state != UPS_MAIN) return NW_SUSPEND; switch(type) { case NWIOSUDPOPT & IOCTYPE_MASK: if (req != NWIOSUDPOPT) { reply_thr_get (udp_fd, EBADIOCTL, TRUE); result= NW_OK; break; } result= udp_setopt(udp_fd); break; case NWIOGUDPOPT & IOCTYPE_MASK: if (req != NWIOGUDPOPT) { reply_thr_put(udp_fd, EBADIOCTL, TRUE); result= NW_OK; break; } opt_acc= bf_memreq(sizeof(*udp_opt));assert (opt_acc->acc_length == sizeof(*udp_opt)); udp_opt= (nwio_udpopt_t *)ptr2acc_data(opt_acc); *udp_opt= udp_fd->uf_udpopt; udp_opt->nwuo_locaddr= udp_fd->uf_port->up_ipaddr; result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, 0, opt_acc, TRUE); if (result == NW_OK) reply_thr_put(udp_fd, NW_OK, TRUE); break; default: reply_thr_get(udp_fd, EBADIOCTL, TRUE); result= NW_OK; break; } if (result != NW_SUSPEND) udp_fd->uf_flags &= ~UFF_IOCTL_IP; return result;}PRIVATE int udp_setopt(udp_fd)udp_fd_t *udp_fd;{ udp_fd_t *fd_ptr; nwio_udpopt_t oldopt, newopt; acc_t *data; int result; udpport_t port; unsigned int new_en_flags, new_di_flags, old_en_flags, old_di_flags, all_flags, flags; unsigned long new_flags; int i;#if DEBUG & 256 { where(); printf("in udp_setopt\n"); }#endif data= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, 0, sizeof(nwio_udpopt_t), TRUE); if (!data) return EFAULT; data= bf_packIffLess(data, sizeof(nwio_udpopt_t));assert (data->acc_length == sizeof(nwio_udpopt_t)); newopt= *(nwio_udpopt_t *)ptr2acc_data(data); bf_afree(data); oldopt= udp_fd->uf_udpopt;#if DEBUG & 256 { where(); printf("newopt.nwuo_flags= 0x%x, newopt.nwuo_locport= %d, newopt.nwuo_remport= %d\n", newopt.nwuo_flags, ntohs(newopt.nwuo_locport), ntohs(newopt.nwuo_remport)); }#endif old_en_flags= oldopt.nwuo_flags & 0xffff; old_di_flags= (oldopt.nwuo_flags >> 16) & 0xffff; new_en_flags= newopt.nwuo_flags & 0xffff; new_di_flags= (newopt.nwuo_flags >> 16) & 0xffff; if (new_en_flags & new_di_flags) {#if DEBUG { where(); printf("returning EBADMODE\n"); }#endif reply_thr_get(udp_fd, EBADMODE, TRUE); return NW_OK; } /* NWUO_ACC_MASK */ if (new_di_flags & NWUO_ACC_MASK) {#if DEBUG { where(); printf("returning EBADMODE\n"); }#endif reply_thr_get(udp_fd, EBADMODE, TRUE); return NW_OK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -