static int invariant(const struct telnet_session_s *t) { if (t == NULL) { return 0; } if (FILE_DESCRIPTOR_NOT_VALID(t->in_fd)) { return 0; } if ((t->in_take < 0) || (t->in_take >= BUF_LEN)) { return 0; } if ((t->in_add < 0) || (t->in_add >= BUF_LEN)) { return 0; } if ((t->in_buflen < 0) || (t->in_buflen > BUF_LEN)) { return 0; } switch (t->in_status) { case NORMAL: break; case GOT_IAC: break; case GOT_WILL: break; case GOT_WONT: break; case GOT_DO: break; case GOT_DONT: break; case GOT_CR: break; default: return 0; } if (FILE_DESCRIPTOR_NOT_VALID(t->out_fd)) { return 0; } if ((t->out_take < 0) || (t->out_take >= BUF_LEN)) { return 0; } if ((t->out_add < 0) || (t->out_add >= BUF_LEN)) { return 0; } if ((t->out_buflen < 0) || (t->out_buflen > BUF_LEN)) { return 0; } return 1; }
/* Called on head of multibus group */ SIZE_OR_ERROR COM_read_with_timeout( BYTE * data, size_t length, struct connection_in *connection) { struct port_in * pin ; if ( length == 0 ) { return 0 ; } if ( connection == NO_CONNECTION || data == NULL ) { // bad parameters return -EIO ; } pin = connection->pown ; // unlike write or open, a closed connection isn't automatically opened. // the reason is that reopening won't have the data waiting. We really need // to restart the transaction from the "write" portion if ( FILE_DESCRIPTOR_NOT_VALID( pin->file_descriptor ) ) { return -EBADF ; } else { size_t actual_size ; ZERO_OR_ERROR zoe = tcp_read( pin->file_descriptor, data, length, &(pin->timeout), &actual_size ) ; if ( zoe == -EBADF ) { COM_close(connection) ; return zoe ; } else { return actual_size ; } } }
/* Called on head of multibus group */ void serial_free(struct connection_in *connection) { FILE_DESCRIPTOR_OR_ERROR fd ; struct port_in * pin = connection->pown ; if ( pin->state == cs_virgin ) { return ; } fd = pin->file_descriptor ; if ( FILE_DESCRIPTOR_NOT_VALID( fd ) ) { // reopen to restore attributes fd = open( pin->init_data, O_RDWR | O_NONBLOCK | O_NOCTTY ) ; } // restore tty settings if ( FILE_DESCRIPTOR_VALID( fd ) ) { LEVEL_DEBUG("COM_close: flush"); tcflush( fd, TCIOFLUSH); LEVEL_DEBUG("COM_close: restore"); if ( tcsetattr( fd, TCSANOW, &(pin->dev.serial.oldSerialTio) ) < 0) { ERROR_CONNECT("Cannot restore port attributes: %s", pin->init_data); } } Test_and_Close( &( pin->file_descriptor) ) ; }
void Config_Monitor_Add( const char * filename ) { FILE_DESCRIPTOR_OR_ERROR fd ; struct kevent ke ; if ( config_monitor_num_files == 0 ) { // first one kq = kqueue() ; if ( kq < 0 ) { LEVEL_DEBUG("Could not create a kevent queue (kqueue)" ) ; return ; } } fd = open( filename, O_EVTONLY ) ; if ( FILE_DESCRIPTOR_NOT_VALID( fd ) ) { LEVEL_DEBUG("Can't open %s for monitoring", filename ) ; return ; } EV_SET( &ke, fd, EVFILT_VNODE, EV_ADD, NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_RENAME, 0, NULL ) ; if ( kevent( kq, &ke, 1, NULL, 0, NULL ) != 0 ) { LEVEL_DEBUG("Couldn't add %s to kqueue for monitoring",filename ) ; } else { ++ config_monitor_num_files ; LEVEL_DEBUG("Added %s to kqueue", filename ) ; } }
// Bind the master netlink socket for all communication // responses will have to be routed to appropriate bus master GOOD_OR_BAD w1_bind( struct connection_in * in ) { struct port_in * pin = in->pown ; struct sockaddr_nl l_local ; pin->type = ct_netlink ; Test_and_Close( &(pin->file_descriptor) ) ; // just in case // Example from http://lxr.linux.no/linux+v3.0/Documentation/connector/ucon.c#L114 //pin->file_descriptor = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); // pin->file_descriptor = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC , NETLINK_CONNECTOR); pin->file_descriptor = socket(PF_NETLINK, SOCK_RAW , NETLINK_CONNECTOR); if ( FILE_DESCRIPTOR_NOT_VALID( pin->file_descriptor ) ) { ERROR_CONNECT("Netlink (w1) socket (are you root?)"); return gbBAD; } // fcntl (pin->file_descriptor, F_SETFD, FD_CLOEXEC); // for safe forking l_local.nl_pid = in->master.w1_monitor.pid = getpid() ; l_local.nl_pad = 0; l_local.nl_family = AF_NETLINK; l_local.nl_groups = 23; if ( bind( pin->file_descriptor, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl) ) == -1 ) { ERROR_CONNECT("Netlink (w1) bind (are you root?)"); Test_and_Close( &( pin->file_descriptor) ); return gbBAD ; } pin->state = cs_deflowered ; return gbGOOD ; }
static GOOD_OR_BAD DS2482_channel_select(struct connection_in * in) { struct connection_in *head = in->master.i2c.head; int chan = in->master.i2c.index; FILE_DESCRIPTOR_OR_ERROR file_descriptor = in->pown->file_descriptor; /* Write and verify codes for the CHANNEL_SELECT command (DS2482-800 only). To set the channel, write the value at the index of the channel. Read and compare against the corresponding value to verify the change. */ static const BYTE W_chan[8] = { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 }; static const BYTE R_chan[8] = { 0xB8, 0xB1, 0xAA, 0xA3, 0x9C, 0x95, 0x8E, 0x87 }; if ( FILE_DESCRIPTOR_NOT_VALID(file_descriptor) ) { LEVEL_CONNECT("Calling a closed i2c channel (%d) "I2Cformat" ", chan,I2Cvar(in)); return gbBAD; } /* Already properly selected? */ /* All `100 (1 channel) will be caught here */ if (chan != head->master.i2c.current) { int read_back; /* Select command */ if (i2c_smbus_write_byte_data(file_descriptor, DS2482_CMD_CHANNEL_SELECT, W_chan[chan]) < 0) { LEVEL_DEBUG("Channel select set error"); return gbBAD; } /* Read back and confirm */ read_back = i2c_smbus_read_byte(file_descriptor); if (read_back < 0) { LEVEL_DEBUG("Channel select get error"); return gbBAD; // flag for DS2482-100 vs -800 detection } if (((BYTE) read_back) != R_chan[chan]) { LEVEL_DEBUG("Channel selected doesn't match"); return gbBAD; // flag for DS2482-100 vs -800 detection } /* Set the channel in head */ head->master.i2c.current = in->master.i2c.index; } /* Now check the configuration register */ /* This is since configuration is per chip, not just channel */ if (in->master.i2c.configreg != head->master.i2c.configchip) { return SetConfiguration(in->master.i2c.configreg, in); } return gbGOOD; }
/* Called on head of multibus group */ GOOD_OR_BAD COM_read( BYTE * data, size_t length, struct connection_in *connection) { struct port_in * pin ; if ( length == 0 ) { return gbGOOD ; } if ( connection == NO_CONNECTION || data == NULL ) { // bad parameters return gbBAD ; } pin = connection->pown ; // unlike write or open, a closed connection isn't automatically opened. // the reason is that reopening won't have the data waiting. We really need // to restart the transaction from the "write" portion if ( FILE_DESCRIPTOR_NOT_VALID( pin->file_descriptor ) ) { return gbBAD ; } switch ( pin->type ) { // test the type of connection case ct_unknown: case ct_none: LEVEL_DEBUG("Unknown type"); break ; case ct_telnet: return telnet_read( data, length, connection ) ; case ct_tcp: // network is ok return COM_read_get_size( data, length, connection ) == (ssize_t) length ? gbGOOD : gbBAD ; case ct_i2c: case ct_netlink: case ct_usb: LEVEL_DEBUG("Unimplemented"); break ; case ct_serial: // serial is ok // printf("Serial read fd=%d length=%d\n",pin->file_descriptor, (int) length); { ssize_t actual = COM_read_get_size( data, length, connection ) ; if ( FILE_DESCRIPTOR_VALID( pin->file_descriptor ) ) { // tcdrain only works on serial conections tcdrain( pin->file_descriptor ); return actual == (ssize_t) length ? gbGOOD : gbBAD ; } break ; } } return gbBAD ; }
/* Device-specific functions */ GOOD_OR_BAD W1_monitor_detect(struct port_in *pin) { struct connection_in * in = pin->first ; struct timeval tvslack = { 1, 0 } ; // 1 second pin->file_descriptor = FILE_DESCRIPTOR_BAD; pin->type = ct_none ; in->iroutines.detect = W1_monitor_detect; in->Adapter = adapter_w1_monitor; /* OWFS assigned value */ in->iroutines.reset = NO_RESET_ROUTINE; in->iroutines.next_both = NO_NEXT_BOTH_ROUTINE; in->iroutines.PowerByte = NO_POWERBYTE_ROUTINE; in->iroutines.ProgramPulse = NO_PROGRAMPULSE_ROUTINE; in->iroutines.sendback_data = NO_SENDBACKDATA_ROUTINE; in->iroutines.sendback_bits = NO_SENDBACKBITS_ROUTINE; in->iroutines.select = NO_SELECT_ROUTINE; in->iroutines.select_and_sendback = NO_SELECTANDSENDBACK_ROUTINE; in->iroutines.set_config = NO_SET_CONFIG_ROUTINE; in->iroutines.get_config = NO_GET_CONFIG_ROUTINE; in->iroutines.reconnect = NO_RECONNECT_ROUTINE; in->iroutines.close = W1_monitor_close; in->iroutines.verify = NO_VERIFY_ROUTINE ; in->iroutines.flags = ADAP_FLAG_sham; in->adapter_name = "W1 monitor"; pin->busmode = bus_w1_monitor ; RETURN_BAD_IF_BAD( w1_monitor_in_use(in) ) ; // Initial setup Inbound_Control.w1_monitor = in ; // essentially a global pointer to the w1_monitor entry _MUTEX_INIT(in->master.w1_monitor.seq_mutex); _MUTEX_INIT(in->master.w1_monitor.read_mutex); timernow( &(in->master.w1_monitor.last_read) ); timeradd( &(in->master.w1_monitor.last_read), &tvslack, &(in->master.w1_monitor.last_read) ); in->master.w1_monitor.seq = SEQ_INIT ; in->master.w1_monitor.pid = 0 ; w1_bind(in) ; // sets in->file_descriptor if ( FILE_DESCRIPTOR_NOT_VALID( in->pown->file_descriptor ) ) { ERROR_DEBUG("Netlink problem -- are you root?"); Inbound_Control.w1_monitor = NO_CONNECTION ; return gbBAD ; } return W1_Browse() ; // creates thread that runs forever. }
/* Re-open a DS2482 */ static GOOD_OR_BAD DS2482_redetect(const struct parsedname *pn) { struct connection_in *head = pn->selected_connection->master.i2c.head; int address = head->master.i2c.i2c_address; FILE_DESCRIPTOR_OR_ERROR file_descriptor; struct address_pair ap ; // to get device name from device:address /* open the i2c port */ Parse_Address( DEVICENAME(head), &ap ) ; file_descriptor = open(ap.first.alpha, O_RDWR ); Free_Address( &ap ) ; if ( FILE_DESCRIPTOR_NOT_VALID(file_descriptor) ) { ERROR_CONNECT("Could not open i2c device %s", DEVICENAME(head)); return gbBAD; } /* address is known */ if (ioctl(file_descriptor, I2C_SLAVE, address) < 0) { ERROR_CONNECT("Cound not set i2c address to %.2X", address); } else { BYTE c; /* write the RESET code */ if (i2c_smbus_write_byte(file_descriptor, DS2482_CMD_RESET) // reset || BAD(DS2482_readstatus(&c, file_descriptor, DS2482_Chip_reset_usec)) // pause .5 usec then read status || (c != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) // make sure status is properly set ) { LEVEL_CONNECT("i2c device at %s address %d cannot be reset. Not a DS2482.", DEVICENAME(head), address); } else { struct connection_in * next ; head->master.i2c.current = 0; head->pown->file_descriptor = file_descriptor; head->pown->state = cs_deflowered ; head->pown->type = ct_i2c ; head->master.i2c.configchip = 0x00; // default configuration register after RESET LEVEL_CONNECT("i2c device at %s address %d reset successfully", DEVICENAME(head), address); for ( next = head->pown->first; next; next = next->next ) { /* loop through devices, matching those that have the same "head" */ /* BUSLOCK also locks the sister channels for this */ next->reconnect_state = reconnect_ok; } return gbGOOD; } } /* fellthough, no device found */ close(file_descriptor); return gbBAD; }
static int Get_HA7_response( struct addrinfo *now, char * name ) { struct timeval tv = { 50, 0 }; FILE_DESCRIPTOR_OR_ERROR file_descriptor; struct HA7_response ha7_response ; struct sockaddr_in from ; socklen_t fromlen = sizeof(struct sockaddr_in) ; int on = 1; file_descriptor = socket(now->ai_family, now->ai_socktype, now->ai_protocol) ; if ( FILE_DESCRIPTOR_NOT_VALID(file_descriptor) ) { ERROR_DEBUG("Cannot get socket file descriptor for broadcast."); return 1; } // fcntl (file_descriptor, F_SETFD, FD_CLOEXEC); // for safe forking if (setsockopt(file_descriptor, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) { ERROR_DEBUG("Cannot set socket option for broadcast."); return 1; } if (sendto(file_descriptor, "HA\000\001", 4, 0, now->ai_addr, now->ai_addrlen) != 4) { ERROR_CONNECT("Trouble sending broadcast message"); return 1; } /* now read */ if ( udp_read(file_descriptor, &ha7_response, sizeof(struct HA7_response), &tv, &from, &fromlen) != sizeof(struct HA7_response) ) { LEVEL_CONNECT("HA7 response bad length"); return 1; } if ( Test_HA7_response( &ha7_response ) ) { return 1 ; } UCLIBCLOCK ; snprintf(name,INET_ADDRSTRLEN+20,"%s:%d",inet_ntoa(from.sin_addr),ntohs(ha7_response.port)); UCLIBCUNLOCK ; return 0 ; }
//open serial port ( called on head of connection_in group from com_open ) GOOD_OR_BAD serial_open(struct connection_in *connection) { struct port_in * pin = connection->pown ; FILE_DESCRIPTOR_OR_ERROR fd = open( DEVICENAME(connection), O_RDWR | O_NONBLOCK | O_NOCTTY) ; pin->file_descriptor = fd ; if ( FILE_DESCRIPTOR_NOT_VALID( fd ) ) { // state doesn't change ERROR_DEFAULT("Cannot open port: %s Permissions problem?", SAFESTRING(DEVICENAME(connection))); return gbBAD; } if ( pin->state == cs_virgin ) { // valgrind warns about uninitialized memory in tcsetattr(), so clear all. memset( &(pin->dev.serial.oldSerialTio), 0, sizeof(struct termios)); if ((tcgetattr( fd, &(pin->dev.serial.oldSerialTio) ) < 0)) { ERROR_CONNECT("Cannot get old port attributes: %s", SAFESTRING(DEVICENAME(connection))); // proceed anyway } pin->state = cs_deflowered ; } return serial_change( connection ) ; }
// bus locking at a higher level GOOD_OR_BAD K1WM_detect(struct port_in *pin) { struct connection_in * in = pin->first ; long long int prebase ; unsigned int prechannels_count; void * mm ; FILE_DESCRIPTOR_OR_ERROR mem_fd ; const char * mem_device = "/dev/uio0"; if (pin->init_data == NULL) { LEVEL_DEFAULT("K1WM needs a memory location"); return gbBAD; } in->Adapter = adapter_k1wm ; in->master.ds1wm.longline = 0 ; // longline timing // in->master.ds1wm.frequency = 0 ; // unused in k1wm in->master.ds1wm.presence_mask = 1 ; // pulse presence mask in->master.ds1wm.active_channel = 0; in->master.ds1wm.channels_count = 1; int param_count = sscanf( pin->init_data, "%lli,%u", &prebase, &prechannels_count); if ( param_count < 1 || param_count > 2) { LEVEL_DEFAULT("K1WM: Could not interpret <%s> as a memory address:channel_count pair", pin->init_data ) ; return gbBAD ; } in->master.ds1wm.channels_count = prechannels_count ; in->master.ds1wm.base = prebase ; // convert types long long int -> off_t if ( in->master.ds1wm.base == 0 ) { LEVEL_DEFAULT("K1WM: Illegal address 0x0000 from <%s>", pin->init_data ) ; return gbBAD ; } LEVEL_DEBUG("K1WM at address %p",(void *)in->master.ds1wm.base); LEVEL_DEBUG("K1WM channels: %u",in->master.ds1wm.channels_count); read_device_map_size(mem_device, &(in->master.ds1wm.mm_size)); read_device_map_offset(mem_device, &(in->master.ds1wm.page_start)); // open /dev/uio0 mem_fd = open( mem_device, O_RDWR | O_SYNC ) ; if ( FILE_DESCRIPTOR_NOT_VALID(mem_fd) ) { LEVEL_DEFAULT("K1WM: Cannot open memory directly -- permissions problem?"); return gbBAD ; } mm = mmap( NULL, in->master.ds1wm.mm_size, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, in->master.ds1wm.page_start ); close(mem_fd) ; // no longer needed if ( mm == MAP_FAILED ) { LEVEL_DEFAULT("K1WM: Cannot map memory") ; return gbBAD ; } in->master.ds1wm.mm = mm ; /* Set up low-level routines */ K1WM_setroutines(in); // Add channels K1WM_create_channels(in, in->master.ds1wm.channels_count); return K1WM_setup(in) ; }
/* return < 0 if failure */ ZERO_OR_ERROR tcp_read(FILE_DESCRIPTOR_OR_ERROR file_descriptor, BYTE * buffer, size_t requested_size, const struct timeval * ptv, size_t * chars_in) { size_t to_be_read = requested_size ; if ( FILE_DESCRIPTOR_NOT_VALID( file_descriptor ) ) { return -EBADF ; } LEVEL_DEBUG("attempt %d bytes Time: "TVformat,(int)requested_size, TVvar(ptv) ) ; *chars_in = 0 ; while (to_be_read > 0) { int select_result; fd_set readset; struct timeval tv ; /* Initialize readset */ FD_ZERO(&readset); FD_SET(file_descriptor, &readset); /* Read if it doesn't timeout first */ timercpy( &tv, ptv ) ; select_result = select(file_descriptor + 1, &readset, NULL, NULL, &tv); if (select_result > 0) { ssize_t read_result; /* Is there something to read? */ if (FD_ISSET(file_descriptor, &readset) == 0) { LEVEL_DEBUG("tcp_error -- nothing avialable to read"); return -EBADF ; /* error */ } errno = 0 ; read_result = read(file_descriptor, &buffer[*chars_in], to_be_read) ; if ( read_result < 0 ) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { read_result = 0; /* and call read() again */ } else { LEVEL_DATA("Network data read error errno=%d %s", errno, strerror(errno)); STAT_ADD1(NET_read_errors); return -EBADF ; } } else if (read_result == 0) { break; /* EOF */ } TrafficInFD("NETREAD", &buffer[*chars_in], read_result, file_descriptor ) ; to_be_read -= read_result; *chars_in += read_result ; } else if (select_result < 0) { /* select error */ if (errno == EINTR) { /* select() was interrupted, try again */ continue; } ERROR_DATA("Select error"); return -EBADF; } else { /* timed out */ LEVEL_CONNECT("TIMEOUT after %d bytes", requested_size - to_be_read); return -EAGAIN; } } LEVEL_DEBUG("read: %d - %d = %d",(int)requested_size, (int) to_be_read, (int) (requested_size-to_be_read) ) ; return 0; }
/* Try to see if there is a DS2482 device on the specified i2c bus */ static GOOD_OR_BAD DS2482_detect_single(int lowindex, int highindex, char * i2c_device, struct port_in *pin) { int test_address[8] = { 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, }; // the last 4 are -800 only int i2c_index; FILE_DESCRIPTOR_OR_ERROR file_descriptor; struct connection_in * in = pin->first ; /* Sanity check */ if ( lowindex < 0 ) { LEVEL_DEBUG("Bad lower bound"); return gbBAD ; } if ( highindex >= (int) (sizeof(test_address)/sizeof(int)) ) { LEVEL_DEBUG("Bad upper bound"); return gbBAD ; } /* open the i2c port */ file_descriptor = open(i2c_device, O_RDWR); if ( FILE_DESCRIPTOR_NOT_VALID(file_descriptor) ) { ERROR_CONNECT("Could not open i2c device %s", i2c_device); return gbBAD; } /* Set up low-level routines */ DS2482_setroutines(in); for (i2c_index = lowindex; i2c_index <= highindex; ++i2c_index) { int trial_address = test_address[i2c_index] ; /* set the candidate address */ if (ioctl(file_descriptor, I2C_SLAVE, trial_address) < 0) { ERROR_CONNECT("Cound not set trial i2c address to %.2X", trial_address); } else { BYTE c; LEVEL_CONNECT("Found an i2c device at %s address %.2X", i2c_device, trial_address); /* Provisional setup as a DS2482-100 ( 1 channel ) */ in->pown->file_descriptor = file_descriptor; pin->state = cs_deflowered; pin->type = ct_i2c ; in->master.i2c.i2c_address = trial_address; in->master.i2c.i2c_index = i2c_index; in->master.i2c.index = 0; in->master.i2c.channels = 1; in->master.i2c.current = 0; in->master.i2c.head = in; in->adapter_name = "DS2482-100"; in->master.i2c.configreg = 0x00 ; // default configuration setting desired if ( Globals.i2c_APU ) { in->master.i2c.configreg |= DS2482_REG_CFG_APU ; } if ( Globals.i2c_PPM ) { in->master.i2c.configreg |= DS2482_REG_CFG_PPM ; } in->Adapter = adapter_DS2482_100; /* write the RESET code */ if (i2c_smbus_write_byte(file_descriptor, DS2482_CMD_RESET) // reset || BAD(DS2482_readstatus(&c, file_descriptor, DS2482_Chip_reset_usec)) // pause .5 usec then read status || (c != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) // make sure status is properly set ) { LEVEL_CONNECT("i2c device at %s address %.2X cannot be reset. Not a DS2482.", i2c_device, trial_address); continue; } LEVEL_CONNECT("i2c device at %s address %.2X appears to be DS2482-x00", i2c_device, trial_address); in->master.i2c.configchip = 0x00; // default configuration register after RESET // Note, only the lower nibble of the device config stored // Create name SAFEFREE( DEVICENAME(in) ) ; DEVICENAME(in) = owmalloc( strlen(i2c_device) + 10 ) ; if ( DEVICENAME(in) ) { UCLIBCLOCK; snprintf(DEVICENAME(in), strlen(i2c_device) + 10, "%s:%.2X", i2c_device, trial_address); UCLIBCUNLOCK; } /* Now see if DS2482-100 or DS2482-800 */ return HeadChannel(in); } } /* fell though, no device found */ COM_close( in ) ; return gbBAD; }
// bus locking at a higher level GOOD_OR_BAD DS1WM_detect(struct port_in *pin) { struct connection_in * in = pin->first ; long long int prebase ; off_t base ; void * mm ; FILE_DESCRIPTOR_OR_ERROR mem_fd ; const char * mem_device = "/dev/mem"; in->Adapter = adapter_ds1wm ; in->master.ds1wm.longline = 0 ; // longline timing in->master.ds1wm.frequency = 10000000 ; // 10MHz in->master.ds1wm.presence_mask = 1 ; // pulse presence mask in->master.ds1wm.active_channel = 0; // always for ds1wm in->master.ds1wm.channels_count = 1; // always for ds1wm if (pin->init_data == NULL) { LEVEL_DEFAULT("DS1WM needs a memory location"); return gbBAD; } if ( sscanf( pin->init_data, "%lli", &prebase ) != 1 ) { LEVEL_DEFAULT("DS1WM: Could not interpret <%s> as a memory address", pin->init_data ) ; return gbBAD ; } base = prebase ; // convert types long long int -> off_t if ( base == 0 ) { LEVEL_DEFAULT("DS1WM: Illegal address 0x0000 from <%s>", pin->init_data ) ; return gbBAD ; } LEVEL_DEBUG("DS1WM at address %p",(void *)base); in->master.ds1wm.mm_size = (size_t) getpagesize() ; in->master.ds1wm.base = base ; in->master.ds1wm.page_offset = base % in->master.ds1wm.mm_size ; in->master.ds1wm.page_start = base - in->master.ds1wm.page_offset ; // open /dev/mem mem_fd = open( mem_device, O_RDWR | O_SYNC ) ; if ( FILE_DESCRIPTOR_NOT_VALID(mem_fd) ) { LEVEL_DEFAULT("DS1WM: Cannot open memory directly -- permissions problem?"); return gbBAD ; } mm = mmap( NULL, in->master.ds1wm.mm_size, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, in->master.ds1wm.page_start ); close(mem_fd) ; // no longer needed if ( mm == MAP_FAILED ) { LEVEL_DEFAULT("DS1WM: Cannot map memory") ; return gbBAD ; } in->master.ds1wm.mm = mm ; /* Set up low-level routines */ DS1WM_setroutines(in); in->adapter_name = "DS1WM"; return DS1WM_setup(in) ; }
/* Read from a telnet device */ GOOD_OR_BAD telnet_read(BYTE * buf, const size_t size, struct connection_in *in) { struct port_in * pin ; // temporary buffer (add some extra space) BYTE readin_buf[size+2] ; // state machine for telnet escape chars // handles TELNET protocol, specifically RFC854 // http://www.ietf.org/rfc/rfc854.txt enum { telnet_regular, telnet_iac, telnet_sb, telnet_sb_opt, telnet_sb_val, telnet_sb_iac, telnet_will, telnet_wont, telnet_do, telnet_dont, } telnet_read_state = telnet_regular ; size_t actual_readin = 0 ; size_t current_index = 0 ; size_t still_needed = size ; // test inputs if ( size == 0 ) { return gbGOOD ; } if ( in == NO_CONNECTION ) { return gbBAD ; } pin = in->pown ; if ( FILE_DESCRIPTOR_NOT_VALID(pin->file_descriptor) ) { return gbBAD ; } // loop and look for escape sequances while ( still_needed > 0 ) { // see if the state requires a longer read than currently scheduled size_t minimum_chars = still_needed ; switch( telnet_read_state ) { case telnet_sb: minimum_chars += 4 ; break ; case telnet_sb_opt: minimum_chars += 3 ; break ; case telnet_sb_val: minimum_chars += 2 ; break ; case telnet_iac: case telnet_sb_iac: case telnet_will: case telnet_wont: case telnet_do: case telnet_dont: minimum_chars += 1 ; break ; case telnet_regular: break ; } if ( current_index >= actual_readin ) { // need to read more -- just read what we think we need -- escape chars may require repeat if ( tcp_read( pin->file_descriptor, readin_buf, minimum_chars, &(pin->timeout), &actual_readin) < 0 ) { LEVEL_DEBUG("tcp seems closed") ; Test_and_Close( &(pin->file_descriptor) ) ; return gbBAD ; } if (actual_readin < minimum_chars) { LEVEL_CONNECT("Telnet (ethernet) error"); Test_and_Close( &(pin->file_descriptor) ) ; return gbBAD; } current_index = 0 ; } switch ( telnet_read_state ) { case telnet_regular : if ( readin_buf[current_index] == TELNET_IAC ) { if (Globals.traffic) { LEVEL_DEBUG("TELNET: IAC"); } // starting escape sequence // following bytes will better characterize telnet_read_state = telnet_iac ; } else { // normal processing // move byte to response and decrement needed bytes // stay in current state buf[size - still_needed] = readin_buf[current_index] ; -- still_needed ; } break ; case telnet_iac: //printf("TELNET: IAC %d\n",readin_buf[current_index]); switch ( readin_buf[current_index] ) { case TELNET_EOF: case TELNET_SUSP: case TELNET_ABORT: case TELNET_EOR: case TELNET_SE: case TELNET_NOP: case TELNET_DM: case TELNET_BREAK: case TELNET_IP: case TELNET_AO: case TELNET_AYT: case TELNET_EC: case TELNET_EL: case TELNET_GA: // 2 byte sequence // just read 2nd character if (Globals.traffic) { LEVEL_DEBUG("TELNET: End 2-byte sequence"); } telnet_read_state = telnet_regular ; break ; case TELNET_SB: // multibyte squence // start scanning for 0xF0 telnet_read_state = telnet_sb ; break ; case TELNET_WILL: // 3 byte sequence // just read 2nd char telnet_read_state = telnet_will ; break ; case TELNET_WONT: // 3 byte sequence // just read 2nd char telnet_read_state = telnet_wont ; break ; case TELNET_DO: // 3 byte sequence // just read 2nd char telnet_read_state = telnet_do ; break ; case TELNET_DONT: // 3 byte sequence // just read 2nd char telnet_read_state = telnet_dont ; break ; case TELNET_IAC: // escape the FF character // make this a single regular FF char buf[size - still_needed] = 0xFF ; -- still_needed ; if (Globals.traffic) { LEVEL_DEBUG("TELNET: FF escape sequence"); } telnet_read_state = telnet_regular ; break ; default: LEVEL_DEBUG("Unexpected telnet sequence"); return gbBAD ; } break ; case telnet_sb: switch ( readin_buf[current_index] ) { case TELNET_IAC: LEVEL_DEBUG("Unexpected telnet sequence"); return gbBAD ; default: //printf("TELNET: IAC SB opt=%d\n",readin_buf[current_index]); // stay in this mode telnet_read_state = telnet_sb_opt ; break ; } break ; case telnet_sb_opt: switch ( readin_buf[current_index] ) { case TELNET_IAC: LEVEL_DEBUG("Unexpected telnet sequence"); return gbBAD ; default: //printf("TELNET: IAC SB sub_opt=%d\n",readin_buf[current_index]); // stay in this mode telnet_read_state = telnet_sb_val ; break ; } break ; case telnet_sb_val: switch ( readin_buf[current_index] ) { case TELNET_IAC: // stay in this mode telnet_read_state = telnet_sb_iac ; break ; default: //printf("TELNET: IAC SB val=%d\n",readin_buf[current_index]); // stay in this mode break ; } break ; case telnet_sb_iac: switch ( readin_buf[current_index] ) { case TELNET_SE: //printf("TELNET: IAC SE\n"); if (Globals.traffic) { LEVEL_DEBUG("TELNET: End multi-byte sequence"); } telnet_read_state = telnet_regular ; break ; default: LEVEL_DEBUG("Unexpected telnet sequence"); return gbBAD ; } break ; case telnet_will: //printf("TELNET: IAC WILL %d\n",readin_buf[current_index]); // 3 byte sequence // now reading 3rd char if (Globals.traffic) { LEVEL_DEBUG("TELNET: End 3-byte sequence"); } telnet_read_state = telnet_regular ; break ; case telnet_wont: //printf("TELNET: IAC WONT %d\n",readin_buf[current_index]); // 3 byte sequence // now reading 3rd char if (Globals.traffic) { LEVEL_DEBUG("TELNET: End 3-byte sequence"); } telnet_read_state = telnet_regular ; break ; case telnet_do: //printf("TELNET: IAC DO %d\n",readin_buf[current_index]); // 3 byte sequence // now reading 3rd char if (Globals.traffic) { LEVEL_DEBUG("TELNET: End 3-byte sequence"); } telnet_read_state = telnet_regular ; break ; case telnet_dont: // 3 byte sequence // now reading 3rd char if (Globals.traffic) { LEVEL_DEBUG("TELNET: End 3-byte sequence"); } telnet_read_state = telnet_regular ; break ; } ++ current_index ; } return gbGOOD ; }