123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
-
-
- #include <string.h>
- #include <byteswap.h>
- #include <ipxe/iobuf.h>
- #include <ipxe/xfer.h>
- #include <ipxe/udp.h>
- #include <ipxe/uaccess.h>
- #include <ipxe/process.h>
- #include <pxe.h>
-
-
-
- FILE_LICENCE ( GPL2_OR_LATER );
-
-
- struct pxe_udp_pseudo_header {
-
- IP4_t src_ip;
-
- UDP_PORT_t s_port;
-
- IP4_t dest_ip;
-
- UDP_PORT_t d_port;
- } __attribute__ (( packed ));
-
-
- struct pxe_udp_connection {
-
- struct interface xfer;
-
- struct sockaddr_in local;
-
- struct list_head list;
- };
-
-
- static int pxe_udp_deliver ( struct pxe_udp_connection *pxe_udp,
- struct io_buffer *iobuf,
- struct xfer_metadata *meta ) {
- struct pxe_udp_pseudo_header *pshdr;
- struct sockaddr_in *sin_src;
- struct sockaddr_in *sin_dest;
- int rc;
-
-
- assert ( meta );
- sin_src = ( struct sockaddr_in * ) meta->src;
- assert ( sin_src );
- assert ( sin_src->sin_family == AF_INET );
- sin_dest = ( struct sockaddr_in * ) meta->dest;
- assert ( sin_dest );
- assert ( sin_dest->sin_family == AF_INET );
-
-
- if ( ( rc = iob_ensure_headroom ( iobuf, sizeof ( *pshdr ) ) ) != 0 ) {
- DBG ( "PXE could not prepend pseudo-header\n" );
- rc = -ENOMEM;
- goto drop;
- }
- pshdr = iob_push ( iobuf, sizeof ( *pshdr ) );
- pshdr->src_ip = sin_src->sin_addr.s_addr;
- pshdr->s_port = sin_src->sin_port;
- pshdr->dest_ip = sin_dest->sin_addr.s_addr;
- pshdr->d_port = sin_dest->sin_port;
-
-
- list_add_tail ( &iobuf->list, &pxe_udp->list );
-
- return 0;
-
- drop:
- free_iob ( iobuf );
- return rc;
- }
-
-
- static struct interface_operation pxe_udp_xfer_operations[] = {
- INTF_OP ( xfer_deliver, struct pxe_udp_connection *, pxe_udp_deliver ),
- };
-
-
- static struct interface_descriptor pxe_udp_xfer_desc =
- INTF_DESC ( struct pxe_udp_connection, xfer, pxe_udp_xfer_operations );
-
-
- static struct pxe_udp_connection pxe_udp = {
- .xfer = INTF_INIT ( pxe_udp_xfer_desc ),
- .local = {
- .sin_family = AF_INET,
- },
- .list = LIST_HEAD_INIT ( pxe_udp.list ),
- };
-
-
- static PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
- int rc;
-
- DBG ( "PXENV_UDP_OPEN" );
-
-
- pxe_udp.local.sin_addr.s_addr = pxenv_udp_open->src_ip;
- DBG ( " %s\n", inet_ntoa ( pxe_udp.local.sin_addr ) );
-
-
- intf_restart ( &pxe_udp.xfer, 0 );
- if ( ( rc = udp_open_promisc ( &pxe_udp.xfer ) ) != 0 ) {
- DBG ( "PXENV_UDP_OPEN could not open promiscuous socket: %s\n",
- strerror ( rc ) );
- pxenv_udp_open->Status = PXENV_STATUS ( rc );
- return PXENV_EXIT_FAILURE;
- }
-
- pxenv_udp_open->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
- }
-
-
- static PXENV_EXIT_t
- pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
- struct io_buffer *iobuf;
- struct io_buffer *tmp;
-
- DBG ( "PXENV_UDP_CLOSE\n" );
-
-
- intf_restart ( &pxe_udp.xfer, 0 );
-
-
- list_for_each_entry_safe ( iobuf, tmp, &pxe_udp.list, list ) {
- list_del ( &iobuf->list );
- free_iob ( iobuf );
- }
-
- pxenv_udp_close->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
- }
-
-
- static PXENV_EXIT_t
- pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
- struct sockaddr_in dest;
- struct xfer_metadata meta = {
- .src = ( struct sockaddr * ) &pxe_udp.local,
- .dest = ( struct sockaddr * ) &dest,
- .netdev = pxe_netdev,
- };
- size_t len;
- struct io_buffer *iobuf;
- userptr_t buffer;
- int rc;
-
- DBG ( "PXENV_UDP_WRITE" );
-
-
- memset ( &dest, 0, sizeof ( dest ) );
- dest.sin_family = AF_INET;
- dest.sin_addr.s_addr = pxenv_udp_write->ip;
- dest.sin_port = pxenv_udp_write->dst_port;
-
-
-
- pxe_udp.local.sin_port = pxenv_udp_write->src_port;
- if ( ! pxe_udp.local.sin_port )
- pxe_udp.local.sin_port = htons ( 2069 );
-
-
-
-
-
- len = pxenv_udp_write->buffer_size;
- iobuf = xfer_alloc_iob ( &pxe_udp.xfer, len );
- if ( ! iobuf ) {
- DBG ( " out of memory\n" );
- pxenv_udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
- return PXENV_EXIT_FAILURE;
- }
- buffer = real_to_user ( pxenv_udp_write->buffer.segment,
- pxenv_udp_write->buffer.offset );
- copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len );
-
- DBG ( " %04x:%04x+%x %d->%s:%d\n", pxenv_udp_write->buffer.segment,
- pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
- ntohs ( pxenv_udp_write->src_port ),
- inet_ntoa ( dest.sin_addr ),
- ntohs ( pxenv_udp_write->dst_port ) );
-
-
- if ( ( rc = xfer_deliver ( &pxe_udp.xfer, iobuf, &meta ) ) != 0 ) {
- DBG ( "PXENV_UDP_WRITE could not transmit: %s\n",
- strerror ( rc ) );
- pxenv_udp_write->Status = PXENV_STATUS ( rc );
- return PXENV_EXIT_FAILURE;
- }
-
- pxenv_udp_write->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
- }
-
-
- static PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
- struct in_addr dest_ip_wanted = { .s_addr = pxenv_udp_read->dest_ip };
- struct in_addr dest_ip;
- struct io_buffer *iobuf;
- struct pxe_udp_pseudo_header *pshdr;
- uint16_t d_port_wanted = pxenv_udp_read->d_port;
- uint16_t d_port;
- userptr_t buffer;
- size_t len;
-
-
- if ( list_empty ( &pxe_udp.list ) )
- step();
-
-
- iobuf = list_first_entry ( &pxe_udp.list, struct io_buffer, list );
- if ( ! iobuf ) {
-
- DBG2 ( "PXENV_UDP_READ\n" );
- goto no_packet;
- }
- list_del ( &iobuf->list );
-
-
- assert ( iob_len ( iobuf ) >= sizeof ( *pshdr ) );
- pshdr = iobuf->data;
- iob_pull ( iobuf, sizeof ( *pshdr ) );
- dest_ip.s_addr = pshdr->dest_ip;
- d_port = pshdr->d_port;
- DBG ( "PXENV_UDP_READ" );
-
-
- if ( dest_ip_wanted.s_addr &&
- ( dest_ip_wanted.s_addr != dest_ip.s_addr ) ) {
- DBG ( " wrong IP %s", inet_ntoa ( dest_ip ) );
- DBG ( " (wanted %s)\n", inet_ntoa ( dest_ip_wanted ) );
- goto drop;
- }
- if ( d_port_wanted && ( d_port_wanted != d_port ) ) {
- DBG ( " wrong port %d", htons ( d_port ) );
- DBG ( " (wanted %d)\n", htons ( d_port_wanted ) );
- goto drop;
- }
-
-
- buffer = real_to_user ( pxenv_udp_read->buffer.segment,
- pxenv_udp_read->buffer.offset );
- len = iob_len ( iobuf );
- if ( len > pxenv_udp_read->buffer_size )
- len = pxenv_udp_read->buffer_size;
- copy_to_user ( buffer, 0, iobuf->data, len );
- pxenv_udp_read->buffer_size = len;
-
-
- pxenv_udp_read->src_ip = pshdr->src_ip;
- pxenv_udp_read->s_port = pshdr->s_port;
- pxenv_udp_read->dest_ip = pshdr->dest_ip;
- pxenv_udp_read->d_port = pshdr->d_port;
-
- DBG ( " %04x:%04x+%x %s:", pxenv_udp_read->buffer.segment,
- pxenv_udp_read->buffer.offset, pxenv_udp_read->buffer_size,
- inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->src_ip ) ));
- DBG ( "%d<-%s:%d\n", ntohs ( pxenv_udp_read->s_port ),
- inet_ntoa ( *( ( struct in_addr * ) &pxenv_udp_read->dest_ip ) ),
- ntohs ( pxenv_udp_read->d_port ) );
-
-
- free_iob ( iobuf );
-
- pxenv_udp_read->Status = PXENV_STATUS_SUCCESS;
- return PXENV_EXIT_SUCCESS;
-
- drop:
- free_iob ( iobuf );
- no_packet:
- pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
- return PXENV_EXIT_FAILURE;
- }
-
-
- struct pxe_api_call pxe_udp_api[] __pxe_api_call = {
- PXE_API_CALL ( PXENV_UDP_OPEN, pxenv_udp_open,
- struct s_PXENV_UDP_OPEN ),
- PXE_API_CALL ( PXENV_UDP_CLOSE, pxenv_udp_close,
- struct s_PXENV_UDP_CLOSE ),
- PXE_API_CALL ( PXENV_UDP_WRITE, pxenv_udp_write,
- struct s_PXENV_UDP_WRITE ),
- PXE_API_CALL ( PXENV_UDP_READ, pxenv_udp_read,
- struct s_PXENV_UDP_READ ),
- };
|