📄 udp.c
字号:
/*udp.cCopyright 1995 Philip Homburg*/#include "inet.h"#include "type.h"#include "assert.h"#include "buf.h"#include "clock.h"#include "icmp_lib.h"#include "io.h"#include "ip.h"#include "sr.h"#include "udp.h"#include "udp_int.h"THIS_FILEFORWARD void read_ip_packets ARGS(( udp_port_t *udp_port ));FORWARD void udp_buffree ARGS(( int priority ));#ifdef BUF_CONSISTENCY_CHECKFORWARD void udp_bufcheck ARGS(( void ));#endifFORWARD void udp_main ARGS(( udp_port_t *udp_port ));FORWARD int udp_select ARGS(( int fd, unsigned operations ));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 int udp_peek ARGS(( udp_fd_t * ));FORWARD int udp_sel_read ARGS(( udp_fd_t * ));FORWARD void udp_restart_write_port ARGS(( udp_port_t *udp_port ));FORWARD void udp_ip_arrived ARGS(( int port, acc_t *pack, size_t pack_size ));FORWARD void reply_thr_put ARGS(( udp_fd_t *udp_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 ));FORWARD void udp_rd_enqueue ARGS(( udp_fd_t *udp_fd, acc_t *pack, clock_t exp_tim ));FORWARD void hash_fd ARGS(( udp_fd_t *udp_fd ));FORWARD void unhash_fd ARGS(( udp_fd_t *udp_fd ));PUBLIC udp_port_t *udp_port_table;PUBLIC udp_fd_t udp_fd_table[UDP_FD_NR];PUBLIC void udp_prep(){ udp_port_table= alloc(udp_conf_nr * sizeof(udp_port_table[0]));}PUBLIC void udp_init(){ udp_fd_t *udp_fd; udp_port_t *udp_port; int i, j, ifno; 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)); for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++) { udp_fd->uf_flags= UFF_EMPTY; udp_fd->uf_rdbuf_head= NULL; }#ifndef BUF_CONSISTENCY_CHECK bf_logon(udp_buffree);#else bf_logon(udp_buffree, udp_bufcheck);#endif for (i= 0, udp_port= udp_port_table; i<udp_conf_nr; i++, udp_port++) { udp_port->up_ipdev= udp_conf[i].uc_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; udp_port->up_wr_pack= NULL; udp_port->up_port_any= NULL; for (j= 0; j<UDP_PORT_HASH_NR; j++) udp_port->up_port_hash[j]= NULL; ifno= ip_conf[udp_port->up_ipdev].ic_ifno; sr_add_minor(if2minor(ifno, UDP_DEV_OFF), i, udp_open, udp_close, udp_read, udp_write, udp_ioctl, udp_cancel, udp_select); udp_main(udp_port); }}PUBLIC int udp_open (port, srfd, get_userdata, put_userdata, put_pkt, select_res)int port;int srfd;get_userdata_t get_userdata;put_userdata_t put_userdata;put_pkt_t put_pkt;select_res_t select_res;{ 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) { DBLOCK(1, printf("out of fds\n")); return EAGAIN; } 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_select_res= select_res; assert(udp_fd->uf_rdbuf_head == NULL); udp_fd->uf_port_next= NULL; return i;}PUBLIC int udp_ioctl (fd, req)int fd;ioreq_t req;{ udp_fd_t *udp_fd; udp_port_t *udp_port; nwio_udpopt_t *udp_opt; acc_t *opt_acc; int result; udp_fd= &udp_fd_table[fd];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(req) { case NWIOSUDPOPT: result= udp_setopt(udp_fd); break; case NWIOGUDPOPT: 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; case NWIOUDPPEEK: result= udp_peek(udp_fd); 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;}PUBLIC int udp_read (fd, count)int fd;size_t count;{ udp_fd_t *udp_fd; acc_t *tmp_acc, *next_acc; udp_fd= &udp_fd_table[fd]; if (!(udp_fd->uf_flags & UFF_OPTSET)) { reply_thr_put(udp_fd, EBADMODE, FALSE); return NW_OK; } udp_fd->uf_rd_count= count; if (udp_fd->uf_rdbuf_head) { if (get_time() <= udp_fd->uf_exp_tim) return udp_packet2user (udp_fd); tmp_acc= udp_fd->uf_rdbuf_head; while (tmp_acc) { next_acc= tmp_acc->acc_ext_link; bf_afree(tmp_acc); tmp_acc= next_acc; } udp_fd->uf_rdbuf_head= NULL; } udp_fd->uf_flags |= UFF_READ_IP; return NW_SUSPEND;}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->up_ipdev, udp_get_data, udp_put_data, udp_ip_arrived, 0 /* no select_res */); if (udp_port->up_ipfd < 0) { udp_port->up_state= UPS_ERROR; DBLOCK(1, 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: DBLOCK(1, printf("udp_port_table[%d].up_state= %d\n", udp_port->up_ipdev, udp_port->up_state)); ip_panic(( "unknown state" )); break; }}PRIVATE int udp_select(fd, operations)int fd;unsigned operations;{ int i; unsigned resops; udp_fd_t *udp_fd; udp_fd= &udp_fd_table[fd]; assert (udp_fd->uf_flags & UFF_INUSE); resops= 0; if (operations & SR_SELECT_READ) { if (udp_sel_read(udp_fd)) resops |= SR_SELECT_READ; else if (!(operations & SR_SELECT_POLL)) udp_fd->uf_flags |= UFF_SEL_READ; } if (operations & SR_SELECT_WRITE) { /* Should handle special case when the interface is down */ resops |= SR_SELECT_WRITE; } if (operations & SR_SELECT_EXCEPTION) { printf("udp_select: not implemented for exceptions\n"); } return resops;}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;assert (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(0); 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 */ udp_ip_arrived(fd, data, bf_bufsize(data)); } break; default: ip_panic(( "udp_put_data(%d, 0x%x, %p) called but up_state= 0x%x\n", fd, offset, data, udp_port->up_state )); } return NW_OK;}PRIVATE int udp_setopt(udp_fd)udp_fd_t *udp_fd;{ udp_fd_t *fd_ptr; nwio_udpopt_t oldopt, newopt; acc_t *data; unsigned int new_en_flags, new_di_flags, old_en_flags, old_di_flags, all_flags, flags; unsigned long new_flags; int i; 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; 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) { DBLOCK(1, printf("returning EBADMODE\n")); reply_thr_get(udp_fd, EBADMODE, TRUE); return NW_OK; } /* NWUO_ACC_MASK */ if (new_di_flags & NWUO_ACC_MASK) { DBLOCK(1, printf("returning EBADMODE\n")); reply_thr_get(udp_fd, EBADMODE, TRUE); return NW_OK; /* access modes can't be disabled */ } if (!(new_en_flags & NWUO_ACC_MASK)) new_en_flags |= (old_en_flags & NWUO_ACC_MASK); /* NWUO_LOCPORT_MASK */ if (new_di_flags & NWUO_LOCPORT_MASK) { DBLOCK(1, printf("returning EBADMODE\n")); reply_thr_get(udp_fd, EBADMODE, TRUE); return NW_OK; /* the loc ports can't be disabled */ } if (!(new_en_flags & NWUO_LOCPORT_MASK)) { new_en_flags |= (old_en_flags & NWUO_LOCPORT_MASK); newopt.nwuo_locport= oldopt.nwuo_locport; } else if ((new_en_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SEL) { newopt.nwuo_locport= find_unused_port(udp_fd-udp_fd_table); } else if ((new_en_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET) { if (!newopt.nwuo_locport) { DBLOCK(1, printf("returning EBADMODE\n")); reply_thr_get(udp_fd, EBADMODE, TRUE); return NW_OK; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -