File:  [ELWIX - Embedded LightWeight unIX -] / tftpd / src / srv.c
Revision 1.5: download - view: text, annotated - select for diffs - revision graph
Fri Feb 21 09:02:28 2014 UTC (10 years, 4 months ago) by misho
Branches: MAIN
CVS tags: tftp0_5, TFTP0_4, HEAD
version 0.4

    1: #include "global.h"
    2: #include "exec.h"
    3: #include "srv.h"
    4: 
    5: 
    6: static void *
    7: timeoutSession(sched_task_t *task)
    8: {
    9: 	rpack_t *pkt = TASK_DATA(task);
   10: 
   11: 	ETRACE();
   12: 
   13: 	/* drop session */
   14: 	if (cli.fd > 2)
   15: 		close(cli.fd);
   16: 	rpack_resize(pkt, TFTP_PKT_MAX);
   17: 	memset(&cli, 0, sizeof cli);
   18: 
   19: 	taskExit(task, NULL);
   20: }
   21: 
   22: static void *
   23: txPkt(sched_task_t *task)
   24: {
   25: 	int wlen;
   26: 	rpack_t *pkt = TASK_DATA(task);
   27: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
   28: 
   29: 	ETRACE();
   30: 
   31: 	wlen = sendto(TASK_FD(task), RPACK_BUF(pkt), TASK_DATLEN(task), 
   32: 			0, &cli.addr.sa, cli.addr.sa.sa_len);
   33: 	if (wlen == -1)
   34: 		ESYSERR(0);
   35: 	else if (wlen != TASK_DATLEN(task)) {
   36: 		EERROR(EIO, "Sended %d bytes != packet %d bytes", 
   37: 				wlen, TASK_DATLEN(task));
   38: 		schedEvent(TASK_ROOT(task), execProg, "error", 0, NULL, TFTP_OPC_ERROR);
   39: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, 
   40: 				timeoutSession, NULL);
   41: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, TASK_DATA(task), 0);
   42: 	} else
   43: 		EVERBOSE(2, "Sended %d bytes", wlen);
   44: 	/* on error or argument, drop session */
   45: 	if (TASK_ARG(task) == (void*) -1 || ntohs(tftp->tftp_opc) == TFTP_OPC_ERROR) {
   46: 		schedEvent(TASK_ROOT(task), execProg, "error", 0, NULL, TFTP_OPC_ERROR);
   47: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, 
   48: 				timeoutSession, NULL);
   49: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, TASK_DATA(task), 0);
   50: 	}
   51: 
   52: 	taskExit(task, NULL);
   53: }
   54: 
   55: static void *
   56: txData(sched_task_t *task)
   57: {
   58: 	rpack_t *pkt = TASK_DATA(task);
   59: 	u_short code = 0, n = htons(TFTP_OPC_DATA);
   60: 	int len;
   61: 
   62: 	ETRACE();
   63: 
   64: 	RPACK_REWIND(pkt);
   65: 	rpack_uint16(pkt, &n, 0);
   66: 	n = htons(cli.seq);
   67: 	rpack_uint16(pkt, &n, 0);
   68: 
   69: 	/* max file size check */
   70: 	if (cli.tsiz && cli.tsiz < cli.seq * cli.siz) {
   71: 		len = cli.tsiz - (cli.seq - 1) * cli.siz;
   72: 		cli.close = 42;	/* last sended packet, should be close! */
   73: 	} else
   74: 		len = cli.siz;
   75: 
   76: 	len = pread(cli.fd, RPACK_NEXT(pkt), len, (cli.seq - 1) * cli.siz);
   77: 	if (len == -1) {
   78: 		ESYSERR(0);
   79: 		code = htons(3);
   80: 		goto end;
   81: 	} else {
   82: 		rpack_rnext(pkt, len);
   83: 		EVERBOSE(3, "Read from file %s %d bytes", cli.file, len);
   84: 	}
   85: 
   86: 	if (cli.siz - len)
   87: 		cli.close = 42;	/* last sended packet, should be close! */
   88: 
   89: 	schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
   90: 			TASK_DATA(task), RPACK_OFF(pkt));
   91: 	taskExit(task, NULL);
   92: end:
   93: 	RPACK_REWIND(pkt);
   94: 	n = htons(TFTP_OPC_ERROR);
   95: 	rpack_uint16(pkt, &n, 0);
   96: 	rpack_uint16(pkt, &code, 0);
   97: 	rpack_rdata(pkt, errs[ntohs(code)].err_msg, strlen(errs[ntohs(code)].err_msg) + 1);
   98: 
   99: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  100: 			TASK_DATA(task), RPACK_OFF(pkt));
  101: 	taskExit(task, NULL);
  102: }
  103: 
  104: static void *
  105: txAck(sched_task_t *task)
  106: {
  107: 	rpack_t *pkt = TASK_DATA(task);
  108: 	u_short n = htons(TFTP_OPC_ACK);
  109: 
  110: 	ETRACE();
  111: 
  112: 	RPACK_REWIND(pkt);
  113: 	rpack_uint16(pkt, &n, 0);
  114: 	n = htons(cli.seq);
  115: 	rpack_uint16(pkt, &n, 0);
  116: 
  117: 	schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
  118: 			TASK_DATA(task), RPACK_OFF(pkt));
  119: 
  120: 	if (cli.close) {
  121: 		schedEvent(TASK_ROOT(task), execProg, "complete", 0, NULL, TFTP_OPC_WRQ);
  122: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  123: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, TASK_DATA(task), 0);
  124: 		EVERBOSE(2, "Finish WRQ request");
  125: 	}
  126: 	taskExit(task, NULL);
  127: }
  128: 
  129: static int
  130: getOpts(rpack_t * __restrict pkt, int rlen)
  131: {
  132: 	char *opt, *val;
  133: 	int len;
  134: 
  135: 	if (!rlen)
  136: 		return -1;
  137: 
  138: 	do {
  139: 		/* option */
  140: 		len = str_getString(RPACK_NEXT(pkt), RPACK_REMAIN(pkt), NULL);
  141: 		if (len == -1)
  142: 			return -1;
  143: 		else
  144: 			rlen -= len;
  145: 		opt = (char*) rpack_rnext(pkt, len);
  146: 		if (!opt)
  147: 			return -1;
  148: 		EVERBOSE(7, "opt=%s rlen=%d", opt, rlen);
  149: 		/* value */
  150: 		len = str_getString(RPACK_NEXT(pkt), RPACK_REMAIN(pkt), NULL);
  151: 		if (len == -1)
  152: 			return -1;
  153: 		else
  154: 			rlen -= len;
  155: 		val = (char*) rpack_rnext(pkt, len);
  156: 		if (!val)
  157: 			return -1;
  158: 		EVERBOSE(7, "val=%s rlen=%d", val, rlen);
  159: 
  160: 		if (!strcasecmp(opt, TFTP_OPT_BLKSIZE))
  161: 			cli.tmp = strtol(val, NULL, 10);
  162: 		else if (!strcasecmp(opt, TFTP_OPT_TSIZE))
  163: 			cli.tsiz = strtoll(val, NULL, 10);
  164: 		else if (!strcasecmp(opt, TFTP_OPT_TIMEOUT))
  165: 			cli.tout.tv_sec = strtol(val, NULL, 10);
  166: 		else if (!strcasecmp(opt, TFTP_OPT_ROLLOVER)) {
  167: 			cli.roll = strtol(val, NULL, 10);
  168: 			cli.roll++;
  169: 		}
  170: 	} while (rlen > 0);
  171: 
  172: 	EVERBOSE(4, "blksize=%u tsize=%llu timeout=%u rollover=%u", 
  173: 			cli.siz, cli.tsiz, cli.tout.tv_sec, cli.roll - 1);
  174: 	return 0;
  175: }
  176: 
  177: static void *
  178: txOack(sched_task_t *task)
  179: {
  180: 	rpack_t *pkt = TASK_DATA(task);
  181: 	u_short n = htons(TFTP_OPC_OACK);
  182: 	struct stat sb;
  183: 	char szStr[STRSIZ];
  184: 
  185: 	ETRACE();
  186: 
  187: 	RPACK_REWIND(pkt);
  188: 	rpack_uint16(pkt, &n, 0);
  189: 
  190: 	/* if opcode is RRQ and tsize is 0 then we must return file size to client */
  191: 	if (cli.opc == TFTP_OPC_RRQ && !cli.tsiz && stat(cli.file, &sb) != -1)
  192: 		cli.tsiz = sb.st_size;
  193: 
  194: 	if (cli.siz > TFTP_LOAD_MAX) {
  195: 		memset(szStr, 0, sizeof szStr);
  196: 		snprintf(szStr, sizeof szStr, "%u", cli.siz);
  197: 		rpack_rdata(pkt, TFTP_OPT_BLKSIZE, strlen(TFTP_OPT_BLKSIZE) + 1);
  198: 		rpack_rdata(pkt, szStr, strlen(szStr) + 1);
  199: 	}
  200: 	if (cli.tsiz) {
  201: 		memset(szStr, 0, sizeof szStr);
  202: 		snprintf(szStr, sizeof szStr, "%llu", cli.tsiz);
  203: 		rpack_rdata(pkt, TFTP_OPT_TSIZE, strlen(TFTP_OPT_TSIZE) + 1);
  204: 		rpack_rdata(pkt, szStr, strlen(szStr) + 1);
  205: 	}
  206: 	if (cli.tout.tv_sec) {
  207: 		memset(szStr, 0, sizeof szStr);
  208: 		snprintf(szStr, sizeof szStr, "%u", cli.tout.tv_sec);
  209: 		rpack_rdata(pkt, TFTP_OPT_TIMEOUT, strlen(TFTP_OPT_TIMEOUT) + 1);
  210: 		rpack_rdata(pkt, szStr, strlen(szStr) + 1);
  211: 	}
  212: 	if (cli.roll) {
  213: 		memset(szStr, 0, sizeof szStr);
  214: 		snprintf(szStr, sizeof szStr, "%u", cli.roll - 1);
  215: 		rpack_rdata(pkt, TFTP_OPT_ROLLOVER, strlen(TFTP_OPT_ROLLOVER) + 1);
  216: 		rpack_rdata(pkt, szStr, strlen(szStr) + 1);
  217: 	}
  218: 
  219: 	EVERBOSE(4, "blksize=%u tsize=%llu timeout=%u rollover=%u", 
  220: 			cli.siz, cli.tsiz, cli.tout.tv_sec, cli.roll - 1);
  221: 	schedCallOnce(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
  222: 			TASK_DATA(task), RPACK_OFF(pkt));
  223: 	taskExit(task, NULL);
  224: }
  225: 
  226: static void *
  227: RQ(sched_task_t *task)
  228: {
  229: 	rpack_t *pkt = TASK_DATA(task);
  230: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  231: 	int len, rlen = TASK_DATLEN(task) - 2;
  232: 	char *str;
  233: 	u_short code = 0;
  234: 
  235: 	ETRACE();
  236: 
  237: 	cli.siz = TFTP_LOAD_MAX;
  238: 	cli.opc = ntohs(rpack_uint16(pkt, NULL, 0));
  239: 	len = str_getString(RPACK_NEXT(pkt), rlen, &str);
  240: 	if (len == -1)
  241: 		goto end;
  242: 	else {
  243: 		strlcpy(cli.file, (char*) RPACK_NEXT(pkt), sizeof cli.file);
  244: 		rlen -= len;
  245: 		rpack_rnext(pkt, len);
  246: 	}
  247: 	len = str_getString((const u_char*) str, rlen, NULL);
  248: 	if (len == -1)
  249: 		goto end;
  250: 	else {
  251: 		rlen -= len;
  252: 		rpack_rnext(pkt, len);
  253: 		if (!strcasecmp(str, TFTP_MODE_ASCII))
  254: 			strlcpy(cli.mode, TFTP_MODE_ASCII, sizeof cli.mode);
  255: 		else if (!strcasecmp(str, TFTP_MODE_OCTET))
  256: 			strlcpy(cli.mode, TFTP_MODE_OCTET, sizeof cli.mode);
  257: 		else if (!strcasecmp(str, TFTP_MODE_MAIL)) {
  258: 			strlcpy(cli.mode, TFTP_MODE_MAIL, sizeof cli.mode);
  259: 			code = htons(4);
  260: 			goto end;
  261: 		} else {
  262: 			code = htons(1);
  263: 			goto end;
  264: 		}
  265: 	}
  266: 
  267: 	switch (cli.opc) {
  268: 		case TFTP_OPC_RRQ:
  269: 			code = O_RDONLY;
  270: 			EVERBOSE(2, "RRQ:: file=%s mode=%s\n", cli.file, cli.mode);
  271: 			break;
  272: 		case TFTP_OPC_WRQ:
  273: 			code = O_WRONLY | O_CREAT;
  274: 			str = (char*) cfg_getAttribute(&cfg, "tftpd", "override");
  275: 			if (!str || tolower(*str) != 'y')
  276: 				code |= O_EXCL;
  277: 			EVERBOSE(2, "WRQ:: file=%s mode=%s\n", cli.file, cli.mode);
  278: 			break;
  279: 	}
  280: 
  281: 	cli.fd = open(cli.file, code, 0644);
  282: 	if (cli.fd == -1) {
  283: 		if (errno == EACCES)
  284: 			code = htons(2);
  285: 		else if (errno == ENFILE)
  286: 			code = htons(3);
  287: 		else if (errno == EEXIST)
  288: 			code = htons(6);
  289: 		else
  290: 			code = htons(0);
  291: 		ESYSERR(0);
  292: 		goto end;
  293: 	} else
  294: 		cli.seq = 0;
  295: 
  296: 	schedEvent(TASK_ROOT(task), execProg, "request", 0, NULL, cli.opc);
  297: 
  298: 	if (!getOpts(pkt, rlen)) {
  299: 		if (cli.tmp > TFTP_LOAD_MAX) {
  300: 			if (rpack_resize(pkt, cli.tmp + 4))
  301: 				ELIBERR(elwix);
  302: 			else
  303: 				cli.siz = cli.tmp;
  304: 		}
  305: 		if (cli.tout.tv_sec) {
  306: 			schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, 
  307: 					timeoutSession, NULL);
  308: 			schedTimer(TASK_ROOT(task), timeoutSession, NULL, 
  309: 					cli.tout, TASK_DATA(task), 0);
  310: 		}
  311: 		schedEvent(TASK_ROOT(task), txOack, NULL, TASK_FD(task), 
  312: 				TASK_DATA(task), 0);
  313: 	} else if (cli.opc == TFTP_OPC_WRQ) {
  314: 		/* ack */
  315: 		tftp->tftp_opc = htons(TFTP_OPC_ACK);
  316: 		RPACK_REWIND(pkt);
  317: 		rpack_uint16(pkt, NULL, 0);
  318: 		rpack_uint16(pkt, &cli.seq, 0);
  319: 
  320: 		schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
  321: 				TASK_DATA(task), RPACK_OFF(pkt));
  322: 	} else
  323: 		schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task), 
  324: 				TASK_DATA(task), 0);
  325: 
  326: 	cli.seq = 1;	/* 1st ack */
  327: 	taskExit(task, NULL);
  328: end:
  329: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  330: 	RPACK_REWIND(pkt);
  331: 	rpack_uint16(pkt, NULL, 0);
  332: 	rpack_uint16(pkt, &code, 0);
  333: 	rpack_rdata(pkt, errs[ntohs(code)].err_msg, strlen(errs[ntohs(code)].err_msg) + 1);
  334: 
  335: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  336: 			TASK_DATA(task), RPACK_OFF(pkt));
  337: 	taskExit(task, NULL);
  338: }
  339: 
  340: static void *
  341: ACK(sched_task_t *task)
  342: {
  343: 	rpack_t *pkt = TASK_DATA(task);
  344: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  345: 	u_short code;
  346: 
  347: 	ETRACE();
  348: 
  349: 	RPACK_REWIND(pkt);
  350: 	code = rpack_uint16(pkt, NULL, 0);
  351: 	if (ntohs(code) != TFTP_OPC_ACK) {
  352: 		code = htons(5);
  353: 		goto end;
  354: 	}
  355: 
  356: 	code = rpack_uint16(pkt, NULL, 0);
  357: 	if (ntohs(code) > cli.seq || (ntohs(code) < (cli.seq - 1))) {
  358: 		code = htons(5);
  359: 		goto end;
  360: 	} else if (ntohs(code) == cli.seq) {
  361: 		/* check for rollover seq id */
  362: 		if (cli.roll && cli.seq == USHRT_MAX)
  363: 			cli.seq = cli.roll - 1;
  364: 		else
  365: 			cli.seq++;
  366: 	}
  367: 
  368: 	EVERBOSE(3, "ACK:: seq=%hu; my new seq=%hu;", ntohs(code), cli.seq);
  369: 
  370: 	if (!cli.close)
  371: 		schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task), 
  372: 				TASK_DATA(task), 0);
  373: 	else {
  374: 		schedEvent(TASK_ROOT(task), execProg, "complete", 0, NULL, TFTP_OPC_RRQ);
  375: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  376: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, TASK_DATA(task), 0);
  377: 		EVERBOSE(2, "Finish RRQ request");
  378: 	}
  379: 	taskExit(task, NULL);
  380: end:
  381: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  382: 	RPACK_REWIND(pkt);
  383: 	rpack_uint16(pkt, NULL, 0);
  384: 	rpack_uint16(pkt, &code, 0);
  385: 	rpack_rdata(pkt, errs[ntohs(code)].err_msg, strlen(errs[ntohs(code)].err_msg) + 1);
  386: 
  387: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  388: 			TASK_DATA(task), RPACK_OFF(pkt));
  389: 	taskExit(task, NULL);
  390: }
  391: 
  392: static void *
  393: DATA(sched_task_t *task)
  394: {
  395: 	rpack_t *pkt = TASK_DATA(task);
  396: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  397: 	u_short code;
  398: 	int len;
  399: 
  400: 	ETRACE();
  401: 
  402: 	RPACK_REWIND(pkt);
  403: 	code = rpack_uint16(pkt, NULL, 0);
  404: 	if (ntohs(code) != TFTP_OPC_DATA) {
  405: 		code = htons(5);
  406: 		goto end;
  407: 	}
  408: 
  409: 	code = rpack_uint16(pkt, NULL, 0);
  410: 	if (ntohs(code) < cli.seq || ntohs(code) > cli.seq + 1) {
  411: 		code = htons(5);
  412: 		goto end;
  413: 	} else
  414: 		cli.seq = ntohs(code);
  415: 
  416: 	/* max file size check */
  417: 	len = TASK_DATLEN(task) - RPACK_OFF(pkt);
  418: 	if (cli.tsiz && cli.tsiz < cli.seq * cli.siz)
  419: 		len = MIN(len, cli.tsiz - (cli.seq - 1) * cli.siz);
  420: 	if (len < cli.siz)
  421: 		cli.close = 42;	/* last received packet, should be close! */
  422: 
  423: 	EVERBOSE(3, "DATA:: seq=%hu; len=%d", cli.seq, len);
  424: 
  425: 	len = pwrite(cli.fd, RPACK_NEXT(pkt), len, (cli.seq - 1) * cli.siz);
  426: 	if (len == -1) {
  427: 		ESYSERR(0);
  428: 		code = htons(3);
  429: 		goto end;
  430: 	} else {
  431: 		rpack_rnext(pkt, len);
  432: 		EVERBOSE(3, "Written to file %s %d bytes", cli.file, len);
  433: 	}
  434: 
  435: 	schedEvent(TASK_ROOT(task), txAck, NULL, TASK_FD(task), TASK_DATA(task), 0);
  436: 	taskExit(task, NULL);
  437: end:
  438: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  439: 	RPACK_REWIND(pkt);
  440: 	rpack_uint16(pkt, NULL, 0);
  441: 	rpack_uint16(pkt, &code, 0);
  442: 	rpack_rdata(pkt, errs[ntohs(code)].err_msg, strlen(errs[ntohs(code)].err_msg) + 1);
  443: 
  444: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  445: 			TASK_DATA(task), RPACK_OFF(pkt));
  446: 	taskExit(task, NULL);
  447: }
  448: 
  449: void *
  450: rxPkt(sched_task_t *task)
  451: {
  452: 	sockaddr_t sa;
  453: 	socklen_t salen = sizeof sa;
  454: 	int rlen;
  455: 	rpack_t *pkt = TASK_DATA(task);
  456: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  457: 	u_short code;
  458: 
  459: 	ETRACE();
  460: 
  461: 	memset(RPACK_BUF(pkt), 0, RPACK_LEN(pkt));
  462: 	rlen = recvfrom(TASK_FD(task), RPACK_BUF(pkt), RPACK_LEN(pkt), 0, &sa.sa, &salen);
  463: 	if (rlen == -1) {
  464: 		ESYSERR(0);
  465: 		goto end;
  466: 	} else if (!cli.addr.sa.sa_len) {
  467: 		cli.addr = sa;
  468: 		RPACK_REWIND(pkt);
  469: 		switch (ntohs(tftp->tftp_opc)) {
  470: 			case TFTP_OPC_RRQ:
  471: 			case TFTP_OPC_WRQ:
  472: 				schedEvent(TASK_ROOT(task), RQ, NULL, TASK_FD(task), 
  473: 						TASK_DATA(task), rlen);
  474: 				break;
  475: 			case TFTP_OPC_ERROR:
  476: 			default:
  477: 				RPACK_REWIND(pkt);
  478: 				code = htons(TFTP_OPC_ERROR);
  479: 				rpack_uint16(pkt, &code, 0);
  480: 				code = htons(4);
  481: 				rpack_uint16(pkt, &code, 0);
  482: 				rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
  483: 
  484: 				schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  485: 						TASK_DATA(task), RPACK_OFF(pkt));
  486: 				goto end;
  487: 		}
  488: 	} else if (memcmp(&cli.addr, &sa, salen)) {
  489: 		EERROR(LOG_WARNING, "Packet dropped!!!\n"
  490: 				"Get frame from different address for this session");
  491: 		goto end;
  492: 	} else
  493: 		switch (ntohs(tftp->tftp_opc)) {
  494: 			case TFTP_OPC_ACK:
  495: 				schedEvent(TASK_ROOT(task), ACK, NULL, TASK_FD(task), 
  496: 						TASK_DATA(task), rlen);
  497: 				break;
  498: 			case TFTP_OPC_DATA:
  499: 				schedEvent(TASK_ROOT(task), DATA, NULL, TASK_FD(task), 
  500: 						TASK_DATA(task), rlen);
  501: 				break;
  502: 			case TFTP_OPC_OACK:
  503: 			case TFTP_OPC_ERROR:
  504: 			default:
  505: 				RPACK_REWIND(pkt);
  506: 				code = htons(TFTP_OPC_ERROR);
  507: 				rpack_uint16(pkt, &code, 0);
  508: 				code = htons(4);
  509: 				rpack_uint16(pkt, &code, 0);
  510: 				rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
  511: 
  512: 				schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  513: 						TASK_DATA(task), RPACK_OFF(pkt));
  514: 				goto end;
  515: 		}
  516: 
  517: 	schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  518: 	schedTimer(TASK_ROOT(task), timeoutSession, NULL, 
  519: 			cli.tout.tv_sec ? cli.tout : timeout, TASK_DATA(task), 0);
  520: end:
  521: 	schedReadSelf(task);
  522: 	taskExit(task, NULL);
  523: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>