File:  [ELWIX - Embedded LightWeight unIX -] / tftpd / src / srv.c
Revision 1.3: download - view: text, annotated - select for diffs - revision graph
Tue Feb 18 12:46:39 2014 UTC (10 years, 4 months ago) by misho
Branches: MAIN
CVS tags: HEAD
start tftp opts support

    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: 	ETRACE();
   10: 
   11: 	/* drop session */
   12: 	if (cli.fd > 2)
   13: 		close(cli.fd);
   14: 	memset(&cli, 0, sizeof cli);
   15: 
   16: 	taskExit(task, NULL);
   17: }
   18: 
   19: static void *
   20: txPkt(sched_task_t *task)
   21: {
   22: 	int wlen;
   23: 	rpack_t *pkt = TASK_DATA(task);
   24: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
   25: 
   26: 	ETRACE();
   27: 
   28: 	wlen = sendto(TASK_FD(task), RPACK_BUF(pkt), TASK_DATLEN(task), 
   29: 			0, &cli.addr.sa, cli.addr.sa.sa_len);
   30: 	if (wlen == -1)
   31: 		ESYSERR(0);
   32: 	else if (wlen != TASK_DATLEN(task)) {
   33: 		EERROR(EIO, "Sended %d bytes != packet %d bytes", 
   34: 				wlen, TASK_DATLEN(task));
   35: 		schedEvent(TASK_ROOT(task), execProg, "error", 0, NULL, TFTP_OPC_ERROR);
   36: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, 
   37: 				timeoutSession, NULL);
   38: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
   39: 	} else
   40: 		EVERBOSE(2, "Sended %d bytes", wlen);
   41: 	/* on error or argument, drop session */
   42: 	if (TASK_ARG(task) == (void*) -1 || ntohs(tftp->tftp_opc) == TFTP_OPC_ERROR) {
   43: 		schedEvent(TASK_ROOT(task), execProg, "error", 0, NULL, TFTP_OPC_ERROR);
   44: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, 
   45: 				timeoutSession, NULL);
   46: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
   47: 	}
   48: 
   49: 	taskExit(task, NULL);
   50: }
   51: 
   52: static void *
   53: txData(sched_task_t *task)
   54: {
   55: 	rpack_t *pkt = TASK_DATA(task);
   56: 	u_short code = 0, n = htons(TFTP_OPC_DATA);
   57: 	int len;
   58: 
   59: 	ETRACE();
   60: 
   61: 	RPACK_REWIND(pkt);
   62: 	rpack_uint16(pkt, &n, 0);
   63: 	n = htons(cli.seq);
   64: 	rpack_uint16(pkt, &n, 0);
   65: 
   66: 	len = pread(cli.fd, RPACK_NEXT(pkt), cli.siz, (cli.seq - 1) * cli.siz);
   67: 	if (len == -1) {
   68: 		ESYSERR(0);
   69: 		code = htole16(3);
   70: 		goto end;
   71: 	} else {
   72: 		rpack_rnext(pkt, len);
   73: 		EVERBOSE(3, "Read from file %s %d bytes", cli.file, len);
   74: 	}
   75: 
   76: 	if (cli.siz - len)
   77: 		cli.close = 42;	/* last sended packet, should be close! */
   78: 
   79: 	schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
   80: 			TASK_DATA(task), RPACK_OFF(pkt));
   81: 	taskExit(task, NULL);
   82: end:
   83: 	RPACK_REWIND(pkt);
   84: 	n = htons(TFTP_OPC_ERROR);
   85: 	rpack_uint16(pkt, &n, 0);
   86: 	rpack_uint16(pkt, &code, 0);
   87: 	rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
   88: 
   89: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
   90: 			TASK_DATA(task), RPACK_OFF(pkt));
   91: 	taskExit(task, NULL);
   92: }
   93: 
   94: static void *
   95: txAck(sched_task_t *task)
   96: {
   97: 	rpack_t *pkt = TASK_DATA(task);
   98: 	u_short n = htons(TFTP_OPC_ACK);
   99: 
  100: 	ETRACE();
  101: 
  102: 	RPACK_REWIND(pkt);
  103: 	rpack_uint16(pkt, &n, 0);
  104: 	n = htons(cli.seq);
  105: 	rpack_uint16(pkt, &n, 0);
  106: 
  107: 	schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
  108: 			TASK_DATA(task), RPACK_OFF(pkt));
  109: 
  110: 	if (cli.close) {
  111: 		schedEvent(TASK_ROOT(task), execProg, "complete", 0, NULL, TFTP_OPC_WRQ);
  112: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  113: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
  114: 		EVERBOSE(2, "Finish WRQ request");
  115: 	}
  116: 	taskExit(task, NULL);
  117: }
  118: 
  119: static int
  120: getOpts(const char *opts, int rlen)
  121: {
  122: 	if (!opts)
  123: 		return -1;
  124: 
  125: 	return 0;
  126: }
  127: 
  128: static void *
  129: RQ(sched_task_t *task)
  130: {
  131: 	rpack_t *pkt = TASK_DATA(task);
  132: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  133: 	int len, rlen = TASK_DATLEN(task) - 2;
  134: 	char *str, *opts;
  135: 	u_short code = 0;
  136: 
  137: 	ETRACE();
  138: 
  139: 	cli.siz = TFTP_LOAD_MAX;
  140: 	len = str_getString(tftp->tftp_data, rlen, &str);
  141: 	if (len == -1)
  142: 		goto end;
  143: 	else {
  144: 		rlen -= len;
  145: 		strlcpy(cli.file, (char*) tftp->tftp_data, sizeof cli.file);
  146: 	}
  147: 	len = str_getString((const u_char*) str, rlen, &opts);
  148: 	if (len == -1)
  149: 		goto end;
  150: 	else {
  151: 		rlen -= len;
  152: 		if (!strcasecmp(str, TFTP_MODE_ASCII))
  153: 			strlcpy(cli.mode, TFTP_MODE_ASCII, sizeof cli.mode);
  154: 		else if (!strcasecmp(str, TFTP_MODE_OCTET))
  155: 			strlcpy(cli.mode, TFTP_MODE_OCTET, sizeof cli.mode);
  156: 		else if (!strcasecmp(str, TFTP_MODE_MAIL)) {
  157: 			strlcpy(cli.mode, TFTP_MODE_MAIL, sizeof cli.mode);
  158: 			code = htole16(4);
  159: 			goto end;
  160: 		} else {
  161: 			code = htole16(1);
  162: 			goto end;
  163: 		}
  164: 	}
  165: 
  166: 	/* tftp extended options */
  167: 	if (!RPACK_ISEND(pkt) && !getOpts(opts, rlen))
  168: 		cli.opts = 42;	/* we have options */
  169: 
  170: 	cli.opc = ntohs(tftp->tftp_opc);
  171: 	switch (cli.opc) {
  172: 		case TFTP_OPC_RRQ:
  173: 			code = O_RDONLY;
  174: 			EVERBOSE(2, "RRQ:: file=%s mode=%s\n", cli.file, cli.mode);
  175: 			break;
  176: 		case TFTP_OPC_WRQ:
  177: 			code = O_WRONLY | O_CREAT;
  178: 			str = (char*) cfg_getAttribute(&cfg, "tftpd", "override");
  179: 			if (!str || tolower(*str) != 'y')
  180: 				code |= O_EXCL;
  181: 			EVERBOSE(2, "WRQ:: file=%s mode=%s\n", cli.file, cli.mode);
  182: 			break;
  183: 	}
  184: 	cli.fd = open(cli.file, code, 0644);
  185: 	if (cli.fd == -1) {
  186: 		if (errno == EACCES)
  187: 			code = htole16(2);
  188: 		else if (errno == ENFILE)
  189: 			code = htole16(3);
  190: 		else if (errno == EEXIST)
  191: 			code = htole16(6);
  192: 		else
  193: 			code = htole16(0);
  194: 		ESYSERR(0);
  195: 		goto end;
  196: 	} else
  197: 		cli.seq = 0;
  198: 
  199: 	schedEvent(TASK_ROOT(task), execProg, "request", 0, NULL, cli.opc);
  200: 
  201: 	if (cli.opc == TFTP_OPC_WRQ) {
  202: 		/* ack */
  203: 		tftp->tftp_opc = htons(TFTP_OPC_ACK);
  204: 		RPACK_REWIND(pkt);
  205: 		rpack_uint16(pkt, NULL, 0);
  206: 		rpack_uint16(pkt, &cli.seq, 0);
  207: 
  208: 		schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task), 
  209: 				TASK_DATA(task), RPACK_OFF(pkt));
  210: 	} else
  211: 		schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task), 
  212: 				TASK_DATA(task), 0);
  213: 
  214: 	cli.seq = 1;	/* 1st ack */
  215: 	taskExit(task, NULL);
  216: end:
  217: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  218: 	RPACK_REWIND(pkt);
  219: 	rpack_uint16(pkt, NULL, 0);
  220: 	rpack_uint16(pkt, &code, 0);
  221: 	rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
  222: 
  223: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  224: 			TASK_DATA(task), RPACK_OFF(pkt));
  225: 	taskExit(task, NULL);
  226: }
  227: 
  228: static void *
  229: ACK(sched_task_t *task)
  230: {
  231: 	rpack_t *pkt = TASK_DATA(task);
  232: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  233: 	u_short code;
  234: 
  235: 	ETRACE();
  236: 
  237: 	RPACK_REWIND(pkt);
  238: 	code = rpack_uint16(pkt, NULL, 0);
  239: 	if (ntohs(code) != TFTP_OPC_ACK) {
  240: 		code = htole16(5);
  241: 		goto end;
  242: 	}
  243: 
  244: 	code = rpack_uint16(pkt, NULL, 0);
  245: 	if (ntohs(code) > cli.seq || (ntohs(code) < (cli.seq - 1))) {
  246: 		code = htole16(5);
  247: 		goto end;
  248: 	} else if (ntohs(code) == cli.seq)
  249: 		cli.seq++;
  250: 
  251: 	EVERBOSE(3, "ACK:: seq=%hu; my new seq=%hu;", ntohs(code), cli.seq);
  252: 
  253: 	if (!cli.close)
  254: 		schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task), 
  255: 				TASK_DATA(task), 0);
  256: 	else {
  257: 		schedEvent(TASK_ROOT(task), execProg, "complete", 0, NULL, TFTP_OPC_RRQ);
  258: 		schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  259: 		schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
  260: 		EVERBOSE(2, "Finish RRQ request");
  261: 	}
  262: 	taskExit(task, NULL);
  263: end:
  264: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  265: 	RPACK_REWIND(pkt);
  266: 	rpack_uint16(pkt, NULL, 0);
  267: 	rpack_uint16(pkt, &code, 0);
  268: 	rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
  269: 
  270: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  271: 			TASK_DATA(task), RPACK_OFF(pkt));
  272: 	taskExit(task, NULL);
  273: }
  274: 
  275: static void *
  276: DATA(sched_task_t *task)
  277: {
  278: 	rpack_t *pkt = TASK_DATA(task);
  279: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  280: 	u_short code;
  281: 	int len;
  282: 
  283: 	ETRACE();
  284: 
  285: 	RPACK_REWIND(pkt);
  286: 	code = rpack_uint16(pkt, NULL, 0);
  287: 	if (ntohs(code) != TFTP_OPC_DATA) {
  288: 		code = htole16(5);
  289: 		goto end;
  290: 	}
  291: 
  292: 	code = rpack_uint16(pkt, NULL, 0);
  293: 	if (ntohs(code) < cli.seq || ntohs(code) > cli.seq + 1) {
  294: 		code = htole16(5);
  295: 		goto end;
  296: 	} else
  297: 		cli.seq = ntohs(code);
  298: 
  299: 	len = TASK_DATLEN(task) - RPACK_OFF(pkt);
  300: 	if (len < cli.siz)
  301: 		cli.close = 42;	/* last received packet, should be close! */
  302: 
  303: 	EVERBOSE(3, "DATA:: seq=%hu; len=%d", cli.seq, len);
  304: 
  305: 	len = pwrite(cli.fd, RPACK_NEXT(pkt), len, (cli.seq - 1) * cli.siz);
  306: 	if (len == -1) {
  307: 		ESYSERR(0);
  308: 		code = htole16(3);
  309: 		goto end;
  310: 	} else {
  311: 		rpack_rnext(pkt, len);
  312: 		EVERBOSE(3, "Written to file %s %d bytes", cli.file, len);
  313: 	}
  314: 
  315: 	schedEvent(TASK_ROOT(task), txAck, NULL, TASK_FD(task), TASK_DATA(task), 0);
  316: 	taskExit(task, NULL);
  317: end:
  318: 	tftp->tftp_opc = htons(TFTP_OPC_ERROR);
  319: 	RPACK_REWIND(pkt);
  320: 	rpack_uint16(pkt, NULL, 0);
  321: 	rpack_uint16(pkt, &code, 0);
  322: 	rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
  323: 
  324: 	schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  325: 			TASK_DATA(task), RPACK_OFF(pkt));
  326: 	taskExit(task, NULL);
  327: }
  328: 
  329: void *
  330: rxPkt(sched_task_t *task)
  331: {
  332: 	sockaddr_t sa;
  333: 	socklen_t salen = sizeof sa;
  334: 	int rlen;
  335: 	rpack_t *pkt = TASK_DATA(task);
  336: 	struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
  337: 	u_short code;
  338: 
  339: 	ETRACE();
  340: 
  341: 	memset(RPACK_BUF(pkt), 0, RPACK_LEN(pkt));
  342: 	rlen = recvfrom(TASK_FD(task), RPACK_BUF(pkt), RPACK_LEN(pkt), 0, &sa.sa, &salen);
  343: 	if (rlen == -1) {
  344: 		ESYSERR(0);
  345: 		goto end;
  346: 	} else if (!cli.addr.sa.sa_len) {
  347: 		cli.addr = sa;
  348: 		switch (ntohs(tftp->tftp_opc)) {
  349: 			case TFTP_OPC_RRQ:
  350: 			case TFTP_OPC_WRQ:
  351: 				schedEvent(TASK_ROOT(task), RQ, NULL, TASK_FD(task), 
  352: 						TASK_DATA(task), rlen);
  353: 				break;
  354: 			case TFTP_OPC_ERROR:
  355: 			default:
  356: 				RPACK_REWIND(pkt);
  357: 				code = htons(TFTP_OPC_ERROR);
  358: 				rpack_uint16(pkt, &code, 0);
  359: 				code = htole16(4);
  360: 				rpack_uint16(pkt, &code, 0);
  361: 				rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
  362: 
  363: 				schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  364: 						TASK_DATA(task), RPACK_OFF(pkt));
  365: 				goto end;
  366: 		}
  367: 	} else if (memcmp(&cli.addr, &sa, salen)) {
  368: 		EERROR(LOG_WARNING, "Packet dropped!!!\n"
  369: 				"Get frame from different address for this session");
  370: 		goto end;
  371: 	} else
  372: 		switch (ntohs(tftp->tftp_opc)) {
  373: 			case TFTP_OPC_ACK:
  374: 				schedEvent(TASK_ROOT(task), ACK, NULL, TASK_FD(task), 
  375: 						TASK_DATA(task), rlen);
  376: 				break;
  377: 			case TFTP_OPC_DATA:
  378: 				schedEvent(TASK_ROOT(task), DATA, NULL, TASK_FD(task), 
  379: 						TASK_DATA(task), rlen);
  380: 				break;
  381: 			case TFTP_OPC_OACK:
  382: 				ELOGGER(LOG_WARNING, "oack");
  383: 				/*
  384: 				schedEvent(TASK_ROOT(task), OACK, NULL, TASK_FD(task), 
  385: 						TASK_DATA(task), rlen);
  386: 						*/
  387: 				break;
  388: 			case TFTP_OPC_ERROR:
  389: 			default:
  390: 				RPACK_REWIND(pkt);
  391: 				code = htons(TFTP_OPC_ERROR);
  392: 				rpack_uint16(pkt, &code, 0);
  393: 				code = htole16(4);
  394: 				rpack_uint16(pkt, &code, 0);
  395: 				rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
  396: 
  397: 				schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task), 
  398: 						TASK_DATA(task), RPACK_OFF(pkt));
  399: 				goto end;
  400: 		}
  401: 
  402: 	schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
  403: 	schedTimer(TASK_ROOT(task), timeoutSession, NULL, timeout, NULL, 0);
  404: end:
  405: 	schedReadSelf(task);
  406: 	taskExit(task, NULL);
  407: }

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