/* * Handle initial connection protocol. */ static int tftp(struct testcase *test, struct tftphdr *tp, int size) { char *cp; int first = 1, ecode; struct formats *pf; char *filename, *mode = NULL; /* store input protocol */ fprintf(test->server, "opcode: %x\n", tp->th_opcode); cp = (char *)&tp->th_stuff; filename = cp; again: while (cp < buf + size) { if (*cp == '\0') break; cp++; } if (*cp) { nak(EBADOP); return 3; } if (first) { mode = ++cp; first = 0; goto again; } /* store input protocol */ fprintf(test->server, "filename: %s\n", filename); for (cp = mode; *cp; cp++) if (isupper((int)*cp)) *cp = tolower((int)*cp); /* store input protocol */ fprintf(test->server, "mode: %s\n", mode); for (pf = formats; pf->f_mode; pf++) if (strcmp(pf->f_mode, mode) == 0) break; if (!pf->f_mode) { nak(EBADOP); return 2; } ecode = validate_access(test, filename, tp->th_opcode); if (ecode) { nak(ecode); return 1; } if (tp->th_opcode == WRQ) recvtftp(test, pf); else sendtftp(test, pf); return 0; }
void FstopComms::respondWrite() { if(!checkcheck()) return; unsigned int addr=getAddr(); char len=cmd[PKT_LEN]; if(len < 1 || len > PKT_MAXREQ || addr < EEPROM_MIN_WRITE || addr+len > EEPROM_MAX_WRITE){ nak(BAD_WRITE); return; } // copy from buffer to EEPROM char bp=PKT_SHORTHDR; for(char i=0;i<len;++i){ EEPROM.write(addr++, cmd[bp++]); } cmd[PKT_CMD]=COM_WRITEACK; buflen=PKT_SHORTHDR; // recompute checksum, send without data txCmd(); }
void tftpd_general(void *p_info, int socket_ID) { connect_info_S *p_con_info=(connect_info_S *)p_info; FILE *f; int result=255; if (p_con_info->job==RRQ) { f=fopen(p_con_info->p_name,"rb"); if(f == NULL) { nak(socket_ID, &p_con_info->adresse, errno,strerror(errno)); tftp_free(p_con_info->p_name); tftp_free(p_con_info); close(socket_ID); return ; } result=tftp_send(&p_con_info->adresse,p_con_info->p_name,"octet",0,TFTPsread,f); fclose(f); } else if (p_con_info->job==WRQ) { result=tftp_receive(&p_con_info->adresse,p_con_info->p_name,"octet",0,TFTPswrite,f); } else { DEBUG_MSG("TFTP op code is not correct \n"); } if (result!=0) DEBUG_MSG("TFTP error\n"); tftp_free(p_con_info->p_name); tftp_free(p_con_info); return ; }
/** * The client is requesting an offer. * * @returns true. * * @param pDhcpMsg The message. * @param cb The message size. */ bool NetworkManager::handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb) { ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager(); /* 1. find client */ Client client = confManager->getClientByDhcpPacket(pDhcpMsg, cb); /* 2. find bound lease */ Lease l = client.lease(); if (l != Lease::NullLease) { if (l.isExpired()) { /* send client to INIT state */ Client c(client); nak(client, pDhcpMsg->bp_xid); confManager->expireLease4Client(c); return true; } else { /* XXX: Validate request */ RawOption opt; RT_ZERO(opt); Client c(client); int rc = confManager->commitLease4Client(c); AssertRCReturn(rc, false); rc = ConfigurationManager::extractRequestList(pDhcpMsg, cb, opt); AssertRCReturn(rc, false); ack(client, pDhcpMsg->bp_xid, opt.au8RawOpt, opt.cbRawOpt); } } else { nak(client, pDhcpMsg->bp_xid); } return true; }
DhcpServerMessage *DHCPD::doRequest(DhcpClientMessage &req) { OptRequestedAddress reqAddr(req); if (req.ciaddr().u != 0 && reqAddr.present() && reqAddr.value().u != req.ciaddr().u) { std::unique_ptr<DhcpServerMessage> nak ( createMessage(RTNET_DHCP_MT_NAC, req) ); nak->addOption(OptMessage("Requested address does not match ciaddr")); return nak.release(); } Binding *b = m_db.allocateBinding(req); if (b == NULL) { return createMessage(RTNET_DHCP_MT_NAC, req); } std::unique_ptr<DhcpServerMessage> ack ( createMessage(RTNET_DHCP_MT_ACK, req) ); b->setState(Binding::ACKED); saveLeases(); ack->setYiaddr(b->addr()); ack->addOption(OptLeaseTime(b->leaseTime())); OptParameterRequest optlist(req); ack->addOptions(m_pConfig->getOptions(optlist, req.clientId())); ack->addOption(OptMessage("Ok, ok, here it is")); ack->maybeUnicast(req); return ack.release(); }
int tftp_connection(struct sockaddr_in _adresse, short _job, char *_name, int socket_ID) { char *p_copy_buf=_name; connect_info_S *p_con_info; int pid; printf("tftp_connection\n"); while ((p_copy_buf<_name+SEGSIZE-5)&&(*p_copy_buf!=' ')&&(*p_copy_buf!='\0')) p_copy_buf++; /* Corrupt packet - no final NULL */ if ((*p_copy_buf!= ' ')&&(*p_copy_buf!='\0')) { DEBUG_MSG("file name is corrupted. \n"); nak(socket_ID, &_adresse, (int)EBADOP,strerror(EBADOP)); close(socket_ID); return 255; }; *p_copy_buf='\0'; p_con_info=(connect_info_S*)malloc(sizeof(connect_info_S)); p_con_info->p_name=(char*)malloc(p_copy_buf-_name+1); strcpy(p_con_info->p_name,_name); p_con_info->adresse=_adresse; p_con_info->job=_job; pid = fork(); if(pid < 0) printf("TFTP fork error"); else if(pid == 0) //child process { tftpd_general(p_con_info, socket_ID); exit(0); } else //parent process ; return 0; }
void FstopComms::respondRead() { if(!checkcheck()) return; unsigned int addr=getAddr(); char len=cmd[PKT_LEN]; if(len < 1 || len > PKT_MAXREQ || addr < EEPROM_MIN_READ || addr+len > EEPROM_MAX_READ){ nak(BAD_READ); return; } // read from EEPROM into buffer cmd[PKT_CMD]=COM_READACK; for(char i=0;i<len;++i){ cmd[i+PKT_SHORTHDR]=EEPROM.read(addr++); } buflen=len+PKT_SHORTHDR; // append checksum and send. txCmd(); }
void Acknowledge:: track_queue (Address const& addr, Queue& q, Messages& msgs) { unsigned short max_payload_size ( params_.max_packet_size () - max_service_size); u32 max_elem (NAK::max_count (max_payload_size)); u32 count (0); Queue::iterator i (q.begin ()), e (q.end ()); // Track existing losses. // while (i != e) { auto_ptr<NAK> nak (new NAK (addr)); // Inner loop that fills NAK profile with up to max_elem elements. // for (; i != e && nak->count () < max_elem; ++i) { u64 sn ((*i).ext_id_); Descr& d = (*i).int_id_; if (d.lost ()) { d.timer (d.timer () - 1); if (d.timer () == 0) { //@@ Need exp fallback. // d.nak_count (d.nak_count () + 1); d.timer ((d.nak_count () + 1) * params_.nak_timeout ()); nak->add (sn); ++count; // cerr << 6 << "NAK # " << d.nak_count () << ": " // << addr << " " << sn << endl; } } } // Send this NAK. // if (nak->count ()) { // cerr << 5 << "NAK: " << addr << " " << nak->count () << " sns" // << endl; Message_ptr m (new Message); m->add (Profile_ptr (nak.release ())); msgs.push_back (m); } } // Detect and record new losses. // for (u64 sn (q.sn () + 1), end (q.max_sn ()); sn < end; ++sn) { if (q.find (sn) == -1) { q.bind (sn, Descr (1)); } } }
/* * Handle initial connection protocol. */ void tftp(struct tftphdr *tp, int size) { char *cp; size_t i; int first = 1, has_options = 0, ecode; struct formats *pf; char *filename, *mode = NULL, *option, *ccp; char fnbuf[MAXPATHLEN]; cp = tp->th_stuff; again: while (cp < buf + size) { if (*cp == '\0') break; cp++; } if (*cp != '\0') { nak(EBADOP); exit(1); } i = cp - tp->th_stuff; if (i >= sizeof(fnbuf)) { nak(EBADOP); exit(1); } memcpy(fnbuf, tp->th_stuff, i); fnbuf[i] = '\0'; filename = fnbuf; if (first) { mode = ++cp; first = 0; goto again; } for (cp = mode; *cp; cp++) if (isupper(*cp)) *cp = tolower(*cp); for (pf = formats; pf->f_mode; pf++) if (strcmp(pf->f_mode, mode) == 0) break; if (pf->f_mode == NULL) { nak(EBADOP); exit(1); } while (++cp < buf + size) { for (i = 2, ccp = cp; i > 0; ccp++) { if (ccp >= buf + size) { /* * Don't reject the request, just stop trying * to parse the option and get on with it. * Some Apple OpenFirmware versions have * trailing garbage on the end of otherwise * valid requests. */ goto option_fail; } else if (*ccp == '\0') i--; } for (option = cp; *cp; cp++) if (isupper(*cp)) *cp = tolower(*cp); for (i = 0; options[i].o_type != NULL; i++) if (strcmp(option, options[i].o_type) == 0) { options[i].o_request = ++cp; has_options = 1; } cp = ccp-1; } option_fail: if (options[OPT_TIMEOUT].o_request) { int to = atoi(options[OPT_TIMEOUT].o_request); if (to < 1 || to > 255) { nak(EBADOP); exit(1); } else if (to <= max_rexmtval) options[OPT_TIMEOUT].o_reply = rexmtval = to; else options[OPT_TIMEOUT].o_request = NULL; } ecode = (*pf->f_validate)(&filename, tp->th_opcode); if (has_options) oack(); if (logging) { char hbuf[NI_MAXHOST]; getnameinfo((struct sockaddr *)&from, from.ss_len, hbuf, sizeof(hbuf), NULL, 0, NI_WITHSCOPEID); syslog(LOG_INFO, "%s: %s request for %s: %s", hbuf, tp->th_opcode == WRQ ? "write" : "read", filename, errtomsg(ecode)); } if (ecode) { /* * Avoid storms of naks to a RRQ broadcast for a relative * bootfile pathname from a diskless Sun. */ if (suppress_naks && *filename != '/' && ecode == ENOTFOUND) exit(0); nak(ecode); exit(1); } if (tp->th_opcode == WRQ) (*pf->f_recv)(pf); else (*pf->f_send)(pf); exit(0); }
/* Send the requested file */ void my_sendfile( Client *cl ) { int oerrno; struct tftphdr *tp = cl->tp; int opcode, block, readblock; readblock = 0; if (tp != NULL) { /* Process an input packet */ opcode = ntohs((u_short)tp->th_opcode); /* Give up if the other side wants to */ if (opcode == ERROR) { stats.errorop++; my_syslog( MLOG_TFTP, "%s.%d ERROR", inet_ntoa(cl->sin.sin_addr), cl->sin.sin_port); cl->proc = CP_DONE; return; } /* If we didn't get an ACK, blow him away */ //if (opcode != ACK) { // /* XXX this probably can't happen */ // my_syslog( MLOG_TFTP, "%s.%d expected ACK", // inet_ntoa(cl->sin.sin_addr), cl->sin.sin_port); // nak( cl, ERROR ); // return; //} if (opcode == RRQ) { cl->state = ST_INIT; } if (cl->state == ST_WAITACK || cl->state == ST_LASTACK) { /* If he didn't ack the right block, ignore packet */ block = ntohs((u_short)tp->th_block); if (block > cl->maxb) { nak( cl, ERROR ); return; } /* Check if we're done */ if (cl->state == ST_LASTACK && block == cl->maxb) { cl->proc = CP_DONE; return; } if (block != cl->block) cl->block = block; /* Setup to send the next block */ cl->block++; readblock++; cl->state = ST_SEND; cl->wakeup = 0; cl->retries = WAIT_RETRIES; } } /* See if it's time to resend */ if (cl->wakeup != 0 && cl->wakeup <= now && (cl->state == ST_WAITACK || cl->state == ST_LASTACK)) { stats.retrans++; my_syslog( MLOG_TFTP, "%s retrans blk %d", inet_ntoa(cl->sin.sin_addr), cl->block ); cl->state = ST_SEND; } /* Initialize some stuff the first time through */ if (cl->state == ST_INIT) { cl->block = 1; readblock++; cl->state = ST_SEND; cl->wakeup = 0; cl->retries = WAIT_RETRIES; cl->dp = NULL; } /* If our first time through or the last block was ack'ed, read */ if (readblock) { errno = 0; if (read_block( cl->fnum, cl->block, &(cl->dp), (u_int32_t *) &(cl->dpcc) ) != 0) { stats.fileioerror++; nak( cl, errno + 100 ); return; } /* Bail if we run into trouble */ if (cl->dpcc < 0) { stats.fileioerror++; nak( cl, errno + 100 ); return; } } if (cl->state == ST_SEND) { /* See if it's time to give up on this turkey */ cl->retries--; if (cl->retries < 0) { stats.timeout++; my_syslog( MLOG_TFTP, "%s timeout blk %d", inet_ntoa(cl->sin.sin_addr), cl->block ); cl->proc = CP_DONE; return; } /* Send the block */ if (sendto(tftp_socket, (char *)cl->dp, cl->dpcc, 0, (struct sockaddr *)&cl->sin, sizeof(cl->sin)) != cl->dpcc) { oerrno = errno; my_syslog( MLOG_TFTP, "sendfile: write: %m"); nak( cl, oerrno + 100 ); return; } stats.sent++; /* log(LOG_DEBUG, "%s.%d > %d", inet_ntoa(cl->sin.sin_addr), cl->sin.sin_port, cl->block); */ if (cl->dpcc == (SEGSIZE + 4)) cl->state = ST_WAITACK; else cl->state = ST_LASTACK; cl->wakeup = now + WAIT_TIMEOUT; } }
/* Handle initial connection protocol */ void tftp( Client *cl ) { struct tftphdr *tp; char *cp, *cp2, *ep; int ecode; char *mode; char file[MAXPATHLEN]; tp = cl->tp; tp->th_opcode = ntohs((u_short)tp->th_opcode); if (tp->th_opcode != RRQ) { // nak( cl, EBADOP ); return; } errstr = NULL; cp = (char *)&tp->th_block; ep = (char *)cl->tp + cl->tpcc; if ( (ep - cp) > MAXPATHLEN ) { stats.badfilename++; nak( cl, EBADOP ); return; } if ( *cp == '/' ) { cp++; } /* Extract filename */ cp2 = file; while (cp < ep && *cp != '\0') *cp2++ = *cp++; if (cp >= ep) { ++stats.badfilename; nak(cl, EBADOP); return; } *cp2 = '\0'; ++cp; /* Make sure mode is in packet */ mode = cp; while (cp < ep && *cp != '\0') cp++; if (cp >= ep) { stats.badfilemode++; nak( cl, EBADOP ); return; } if (strcasecmp(mode, "octet") != 0) { stats.badfilemode++; nak( cl, EBADOP ); return; } ecode = validate_access( cl, file ); if (ecode) { my_syslog( MLOG_TFTP, "%s %s \"%s\" DENIED (%s)", inet_ntoa(cl->sin.sin_addr), tp->th_opcode == WRQ ? "write" : "read", file, errstr != NULL ? errstr : errtomsg(ecode)); cl->proc = CP_DONE; return; } if (cl->dynam == 0) my_TFTPlog( file, cl->sin.sin_addr.s_addr ); /* my_syslog( MLOG_TFTP, "%s-%s req for \"%s\" from %s", tp->th_opcode == WRQ ? "write" : "read", mode, file, inet_ntoa(cl->sin.sin_addr)); */ cl->state = ST_INIT; cl->tp = NULL; cl->tpcc = 0; cl->proc = CP_SENDFILE; // sendfile( cl ); }
/* * Receive a file. */ void recvfile(struct formats *pf) { struct tftphdr *dp; struct tftphdr *ap; /* ack buffer */ int n, size; volatile unsigned short block; signal(SIGALRM, timer); dp = w_init(); ap = (struct tftphdr *)ackbuf; block = 0; do { timeouts = 0; ap->th_opcode = htons((u_short)ACK); ap->th_block = htons((u_short)block); block++; (void) setjmp(timeoutbuf); send_ack: if (send(peer, ackbuf, 4, 0) != 4) { syslog(LOG_ERR, "write: %m"); goto abort; } write_behind(file, pf->f_convert); for ( ; ; ) { alarm(rexmtval); n = recv(peer, dp, PKTSIZE, 0); alarm(0); if (n < 0) { /* really? */ syslog(LOG_ERR, "read: %m"); goto abort; } dp->th_opcode = ntohs((u_short)dp->th_opcode); dp->th_block = ntohs((u_short)dp->th_block); if (dp->th_opcode == ERROR) goto abort; if (dp->th_opcode == DATA) { if (dp->th_block == block) { break; /* normal */ } /* Re-synchronize with the other side */ (void) synchnet(peer); if (dp->th_block == (block-1)) goto send_ack; /* rexmit */ } } /* size = write(file, dp->th_data, n - 4); */ size = writeit(file, &dp, n - 4, pf->f_convert); if (size != (n-4)) { /* ahem */ if (size < 0) nak(errno + 100); else nak(ENOSPACE); goto abort; } } while (size == SEGSIZE); write_behind(file, pf->f_convert); (void) fclose(file); /* close data file */ ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ ap->th_block = htons((u_short)(block)); (void) send(peer, ackbuf, 4, 0); signal(SIGALRM, justquit); /* just quit on timeout */ alarm(rexmtval); n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */ alarm(0); if (n >= 4 && /* if read some data */ dp->th_opcode == DATA && /* and got a data block */ block == dp->th_block) { /* then my last ack was lost */ (void) send(peer, ackbuf, 4, 0); /* resend final ack */ } abort: return; }
static int ProcessMsg (SOCKET s, const struct S_ConsoleMsg *pmsg) { struct LL_TftpInfo *pTftp; int uServices; LogToMonitor ("TFTPd console receive msg %d\n", pmsg->type); switch (pmsg->type) { case C_CONS_KILL_TRF : LOG (1, "transfer %d must be killed", pmsg->u.kill.dwTransferId); for ( pTftp=pTftpFirst ; pTftp!=NULL && pTftp->tm.dwTransferId != pmsg->u.kill.dwTransferId ; pTftp = pTftp->next ); if (pTftp != NULL) { nak (pTftp, ECANCELLED); pTftp->st.ret_code=TFTP_TRF_STOPPED; } break; case C_TFTP_TERMINATE : LogToMonitor ("terminating TFTP service\n"); tThreads[TH_TFTP].gRunning = FALSE; WakeUpThread (TH_TFTP); break; case C_DHCP_TERMINATE : LogToMonitor ("terminating DHCP service\n"); tThreads[TH_DHCP].gRunning = FALSE; // wake up DHCP thread WakeUpThread (TH_DHCP); break; case C_TERMINATE : LogToMonitor ("stopping services\n"); TerminateWorkerThreads (FALSE); // keep management threads break; case C_SUSPEND : LogToMonitor ("suspending services\n"); TerminateWorkerThreads (TRUE); // keep management threads break; case C_START : LogToMonitor ("starting services\n"); StartMultiWorkerThreads (TRUE); break; case C_DHCP_RRQ_SETTINGS : LogToMonitor ("sending DHCP settings\n"); SendMsg (s, C_DHCP_RPLY_SETTINGS, & sParamDHCP, sizeof sParamDHCP); break; case C_TFTP_RRQ_SETTINGS : LogToMonitor ("sending TFTP settings\n"); SendMsg (s, C_TFTP_RPLY_SETTINGS, & sSettings, sizeof sSettings); break; case C_DHCP_WRQ_SETTINGS : LogToMonitor ("storing new DHCP settings\n"); DHCPSaveConfig ( & pmsg->u.dhcp_settings ); break; case C_TFTP_WRQ_SETTINGS : LogToMonitor ("storing new TFTP settings\n"); {static struct S_RestartTable sRestart; sRestart.newservices = pmsg->u.tftp_settings.uServices; sRestart.oldservices = sSettings.uServices; sRestart.flapservices = 0; if ( sSettings.Port != pmsg->u.tftp_settings.Port || lstrcmp (sSettings.szTftpLocalIP, pmsg->u.tftp_settings.szTftpLocalIP )!=0 ) sRestart.flapservices |= TFTPD32_TFTP_SERVER; // restart syslog if its settings log has changed if ( sSettings.uServices & TFTPD32_SYSLOG_SERVER && ( sSettings.bSyslogPipe != pmsg->u.tftp_settings.bSyslogPipe || strcmp(sSettings.szSyslogFile,pmsg->u.tftp_settings.szSyslogFile)!= 0 ) ) sRestart.flapservices |= TFTPD32_SYSLOG_SERVER; sSettings = pmsg->u.tftp_settings; if ( IsValidDirectory ( pmsg->u.tftp_settings.szBaseDirectory ) ) lstrcpyn ( sSettings.szWorkingDirectory, pmsg->u.tftp_settings.szBaseDirectory, sizeof sSettings.szWorkingDirectory ); _beginthread ( Tftpd32UpdateServices, 0, (void *) & sRestart ); Tftpd32SaveSettings (); } break; case C_TFTP_RESTORE_DEFAULT_SETTINGS : LogToMonitor ("restore default settings\n"); Tftpd32DestroySettings (); break; case C_TFTP_CHG_WORKING_DIR : LogToMonitor ("changing working directory to <%s>\n", pmsg->u.working_dir); if ( IsValidDirectory ( pmsg->u.working_dir ) ) lstrcpyn ( sSettings.szWorkingDirectory, pmsg->u.working_dir, sizeof sSettings.szWorkingDirectory ); break; case C_RRQ_WORKING_DIR : LogToMonitor ("sending working directory <%s>\n", sSettings.szWorkingDirectory); SendMsg (s, C_REPLY_WORKING_DIR, sSettings.szWorkingDirectory, 1 + lstrlen (sSettings.szWorkingDirectory) ); break; case C_DELETE_ASSIGNATION : LogToMonitor ("deleting DHCP entry %X\n", pmsg->u.del_lease.ip); { struct in_addr addr; BOOL dummy; addr.s_addr = pmsg->u.del_lease.ip; DHCPDestroyItem ( DHCPSearchByIP ( & addr, &dummy ) ); } break; case C_RRQ_GET_SERVICES : LogToMonitor ("sending running services\n"); uServices = GetRunningThreads (); SendMsg (s, C_REPLY_GET_SERVICES, & uServices, sizeof uServices ); break; case C_RRQ_GET_INTERFACES : LogToMonitor ("sending IP interfaces"); AnswerIPList (); break; case C_RRQ_DIRECTORY_CONTENT : LogToMonitor ("sending Directory content"); SendDirectoryContent (); break; case C_TFTP_GET_FULL_STAT : LogToMonitor ("sending Directory content"); ConsoleTftpGetStatistics (); break; default : LogToMonitor ("Service received unknown message %d\n", pmsg->type); break; } return 1; } // ReadMsg
/* * Send the requested file. */ static void sendtftp(struct testcase *test, struct formats *pf) { struct tftphdr *dp; struct tftphdr *ap; /* ack packet */ unsigned short block = 1; int size, n; #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer); #endif dp = r_init(); ap = (struct tftphdr *)ackbuf; do { size = readit(test, &dp, pf->f_convert); if (size < 0) { nak(errno + 100); return; } dp->th_opcode = htons((u_short)DATA); dp->th_block = htons((u_short)block); timeout = 0; #ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1); #endif send_data: if (send(peer, dp, size + 4, 0) != size + 4) { logmsg("write\n"); return; } read_ahead(test, pf->f_convert); for ( ; ; ) { #ifdef HAVE_ALARM alarm(rexmtval); /* read the ack */ #endif n = recv(peer, ackbuf, sizeof (ackbuf), 0); #ifdef HAVE_ALARM alarm(0); #endif if (n < 0) { logmsg("read: fail\n"); return; } ap->th_opcode = ntohs((u_short)ap->th_opcode); ap->th_block = ntohs((u_short)ap->th_block); if (ap->th_opcode == ERROR) { logmsg("got ERROR"); return; } if (ap->th_opcode == ACK) { if (ap->th_block == block) { break; } /* Re-synchronize with the other side */ (void) synchnet(peer); if (ap->th_block == (block -1)) { goto send_data; } } } block++; } while (size == SEGSIZE); }
/* * Send the requested file. */ static void sendtftp(struct testcase *test, struct formats *pf) { int size; ssize_t n; sendblock = 1; #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer); #endif sdp = r_init(); sap = (struct tftphdr *)ackbuf; do { size = readit(test, &sdp, pf->f_convert); if (size < 0) { nak(ERRNO + 100); return; } sdp->th_opcode = htons((u_short)opcode_DATA); sdp->th_block = htons((u_short)sendblock); timeout = 0; #ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1); #endif send_data: if (swrite(peer, sdp, size + 4) != size + 4) { logmsg("write"); return; } read_ahead(test, pf->f_convert); for ( ; ; ) { #ifdef HAVE_ALARM alarm(rexmtval); /* read the ack */ #endif n = sread(peer, ackbuf, sizeof (ackbuf)); #ifdef HAVE_ALARM alarm(0); #endif if (n < 0) { logmsg("read: fail"); return; } sap->th_opcode = ntohs((u_short)sap->th_opcode); sap->th_block = ntohs((u_short)sap->th_block); if (sap->th_opcode == opcode_ERROR) { logmsg("got ERROR"); return; } if (sap->th_opcode == opcode_ACK) { if (sap->th_block == sendblock) { break; } /* Re-synchronize with the other side */ (void) synchnet(peer); if (sap->th_block == (sendblock-1)) { goto send_data; } } } sendblock++; } while (size == SEGSIZE); }
void IPCP::RCREvent(struct mbuf *packet) { TRACE("IPCP: RCREvent() state=%d\n", State()); KPPPConfigurePacket request(packet); KPPPConfigurePacket nak(PPP_CONFIGURE_NAK); KPPPConfigurePacket reject(PPP_CONFIGURE_REJECT); // we should not use the same id as the peer if(fID == mtod(packet, ppp_lcp_packet*)->id) fID -= 128; nak.SetID(request.ID()); reject.SetID(request.ID()); // parse each item ppp_configure_item *item; in_addr_t *requestedAddress, *wishedAddress = NULL; for(int32 index = 0; index < request.CountItems(); index++) { item = request.ItemAt(index); if(!item) continue; // addresses have special handling to reduce code size switch(item->type) { case IPCP_ADDRESSES: // abandoned by the standard case IPCP_ADDRESS: wishedAddress = &fPeerRequests.address; break; case IPCP_PRIMARY_DNS: wishedAddress = &fPeerRequests.primaryDNS; break; case IPCP_SECONDARY_DNS: wishedAddress = &fPeerRequests.secondaryDNS; break; } // now parse item switch(item->type) { case IPCP_ADDRESSES: // abandoned by the standard case IPCP_ADDRESS: case IPCP_PRIMARY_DNS: case IPCP_SECONDARY_DNS: if(item->length != 6) { // the packet is invalid m_freem(packet); NewState(PPP_INITIAL_STATE); ReportUpFailedEvent(); return; } requestedAddress = (in_addr_t*) item->data; if(*wishedAddress == INADDR_ANY) { if(*requestedAddress == INADDR_ANY) { // we do not have an address for you m_freem(packet); NewState(PPP_INITIAL_STATE); ReportUpFailedEvent(); return; } } else if(*requestedAddress != *wishedAddress) { // we do not want this address ip_item ipItem; ipItem.type = item->type; ipItem.length = 6; ipItem.address = *wishedAddress; nak.AddItem((ppp_configure_item*) &ipItem); } break; // case IPCP_COMPRESSION_PROTOCOL: // TODO: implement me! // break; default: reject.AddItem(item); } } // append additional values to the nak if(!request.ItemWithType(IPCP_ADDRESS) && fPeerRequests.address == INADDR_ANY) { // The peer did not provide us his address. Tell him to do so. ip_item ipItem; ipItem.type = IPCP_ADDRESS; ipItem.length = 6; ipItem.address = INADDR_ANY; nak.AddItem((ppp_configure_item*) &ipItem); } if(nak.CountItems() > 0) { RCRBadEvent(nak.ToMbuf(Interface().MRU(), Interface().PacketOverhead()), NULL); m_freem(packet); } else if(reject.CountItems() > 0) { RCRBadEvent(NULL, reject.ToMbuf(Interface().MRU(), Interface().PacketOverhead())); m_freem(packet); } else RCRGoodEvent(packet); }
/* * Handle initial connection protocol. */ int tftp(struct tftphdr *tp, int size) { char *cp; int argn, ecode; struct formats *pf = NULL; char *filename, *mode = NULL; char *val = NULL, *opt = NULL; char *ap = ackbuf + 2; ((struct tftphdr *)ackbuf)->th_opcode = ntohs(OACK); filename = cp = tp->th_stuff; // --> 2005/09/26 Ryan : using tmpfs for firmware upgrade to save run time memory printf("filename[%s]\n",filename); if (!strncmp(filename+5,"tmpfs",5)) { mkdir("/tmp/tmpfs", 0777); //TT mount("tmpfs", "/tmp/tmpfs", "tmpfs", MS_MGC_VAL, NULL); } // <-- argn = 0; while ( cp < buf + size && *cp ) { do { cp++; } while (cp < buf + size && *cp); if ( *cp ) { nak(EBADOP); /* Corrupt packet - no final NULL */ exit(0); } argn++; if (argn == 1) { mode = ++cp; } else if (argn == 2) { for (cp = mode; *cp; cp++) *cp = tolower(*cp); for (pf = formats; pf->f_mode; pf++) { if (!strcmp(pf->f_mode, mode)) break; } if (!pf->f_mode) { nak(EBADOP); exit(0); } ecode = (*pf->f_validate)(filename, tp->th_opcode, pf); if (ecode) { nak(ecode); exit(0); } opt = ++cp; } else if ( argn & 1 ) { val = ++cp; } else { do_opt(opt, val, &ap); opt = ++cp; } } if (!pf) { nak(EBADOP); exit(0); } if (strlen(filename) >= 128) { nak(EBADOP); exit(0); } strcpy(pf->filename, filename); //printf("tftp filename=%s\n",filename); if ( ap != (ackbuf+2) ) { // doesn't come here if ( tp->th_opcode == WRQ ) (*pf->f_recv)(pf, (struct tftphdr *)ackbuf, ap-ackbuf); else (*pf->f_send)(pf, (struct tftphdr *)ackbuf, ap-ackbuf); } else { if (tp->th_opcode == WRQ) (*pf->f_recv)(pf, NULL, 0); else (*pf->f_send)(pf, NULL, 0); } exit(1); }
/* * Send the requested file. */ int tftp_sendfile(int f, union sock_addr *peeraddr, int fd, const char *name, const char *mode) { struct tftphdr *ap; /* data and ack packets */ struct tftphdr *dp; int n; volatile int is_request; volatile u_short block; volatile int size, convert; volatile off_t amount; union sock_addr from; socklen_t fromlen; FILE *file; u_short ap_opcode, ap_block; startclock(); /* start stat's clock */ dp = r_init(); /* reset fillbuf/read-ahead code */ ap = (struct tftphdr *)ackbuf; convert = !strcmp(mode, "netascii"); file = fdopen(fd, convert ? "rt" : "rb"); block = 0; is_request = 1; /* First packet is the actual WRQ */ amount = 0; bsd_signal(SIGALRM, timer); do { if (is_request) { size = makerequest(WRQ, name, dp, mode) - 4; } else { /* size = read(fd, dp->th_data, SEGSIZE); */ size = readit(file, &dp, convert); if (size < 0) { nak(f, peeraddr, errno + 100, NULL); break; } dp->th_opcode = htons((u_short) DATA); dp->th_block = htons((u_short) block); } timeout = 0; (void)sigsetjmp(timeoutbuf, 1); if (trace) tpacket("sent", dp, size + 4); n = sendto(f, dp, size + 4, 0, &(peeraddr->sa), SOCKLEN(peeraddr)); if (n != size + 4) { perror("tftp: sendto"); goto abort; } read_ahead(file, convert); for (;;) { alarm(rexmtval); do { fromlen = sizeof(from); n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, &from.sa, &fromlen); } while (n <= 0); alarm(0); if (n < 0) { perror("tftp: recvfrom"); goto abort; } sa_set_port(peeraddr, SOCKPORT(&from)); /* added */ if (trace) tpacket("received", ap, n); /* should verify packet came from server */ ap_opcode = ntohs((u_short) ap->th_opcode); ap_block = ntohs((u_short) ap->th_block); if (ap_opcode == ERROR) { printf("Error code %d: %s\n", ap_block, ap->th_msg); goto abort; } if (ap_opcode == ACK) { int j; if (ap_block == block) { break; } /* On an error, try to synchronize * both sides. */ j = synchnet(f); if (j && trace) { printf("discarded %d packets\n", j); } /* * RFC1129/RFC1350: We MUST NOT re-send the DATA * packet in response to an invalid ACK. Doing so * would cause the Sorcerer's Apprentice bug. */ } } if (!is_request) amount += size; is_request = 0; block++; } while (size == SEGSIZE || block == 1); abort: fclose(file); stopclock(); //if (amount > 0) // printstats("Sent", amount); return amount; }
/* * Receive a file. */ int tftp_recvfile(int f, union sock_addr *peeraddr, int fd, const char *name, const char *mode) { struct tftphdr *ap; struct tftphdr *dp; int n; volatile u_short block; volatile int size, firsttrip; volatile unsigned long amount; union sock_addr from; socklen_t fromlen; FILE *file; volatile int convert; /* true if converting crlf -> lf */ u_short dp_opcode, dp_block; startclock(); dp = w_init(); ap = (struct tftphdr *)ackbuf; convert = !strcmp(mode, "netascii"); file = fdopen(fd, convert ? "wt" : "wb"); block = 1; firsttrip = 1; amount = 0; bsd_signal(SIGALRM, timer); do { if (firsttrip) { size = makerequest(RRQ, name, ap, mode); firsttrip = 0; } else { ap->th_opcode = htons((u_short) ACK); ap->th_block = htons((u_short) block); size = 4; block++; } timeout = 0; (void)sigsetjmp(timeoutbuf, 1); send_ack: if (trace) tpacket("sent", ap, size); if (sendto(f, ackbuf, size, 0, &(peeraddr->sa), SOCKLEN(peeraddr)) != size) { alarm(0); perror("tftp: sendto"); goto abort; } write_behind(file, convert); for (;;) { alarm(rexmtval); do { fromlen = sizeof(from); n = recvfrom(f, dp, PKTSIZE, 0, &from.sa, &fromlen); } while (n <= 0); alarm(0); if (n < 0) { perror("tftp: recvfrom"); goto abort; } sa_set_port(peeraddr, SOCKPORT(&from)); /* added */ if (trace) tpacket("received", dp, n); /* should verify client address */ dp_opcode = ntohs((u_short) dp->th_opcode); dp_block = ntohs((u_short) dp->th_block); if (dp_opcode == ERROR) { printf("Error code %d: %s\n", dp_block, dp->th_msg); goto abort; } if (dp_opcode == DATA) { int j; if (dp_block == block) { break; /* have next packet */ } /* On an error, try to synchronize * both sides. */ j = synchnet(f); if (j && trace) { printf("discarded %d packets\n", j); } if (dp_block == (block - 1)) { goto send_ack; /* resend ack */ } } } /* size = write(fd, dp->th_data, n - 4); */ size = writeit(file, &dp, n - 4, convert); if (size < 0) { nak(f, peeraddr, errno + 100, NULL); break; } amount += size; } while (size == SEGSIZE); abort: /* ok to ack, since user */ ap->th_opcode = htons((u_short) ACK); /* has seen err msg */ ap->th_block = htons((u_short) block); (void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)peeraddr, SOCKLEN(peeraddr)); write_behind(file, convert); /* flush last buffer */ fclose(file); stopclock(); //if (amount > 0) // printstats("Received", amount); return amount; }
/* * Handle initial connection protocol. */ int tftp (struct tftphdr *tp, int size) { char *cp; int argn, ecode; struct formats *pf = NULL; char *origfilename; char *filename, *mode = NULL; char *val = NULL, *opt = NULL; char *ap = ackbuf + 2; ((struct tftphdr *) ackbuf)->th_opcode = ntohs (OACK); origfilename = cp = (char *) &(tp->th_stuff); argn = 0; while (cp < buf + size && *cp) { do { cp++; } while (cp < buf + size && *cp); if (*cp) { nak (EBADOP); /* Corrupt packet - no final NULL */ exit (0); } argn++; if (argn == 1) { mode = ++cp; } else if (argn == 2) { for (cp = mode; *cp; cp++) *cp = tolower (*cp); for (pf = formats; pf->f_mode; pf++) { if (!strcmp (pf->f_mode, mode)) break; } if (!pf->f_mode) { nak (EBADOP); exit (0); } if (!(filename = (*pf->f_rewrite) (origfilename, tp->th_opcode))) { nak (EACCESS); /* File denied by mapping rule */ exit (0); } if (verbosity >= 1) { if (filename == origfilename || !strcmp (filename, origfilename)) syslog (LOG_NOTICE, "%s from %s filename %s\n", tp->th_opcode == WRQ ? "WRQ" : "RRQ", inet_ntoa (from.sin_addr), filename); else syslog (LOG_NOTICE, "%s from %s filename %s remapped to %s\n", tp->th_opcode == WRQ ? "WRQ" : "RRQ", inet_ntoa (from.sin_addr), origfilename, filename); } ecode = (*pf->f_validate) (filename, tp->th_opcode, pf); if (ecode) { nak (ecode); exit (0); } opt = ++cp; } else if (argn & 1) { val = ++cp; } else { do_opt (opt, val, &ap); opt = ++cp; } } if (!pf) { nak (EBADOP); exit (0); } if (ap != (ackbuf + 2)) { if (tp->th_opcode == WRQ) (*pf->f_recv) (pf, (struct tftphdr *) ackbuf, ap - ackbuf); else (*pf->f_send) (pf, (struct tftphdr *) ackbuf, ap - ackbuf); } else { if (tp->th_opcode == WRQ) (*pf->f_recv) (pf, NULL, 0); else (*pf->f_send) (pf, NULL, 0); } exit (0); /* Request completed */ }
/* * Send the requested file. */ void sendfile(int fd, char *name, char *mode) { register struct tftphdr *ap; /* data and ack packets */ struct tftphdr *dp; volatile int block = 0, size = 0; int n; volatile unsigned long amount = 0; struct sockaddr_in from; socklen_t fromlen; volatile int convert; /* true if doing nl->crlf conversion */ FILE *file; startclock(); /* start stat's clock */ dp = r_init(); /* reset fillbuf/read-ahead code */ ap = (struct tftphdr *)ackbuf; file = fdopen(fd, "r"); convert = !strcmp(mode, "netascii"); signal(SIGALRM, timer); do { if (block == 0) size = makerequest(WRQ, name, dp, mode) - 4; else { /* size = read(fd, dp->th_data, SEGSIZE); */ size = readit(file, &dp, convert); if (size < 0) { nak(errno + 100); break; } dp->th_opcode = htons((u_short)DATA); dp->th_block = htons((u_short)block); } timeout = 0; (void) sigsetjmp(timeoutbuf, 1); send_data: if (trace) tpacket("sent", dp, size + 4); n = sendto(f, dp, size + 4, 0, (struct sockaddr *)&s_inn, sizeof(s_inn)); if (n != size + 4) { perror("tftp: sendto"); goto abort; } read_ahead(file, convert); for ( ; ; ) { alarm(rexmtval); do { fromlen = sizeof (from); n = recvfrom(f, ackbuf, sizeof (ackbuf), 0, (struct sockaddr *)&from, &fromlen); } while (n <= 0); alarm(0); if (n < 0) { perror("tftp: recvfrom"); goto abort; } s_inn.sin_port = from.sin_port; /* added */ if (trace) tpacket("received", ap, n); /* should verify packet came from server */ ap->th_opcode = ntohs(ap->th_opcode); ap->th_block = ntohs(ap->th_block); if (ap->th_opcode == ERROR) { printf("Error code %d: %s\n", ap->th_code, ap->th_msg); goto abort; } if (ap->th_opcode == ACK) { volatile int j = 0; if (ap->th_block == block) { break; } /* On an error, try to synchronize * both sides. */ j = synchnet(f); if (j && trace) { printf("discarded %d packets\n", j); } if (ap->th_block == (block-1)) { goto send_data; } } } if (block > 0) amount += size; block++; } while (size == SEGSIZE || block == 1); abort: fclose(file); stopclock(); if (amount > 0) printstats("Sent", amount); }
void FstopComms::rx(char ch) { lastrx=micros(); // store byte if(buflen >= PKT_BUFFER) buflen=PKT_BUFFER-1; cmd[buflen++]=ch; incmd=true; // got the data we expected... if(buflen >= bufwant){ if(!connected){ connected=true; disp.clear(); disp.print(CONNECTED); lastlcd=lastrx; } switch(cmd[0]){ // keepalive; do nothing case COM_KEEPALIVE: bufwant=1; buflen=0; incmd=false; break; // request to read data case COM_READ: if(bufwant == 1){ // wait for the rest of the packet bufwant=PKT_HEADER; } else{ respondRead(); } break; // request to write data case COM_WRITE: if(bufwant == 1){ // wait for rest of header bufwant=PKT_SHORTHDR; } else if(bufwant == PKT_SHORTHDR){ // got length, decide how much packet to wait for char len=cmd[PKT_LEN]; if(len < 1 || len > PKT_MAXREQ){ nak(BAD_WRITE); } else{ bufwant=PKT_HEADER+len; // header+data+checksum } } else{ // got whole packet respondWrite(); } break; // disconnect default: reset(); } } }
/* * Send the requested file. */ void send_file (struct formats *pf) { struct tftphdr *dp, *r_init (); register struct tftphdr *ap; /* ack packet */ register int size, n; volatile int block; signal (SIGALRM, timer); dp = r_init (); ap = (struct tftphdr *) ackbuf; block = 1; do { size = readit (file, &dp, pf->f_convert); if (size < 0) { nak (errno + 100); goto abort; } dp->th_opcode = htons ((u_short) DATA); dp->th_block = htons ((u_short) block); timeout = 0; setjmp (timeoutbuf); send_data: if (send (peer, (const char *) dp, size + 4, 0) != size + 4) { syslog (LOG_ERR, "tftpd: write: %m\n"); goto abort; } read_ahead (file, pf->f_convert); for (;;) { alarm (rexmtval); /* read the ack */ n = recv (peer, ackbuf, sizeof (ackbuf), 0); alarm (0); if (n < 0) { syslog (LOG_ERR, "tftpd: read: %m\n"); goto abort; } ap->th_opcode = ntohs ((u_short) ap->th_opcode); ap->th_block = ntohs ((u_short) ap->th_block); if (ap->th_opcode == ERROR) goto abort; if (ap->th_opcode == ACK) { if ((u_short) ap->th_block == (u_short) block) break; /* Re-synchronize with the other side */ synchnet (peer); if ((u_short) ap->th_block == (u_short) (block - 1)) goto send_data; } } block++; } while (size == SEGSIZE); abort: fclose (file); }
/* * Send the requested file. */ static void sendtftp(struct testcase *test, struct formats *pf) { int size; ssize_t n; /* These are volatile to live through a siglongjmp */ volatile unsigned short sendblock; /* block count */ struct tftphdr * volatile sdp = r_init(); /* data buffer */ struct tftphdr * const sap = &ackbuf.hdr; /* ack buffer */ sendblock = 1; #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer); #endif do { size = readit(test, (struct tftphdr **)&sdp, pf->f_convert); if(size < 0) { nak(errno + 100); return; } sdp->th_opcode = htons((unsigned short)opcode_DATA); sdp->th_block = htons(sendblock); timeout = 0; #ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1); #endif if(test->writedelay) { logmsg("Pausing %d seconds before %d bytes", test->writedelay, size); wait_ms(1000*test->writedelay); } send_data: if(swrite(peer, sdp, size + 4) != size + 4) { logmsg("write"); return; } read_ahead(test, pf->f_convert); for(;;) { #ifdef HAVE_ALARM alarm(rexmtval); /* read the ack */ #endif n = sread(peer, &ackbuf.storage[0], sizeof(ackbuf.storage)); #ifdef HAVE_ALARM alarm(0); #endif if(got_exit_signal) return; if(n < 0) { logmsg("read: fail"); return; } sap->th_opcode = ntohs((unsigned short)sap->th_opcode); sap->th_block = ntohs(sap->th_block); if(sap->th_opcode == opcode_ERROR) { logmsg("got ERROR"); return; } if(sap->th_opcode == opcode_ACK) { if(sap->th_block == sendblock) { break; } /* Re-synchronize with the other side */ (void) synchnet(peer); if(sap->th_block == (sendblock-1)) { goto send_data; } } } sendblock++; } while(size == SEGSIZE); }
/* * Receive a file. */ static void recvtftp(struct testcase *test, struct formats *pf) { struct tftphdr *dp; struct tftphdr *ap; /* ack buffer */ unsigned short block = 0; int n, size; #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer); #endif dp = w_init(); ap = (struct tftphdr *)ackbuf; do { timeout = 0; ap->th_opcode = htons((u_short)ACK); ap->th_block = htons((u_short)block); block++; #ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1); #endif send_ack: if (send(peer, ackbuf, 4, 0) != 4) { logmsg("write: fail\n"); goto abort; } write_behind(test, pf->f_convert); for ( ; ; ) { #ifdef HAVE_ALARM alarm(rexmtval); #endif n = recv(peer, dp, PKTSIZE, 0); #ifdef HAVE_ALARM alarm(0); #endif if (n < 0) { /* really? */ logmsg("read: fail\n"); goto abort; } dp->th_opcode = ntohs((u_short)dp->th_opcode); dp->th_block = ntohs((u_short)dp->th_block); if (dp->th_opcode == ERROR) goto abort; if (dp->th_opcode == DATA) { if (dp->th_block == block) { break; /* normal */ } /* Re-synchronize with the other side */ (void) synchnet(peer); if (dp->th_block == (block-1)) goto send_ack; /* rexmit */ } } size = writeit(test, &dp, n - 4, pf->f_convert); if (size != (n-4)) { /* ahem */ if (size < 0) nak(errno + 100); else nak(ENOSPACE); goto abort; } } while (size == SEGSIZE); write_behind(test, pf->f_convert); ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ ap->th_block = htons((u_short)(block)); (void) send(peer, ackbuf, 4, 0); #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, justquit); /* just quit on timeout */ alarm(rexmtval); #endif n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */ #ifdef HAVE_ALARM alarm(0); #endif if (n >= 4 && /* if read some data */ dp->th_opcode == DATA && /* and got a data block */ block == dp->th_block) { /* then my last ack was lost */ (void) send(peer, ackbuf, 4, 0); /* resend final ack */ } abort: return; }
/* * Handle initial connection protocol. */ static int do_tftp(struct testcase *test, struct tftphdr *tp, ssize_t size) { char *cp; int first = 1, ecode; struct formats *pf; char *filename, *mode = NULL; int error; FILE *server; #ifdef USE_WINSOCK DWORD recvtimeout, recvtimeoutbak; #endif char *option = (char *)"mode"; /* mode is implicit */ int toggle = 1; /* Open request dump file. */ server = fopen(REQUEST_DUMP, "ab"); if(!server) { error = errno; logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", REQUEST_DUMP); return -1; } /* store input protocol */ fprintf(server, "opcode: %x\n", tp->th_opcode); cp = (char *)&tp->th_stuff; filename = cp; do { bool endofit = true; while(cp < &buf.storage[size]) { if(*cp == '\0') { endofit = false; break; } cp++; } if(endofit) /* no more options */ break; /* before increasing pointer, make sure it is still within the legal space */ if((cp+1) < &buf.storage[size]) { ++cp; if(first) { /* store the mode since we need it later */ mode = cp; first = 0; } if(toggle) /* name/value pair: */ fprintf(server, "%s: %s\n", option, cp); else { /* store the name pointer */ option = cp; } toggle ^= 1; } else /* No more options */ break; } while(1); if(*cp) { nak(EBADOP); fclose(server); return 3; } /* store input protocol */ fprintf(server, "filename: %s\n", filename); for(cp = mode; cp && *cp; cp++) if(ISUPPER(*cp)) *cp = (char)tolower((int)*cp); /* store input protocol */ fclose(server); for(pf = formata; pf->f_mode; pf++) if(strcmp(pf->f_mode, mode) == 0) break; if(!pf->f_mode) { nak(EBADOP); return 2; } ecode = validate_access(test, filename, tp->th_opcode); if(ecode) { nak(ecode); return 1; } #ifdef USE_WINSOCK recvtimeout = sizeof(recvtimeoutbak); getsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, (char*)&recvtimeoutbak, (int*)&recvtimeout); recvtimeout = TIMEOUT*1000; setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, (const char*)&recvtimeout, sizeof(recvtimeout)); #endif if(tp->th_opcode == opcode_WRQ) recvtftp(test, pf); else sendtftp(test, pf); #ifdef USE_WINSOCK recvtimeout = recvtimeoutbak; setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, (const char*)&recvtimeout, sizeof(recvtimeout)); #endif return 0; }
/* * Handle initial connection protocol. */ static int tftp(struct testcase *test, struct tftphdr *tp, ssize_t size) { char *cp; int first = 1, ecode; struct formats *pf; char *filename, *mode = NULL; int error; FILE *server; /* Open request dump file. */ server = fopen(REQUEST_DUMP, "ab"); if(!server) { error = ERRNO; logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", REQUEST_DUMP); return -1; } /* store input protocol */ fprintf(server, "opcode: %x\n", tp->th_opcode); cp = (char *)&tp->th_stuff; filename = cp; again: while (cp < buf + size) { if (*cp == '\0') break; cp++; } if (*cp) { nak(EBADOP); fclose(server); return 3; } if (first) { mode = ++cp; first = 0; goto again; } /* store input protocol */ fprintf(server, "filename: %s\n", filename); for (cp = mode; cp && *cp; cp++) if(ISUPPER(*cp)) *cp = (char)tolower((int)*cp); /* store input protocol */ fprintf(server, "mode: %s\n", mode); fclose(server); for (pf = formata; pf->f_mode; pf++) if (strcmp(pf->f_mode, mode) == 0) break; if (!pf->f_mode) { nak(EBADOP); return 2; } ecode = validate_access(test, filename, tp->th_opcode); if (ecode) { nak(ecode); return 1; } if (tp->th_opcode == opcode_WRQ) recvtftp(test, pf); else sendtftp(test, pf); return 0; }
/* * Send the requested file. */ void xmitfile(struct formats *pf) { struct tftphdr *dp; struct tftphdr *ap; /* ack packet */ int size, n; volatile unsigned short block; signal(SIGALRM, timer); dp = r_init(); ap = (struct tftphdr *)ackbuf; block = 1; do { size = readit(file, &dp, pf->f_convert); if (size < 0) { nak(errno + 100); goto abort; } dp->th_opcode = htons((u_short)DATA); dp->th_block = htons((u_short)block); timeouts = 0; (void)setjmp(timeoutbuf); send_data: { int i, t = 1; for (i = 0; ; i++){ if (send(peer, dp, size + 4, 0) != size + 4) { sleep(t); t = (t < 32) ? t<< 1 : t; if (i >= 12) { syslog(LOG_ERR, "write: %m"); goto abort; } } break; } } read_ahead(file, pf->f_convert); for ( ; ; ) { alarm(rexmtval); /* read the ack */ n = recv(peer, ackbuf, sizeof (ackbuf), 0); alarm(0); if (n < 0) { syslog(LOG_ERR, "read: %m"); goto abort; } ap->th_opcode = ntohs((u_short)ap->th_opcode); ap->th_block = ntohs((u_short)ap->th_block); if (ap->th_opcode == ERROR) goto abort; if (ap->th_opcode == ACK) { if (ap->th_block == block) break; /* Re-synchronize with the other side */ (void) synchnet(peer); if (ap->th_block == (block -1)) goto send_data; } } block++; } while (size == SEGSIZE); abort: (void) fclose(file); }
/* * Receive a file. */ static void recvtftp(struct testcase *test, struct formats *pf) { ssize_t n, size; recvblock = 0; #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer); #endif rdp = w_init(); rap = (struct tftphdr *)ackbuf; do { timeout = 0; rap->th_opcode = htons((u_short)opcode_ACK); rap->th_block = htons((u_short)recvblock); recvblock++; #ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1); #endif send_ack: if (swrite(peer, ackbuf, 4) != 4) { logmsg("write: fail\n"); goto abort; } write_behind(test, pf->f_convert); for ( ; ; ) { #ifdef HAVE_ALARM alarm(rexmtval); #endif n = sread(peer, rdp, PKTSIZE); #ifdef HAVE_ALARM alarm(0); #endif if (n < 0) { /* really? */ logmsg("read: fail\n"); goto abort; } rdp->th_opcode = ntohs((u_short)rdp->th_opcode); rdp->th_block = ntohs((u_short)rdp->th_block); if (rdp->th_opcode == opcode_ERROR) goto abort; if (rdp->th_opcode == opcode_DATA) { if (rdp->th_block == recvblock) { break; /* normal */ } /* Re-synchronize with the other side */ (void) synchnet(peer); if (rdp->th_block == (recvblock-1)) goto send_ack; /* rexmit */ } } size = writeit(test, &rdp, (int)(n - 4), pf->f_convert); if (size != (n-4)) { /* ahem */ if (size < 0) nak(ERRNO + 100); else nak(ENOSPACE); goto abort; } } while (size == SEGSIZE); write_behind(test, pf->f_convert); rap->th_opcode = htons((u_short)opcode_ACK); /* send the "final" ack */ rap->th_block = htons((u_short)recvblock); (void) swrite(peer, ackbuf, 4); #if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, justtimeout); /* just abort read on timeout */ alarm(rexmtval); #endif n = sread(peer, buf, sizeof(buf)); /* normally times out and quits */ #ifdef HAVE_ALARM alarm(0); #endif if (n >= 4 && /* if read some data */ rdp->th_opcode == opcode_DATA && /* and got a data block */ recvblock == rdp->th_block) { /* then my last ack was lost */ (void) swrite(peer, ackbuf, 4); /* resend final ack */ } abort: return; }
/* * Handle initial connection protocol. */ void tftp (struct tftphdr *tp, int size) { register char *cp; int first = 1, ecode; register struct formats *pf; char *filename, *mode; filename = cp = tp->th_stuff; again: while (cp < buf + size) { if (*cp == '\0') break; cp++; } if (*cp != '\0') { nak (EBADOP); exit (1); } if (first) { mode = ++cp; first = 0; goto again; } for (cp = mode; *cp; cp++) if (isupper (*cp)) *cp = tolower (*cp); for (pf = formats; pf->f_mode; pf++) if (strcmp (pf->f_mode, mode) == 0) break; if (pf->f_mode == 0) { nak (EBADOP); exit (1); } ecode = (*pf->f_validate) (&filename, tp->th_opcode); if (logging) { syslog (LOG_INFO, "%s: %s request for %s: %s", verifyhost (&from), tp->th_opcode == WRQ ? "write" : "read", filename, errtomsg (ecode)); } if (ecode) { /* * Avoid storms of naks to a RRQ broadcast for a relative * bootfile pathname from a diskless Sun. */ if (suppress_naks && *filename != '/' && ecode == ENOTFOUND) exit (0); nak (ecode); exit (1); } if (tp->th_opcode == WRQ) (*pf->f_recv) (pf); else (*pf->f_send) (pf); exit (0); }