// 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 ; }
void telnet_session_destroy(struct telnet_session_s *t) { daemon_assert(invariant(t)); Test_and_Close( & t->in_fd); Test_and_Close( & t->out_fd); }
/* 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 COM_close(struct connection_in *connection) { struct port_in * pin ; if (connection == NO_CONNECTION) { LEVEL_DEBUG("Attempt to close a NULL device"); return ; } pin = connection->pown ; switch ( pin->type ) { case ct_unknown: case ct_none: case ct_usb: LEVEL_DEBUG("ERROR!!! ----------- ERROR!"); return ; case ct_telnet: case ct_tcp: break ; case ct_i2c: case ct_netlink: LEVEL_DEBUG("Unimplemented!!!"); return ; case ct_serial: break ; } switch ( pin->state ) { case cs_virgin: break ; default: case cs_deflowered: Test_and_Close( &( pin->file_descriptor) ) ; break ; } }
/* 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 ; }