1 /*
2 * ex: set tabstop=4 ai expandtab softtabstop=4 shiftwidth=4:
3 * -*- mode: c-basic-indent: 4; tab-width: 4; indent-tabls-mode: nil -*-
4 * $Id: protocol.c 1010 2008-07-19 16:29:55Z boote $
5 */
6 /************************************************************************
7 * *
8 * Copyright (C) 2002 *
9 * Internet2 *
10 * All Rights Reserved *
11 * *
12 ************************************************************************/
13 /*
14 ** File: protocol.c
15 **
16 ** Author: Jeff W. Boote
17 ** Anatoly Karp
18 **
19 ** Date: Tue Apr 2 10:42:12 2002
20 **
21 ** Description: This file contains the private functions that
22 ** speak the owamp protocol directly.
23 ** (i.e. read and write the data and save it
24 ** to structures for the rest of the api to deal
25 ** with.)
26 **
27 ** The idea is to basically keep all network ordering
28 ** architecture dependant things in this file. And
29 ** hopefully to minimize the impact of any changes
30 ** to the actual protocol message formats.
31 **
32 ** The message templates are here for convienent
33 ** reference for byte offsets in the code - for
34 ** explainations of the fields please see the
35 ** relevant specification document.
36 ** RFC 4656
37 **
38 ** Ease of referenceing byte offsets is also why
39 ** the &buf[BYTE] notation is being used.
40 ** Now the C99 may actually start to take hold,
41 ** (char *) is the type being used to accomplish this.
42 */
43
44 #include <owampP.h>
45 #include <I2util/util.h>
46
47 /*
48 * ServerGreeting message format:
49 *
50 * size: 64 octets
51 *
52 * 0 1 2 3
53 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
54 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 * 00| |
56 * 04| Unused (12 octets) |
57 * 08| |
58 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59 * 12| Modes |
60 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61 * 16| |
62 * 20| Challenge (16 octets) |
63 * 24| |
64 * 28| |
65 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66 * 32| |
67 * 36| Salt (16 octets) |
68 * 40| |
69 * 44| |
70 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 * 48| Count (4 octets) |
72 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73 * 52| |
74 * 56| MBZ (12 octets) |
75 * 60| |
76 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77 *
78 */
79 OWPErrSeverity
_OWPWriteServerGreeting(OWPControl cntrl,int * retn_on_err,uint32_t avail_modes,uint8_t * challenge,uint8_t * salt,uint32_t count)80 _OWPWriteServerGreeting(
81 OWPControl cntrl,
82 int *retn_on_err,
83 uint32_t avail_modes,
84 uint8_t *challenge, /* [16] */
85 uint8_t *salt, /* [16] */
86 uint32_t count
87 )
88 {
89 /*
90 * buf_aligned it to ensure uint32_t alignment, but I use
91 * buf for actual assignments to make the array offsets agree with
92 * the byte offsets shown above.
93 */
94 char *buf = (char *)cntrl->msg;
95
96 if(!_OWPStateIsInitial(cntrl)){
97 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
98 "_OWPWriteServerGreeting:called in wrong state.");
99 return OWPErrFATAL;
100 }
101
102 /*
103 * Set unused/MBZ bits to 0. (and initialize rest)
104 */
105 memset(buf,0,64);
106
107 *((uint32_t *)&buf[12]) = htonl(avail_modes);
108 memcpy(&buf[16],challenge,16);
109 memcpy(&buf[32],salt,16);
110 *((uint32_t *)&buf[48]) = htonl(count);
111 if(I2Writeni(cntrl->sockfd,buf,64,retn_on_err) != 64){
112 return OWPErrFATAL;
113 }
114
115 cntrl->state = _OWPStateSetup;
116
117 return OWPErrOK;
118 }
119
120 OWPErrSeverity
_OWPReadServerGreeting(OWPControl cntrl,int * retn_on_intr,uint32_t * mode,uint8_t * challenge,uint8_t * salt,uint32_t * count)121 _OWPReadServerGreeting(
122 OWPControl cntrl,
123 int *retn_on_intr,
124 uint32_t *mode, /* modes available - returned */
125 uint8_t *challenge, /* [16] : challenge - returned */
126 uint8_t *salt, /* [16] : challenge - returned */
127 uint32_t *count /* count - returned */
128 )
129 {
130 char *buf = (char *)cntrl->msg;
131
132 if(!_OWPStateIsInitial(cntrl)){
133 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
134 "_OWPReadServerGreeting: called in wrong state.");
135 return OWPErrFATAL;
136 }
137
138 if(I2Readni(cntrl->sockfd,buf,64,retn_on_intr) != 64){
139 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
140 "Read failed: (%s)",strerror(errno));
141 return (int)OWPErrFATAL;
142 }
143
144 *mode = ntohl(*((uint32_t *)&buf[12]));
145 memcpy(challenge,&buf[16],16);
146 memcpy(salt,&buf[32],16);
147 *count = ntohl(*((uint32_t *)&buf[48]));
148
149 cntrl->state = _OWPStateSetup;
150
151 return OWPErrOK;
152 }
153
154 /*
155 * SetupResponse message format:
156 *
157 * size: 164 octets
158 *
159 * 0 1 2 3
160 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
161 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162 * 00| Mode |
163 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
164 * 04| |
165 * 08| KeyID (80 octets) |
166 * 12| |
167 * 16| |
168 * ...
169 *
170 * 80| |
171 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
172 * 84| |
173 * 88| Token (64 octets) |
174 * 92| |
175 * 96| |
176 * ...
177 * 144| |
178 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179 * 148| |
180 * 152| Client-IV (16 octets) |
181 * 156| |
182 * 160| |
183 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
184 *
185 */
186 OWPErrSeverity
_OWPWriteSetupResponse(OWPControl cntrl,int * retn_on_intr,uint8_t * token)187 _OWPWriteSetupResponse(
188 OWPControl cntrl,
189 int *retn_on_intr,
190 uint8_t *token /* [64] */
191 )
192 {
193 char *buf = (char *)cntrl->msg;
194
195 if(!_OWPStateIsSetup(cntrl)){
196 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
197 "_OWPWriteSetupResponse: called in wrong state.");
198 return OWPErrFATAL;
199 }
200
201 memset(&buf[0],0,164);
202
203 *(uint32_t *)&buf[0] = htonl(cntrl->mode);
204 if(cntrl->mode & OWP_MODE_DOCIPHER){
205 memcpy(&buf[4],cntrl->userid,80);
206 memcpy(&buf[84],token,64);
207 memcpy(&buf[148],cntrl->writeIV,16);
208 }
209
210 if(I2Writeni(cntrl->sockfd,buf,164,retn_on_intr) != 164)
211 return OWPErrFATAL;
212
213 return OWPErrOK;
214 }
215
216 OWPErrSeverity
_OWPReadSetupResponse(OWPControl cntrl,int * retn_on_intr,uint32_t * mode,uint8_t * token,uint8_t * clientIV)217 _OWPReadSetupResponse(
218 OWPControl cntrl,
219 int *retn_on_intr,
220 uint32_t *mode,
221 uint8_t *token, /* [64] - return */
222 uint8_t *clientIV /* [16] - return */
223 )
224 {
225 ssize_t len;
226 char *buf = (char *)cntrl->msg;
227
228 if(!_OWPStateIsSetup(cntrl)){
229 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
230 "_OWPReadClientGreeting: called in wrong state.");
231 return OWPErrFATAL;
232 }
233
234 if((len = I2Readni(cntrl->sockfd,buf,164,retn_on_intr)) != 164){
235 if((len < 0) && *retn_on_intr && (errno == EINTR)){
236 return OWPErrFATAL;
237 }
238 /*
239 * if len == 0 - this is just a socket close, no error
240 * should be printed.
241 */
242 if(len != 0){
243 OWPError(cntrl->ctx,OWPErrFATAL,errno,"I2Readni(): %M");
244 }
245 return OWPErrFATAL;
246 }
247
248 *mode = ntohl(*(uint32_t *)&buf[0]);
249 memcpy(cntrl->userid_buffer,&buf[4],80);
250 memcpy(token,&buf[84],64);
251 memcpy(clientIV,&buf[148],16);
252
253 return OWPErrOK;
254 }
255
256 static OWPAcceptType
GetAcceptType(OWPControl cntrl,uint8_t val)257 GetAcceptType(
258 OWPControl cntrl,
259 uint8_t val
260 )
261 {
262 switch(val){
263 case OWP_CNTRL_ACCEPT:
264 return OWP_CNTRL_ACCEPT;
265 case OWP_CNTRL_REJECT:
266 return OWP_CNTRL_REJECT;
267 case OWP_CNTRL_FAILURE:
268 return OWP_CNTRL_FAILURE;
269 case OWP_CNTRL_UNSUPPORTED:
270 return OWP_CNTRL_UNSUPPORTED;
271 case OWP_CNTRL_UNAVAILABLE_PERM:
272 return OWP_CNTRL_UNAVAILABLE_PERM;
273 case OWP_CNTRL_UNAVAILABLE_TEMP:
274 return OWP_CNTRL_UNAVAILABLE_TEMP;
275 default:
276 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
277 "GetAcceptType:Invalid val %u",val);
278 return OWP_CNTRL_INVALID;
279 }
280 }
281
282 /*
283 * ServerStart message format:
284 *
285 * size: 48 octets
286 *
287 * 0 1 2 3
288 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
289 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
290 * 00| |
291 * 04| MBZ (15 octets) |
292 * 08| |
293 * + +-+-+-+-+-+-+-+-+
294 * 12| | Accept |
295 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
296 * 16| |
297 * 20| Server-IV (16 octets) |
298 * 24| |
299 * 28| |
300 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
301 * 32| Uptime (Timestamp) |
302 * 36| |
303 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
304 * 40| MBZ (8 octets) |
305 * 44| |
306 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
307 *
308 */
309 OWPErrSeverity
_OWPWriteServerStart(OWPControl cntrl,int * retn_on_intr,OWPAcceptType code,OWPNum64 uptime)310 _OWPWriteServerStart(
311 OWPControl cntrl,
312 int *retn_on_intr,
313 OWPAcceptType code,
314 OWPNum64 uptime
315 )
316 {
317 ssize_t len;
318 OWPTimeStamp tstamp;
319 char *buf = (char *)cntrl->msg;
320 int ival=0;
321 int *intr=&ival;
322
323 if(!_OWPStateIsSetup(cntrl)){
324 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
325 "_OWPWriteServerOK:called in wrong state.");
326 return OWPErrFATAL;
327 }
328
329 if(retn_on_intr){
330 intr = retn_on_intr;
331 }
332
333 /*
334 * Write first two blocks of message - not encrypted
335 */
336 memset(&buf[0],0,15);
337 *(uint8_t *)&buf[15] = code & 0xff;
338 memcpy(&buf[16],cntrl->writeIV,16);
339 if((len = I2Writeni(cntrl->sockfd,buf,32,intr)) != 32){
340 if((len < 0) && *intr && (errno == EINTR)){
341 return OWPErrFATAL;
342 }
343 return OWPErrFATAL;
344 }
345
346 if(code == OWP_CNTRL_ACCEPT){
347 /*
348 * Uptime should be encrypted if encr/auth mode so use Block
349 * func.
350 */
351 tstamp.owptime = uptime;
352 _OWPEncodeTimeStamp((uint8_t *)&buf[0],&tstamp);
353 memset(&buf[8],0,8);
354
355 cntrl->state = _OWPStateRequest;
356 }
357 else{
358 /* encryption not valid - reset to clear mode and reject */
359 cntrl->mode = OWP_MODE_OPEN;
360 memset(&buf[0],0,16);
361 cntrl->state = _OWPStateInvalid;
362 }
363
364 /*
365 * Add this block to HMAC, and then send it.
366 * No HMAC digest field in this message - so this block gets
367 * include as part of the text for the next digest sent in the
368 * 'next' message.
369 */
370 _OWPSendHMACAdd(cntrl,buf,1);
371 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,intr) != 1){
372 if((len < 0) && *intr && (errno == EINTR)){
373 return OWPErrFATAL;
374 }
375 return OWPErrFATAL;
376 }
377
378 return OWPErrOK;
379 }
380
381 OWPErrSeverity
_OWPReadServerStart(OWPControl cntrl,int * retn_on_intr,OWPAcceptType * acceptval,OWPNum64 * uptime)382 _OWPReadServerStart(
383 OWPControl cntrl,
384 int *retn_on_intr,
385 OWPAcceptType *acceptval, /* ret */
386 OWPNum64 *uptime /* ret */
387 )
388 {
389 char *buf = (char *)cntrl->msg;
390 OWPTimeStamp tstamp;
391
392 if(!_OWPStateIsSetup(cntrl)){
393 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
394 "_OWPReadServerStart: called in wrong state.");
395 return OWPErrFATAL;
396 }
397
398 /*
399 * First read unencrypted blocks
400 */
401 if(I2Readni(cntrl->sockfd,buf,32,retn_on_intr) != 32){
402 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
403 "Read failed:(%s)",strerror(errno));
404 cntrl->state = _OWPStateInvalid;
405 return OWPErrFATAL;
406 }
407
408 *acceptval = GetAcceptType(cntrl,buf[15]);
409 if(*acceptval == OWP_CNTRL_INVALID){
410 cntrl->state = _OWPStateInvalid;
411 return OWPErrFATAL;
412 }
413
414 memcpy(cntrl->readIV,&buf[16],16);
415
416 /*
417 * If the session is not accepted, there is no key available
418 * for ReceiveBlocksIntr to decode, so turn off encryption here.
419 */
420 if(*acceptval != OWP_CNTRL_ACCEPT){
421 cntrl->mode = OWP_MODE_OPEN;
422 }
423
424 /*
425 * Now read encrypted blocks (In encrypted modes, everything after
426 * IV is encrypted.
427 * Add block to HMAC
428 */
429 if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
430 OWPError(cntrl->ctx,OWPErrFATAL,errno,
431 "_OWPReadServerStart: Unable to read from socket.");
432 cntrl->state = _OWPStateInvalid;
433 return OWPErrFATAL;
434 }
435 _OWPRecvHMACAdd(cntrl,buf,1);
436
437 _OWPDecodeTimeStamp(&tstamp,(uint8_t *)&buf[0]);
438 *uptime = tstamp.owptime;
439
440 /*
441 * Now in normal request state
442 */
443 cntrl->state = _OWPStateRequest;
444
445 return OWPErrOK;
446 }
447
448 /*
449 * This function is called on the server side to read the first block
450 * of client requests. The remaining read request messages MUST be called
451 * next!.
452 * It is also called by the client side from OWPStopSessionsWait and
453 * OWPStopSessions.
454 *
455 * This function does NOT add any data to the HMAC.
456 */
457 OWPRequestType
OWPReadRequestType(OWPControl cntrl,int * retn_on_intr)458 OWPReadRequestType(
459 OWPControl cntrl,
460 int *retn_on_intr
461 )
462 {
463 uint8_t msgtype;
464 int n;
465 int ival=0;
466 int *intr = &ival;
467
468 if(retn_on_intr){
469 intr = retn_on_intr;
470 }
471
472 if(!_OWPStateIsRequest(cntrl) || _OWPStateIsReading(cntrl)){
473 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
474 "OWPReadRequestType:called in wrong state.");
475 return OWPReqInvalid;
476 }
477
478 /* Read one block so we can peek at the message type */
479 n = _OWPReceiveBlocksIntr(cntrl,(uint8_t *)cntrl->msg,1,intr);
480 if(n != 1){
481 cntrl->state = _OWPStateInvalid;
482 if((n < 0) && *intr && (errno == EINTR)){
483 return OWPReqSockIntr;
484 }
485 return OWPReqSockClose;
486 }
487
488 msgtype = *(char *)cntrl->msg;
489
490 /*
491 * StopSessions(3) message is only allowed during active tests,
492 * and it is the only message allowed during active tests.
493 */
494 if((_OWPStateIs(_OWPStateTest,cntrl) && (msgtype != 3)) ||
495 (!_OWPStateIs(_OWPStateTest,cntrl) && (msgtype == 3))){
496 cntrl->state = _OWPStateInvalid;
497 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
498 "OWPReadRequestType: Invalid request.");
499 return OWPReqInvalid;
500 }
501
502 switch(msgtype){
503 /*
504 * TestRequest
505 */
506 case 1:
507 cntrl->state |= _OWPStateTestRequest;
508 break;
509 case 2:
510 cntrl->state |= _OWPStateStartSessions;
511 break;
512 case 3:
513 cntrl->state |= _OWPStateStopSessions;
514 break;
515 case 4:
516 cntrl->state |= _OWPStateFetchSession;
517 break;
518 default:
519 cntrl->state = _OWPStateInvalid;
520 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
521 "OWPReadRequestType: Unknown msg:%d",msgtype);
522 return OWPReqInvalid;
523 }
524
525 return (OWPRequestType)msgtype;
526 }
527
528 /*
529 * TestRequestPreamble message format:
530 *
531 * size:112 octets
532 *
533 * 0 1 2 3
534 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
535 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
536 * 00| 1 | MBZ | IPVN | Conf-Sender | Conf-Receiver |
537 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
538 * 04| Number of Schedule Slots |
539 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
540 * 08| Number of Packets |
541 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
542 * 12| Sender Port | Receiver Port |
543 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
544 * 16| Sender Address |
545 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
546 * 20| Sender Address (cont.) or MBZ (12 octets) |
547 * 24| |
548 * 28| |
549 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
550 * 32| Receiver Address |
551 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
552 * 36| Receiver Address (cont.) or MBZ (12 octets) |
553 * 40| |
554 * 44| |
555 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
556 * 48| |
557 * 52| SID (16 octets) |
558 * 56| |
559 * 60| |
560 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
561 * 64| Padding Length |
562 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
563 * 68| Start Time |
564 * 72| |
565 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
566 * 76| Timeout (8 octets) |
567 * 80| |
568 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
569 * 84| Type-P Descriptor |
570 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
571 * 88| MBZ (8 octets) |
572 * 92| |
573 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
574 * 96| |
575 * 100| HMAC (16 octets) |
576 * 104| |
577 * 108| |
578 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
579 */
580 int
_OWPEncodeTestRequestPreamble(OWPContext ctx,uint32_t * msg,uint32_t * len_ret,struct sockaddr * sender,struct sockaddr * receiver,OWPBoolean server_conf_sender,OWPBoolean server_conf_receiver,OWPSID sid,OWPTestSpec * tspec)581 _OWPEncodeTestRequestPreamble(
582 OWPContext ctx,
583 uint32_t *msg,
584 uint32_t *len_ret,
585 struct sockaddr *sender,
586 struct sockaddr *receiver,
587 OWPBoolean server_conf_sender,
588 OWPBoolean server_conf_receiver,
589 OWPSID sid,
590 OWPTestSpec *tspec
591 )
592 {
593 char *buf = (char*)msg;
594 char version;
595 OWPTimeStamp tstamp;
596
597 if(*len_ret < 112){
598 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
599 "_OWPEncodeTestRequestPreamble:Buffer too small");
600 *len_ret = 0;
601 return OWPErrFATAL;
602 }
603 *len_ret = 0;
604
605 /*
606 * Check validity of input variables.
607 */
608
609 /* valid "conf" setup? */
610 if(!server_conf_sender && !server_conf_receiver){
611 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
612 "_OWPEncodeTestRequestPreamble:Request for empty config?");
613 return OWPErrFATAL;
614 }
615
616 /* consistant addresses? */
617 if(sender->sa_family != receiver->sa_family){
618 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
619 "Address Family mismatch");
620 return OWPErrFATAL;
621 }
622
623 /*
624 * Addresses are consistant. Can we deal with what we
625 * have been given? (We only support AF_INET and AF_INET6.)
626 */
627 switch (sender->sa_family){
628 case AF_INET:
629 version = 4;
630 break;
631 #ifdef AF_INET6
632 case AF_INET6:
633 version = 6;
634 break;
635 #endif
636 default:
637 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
638 "Invalid IP Address Family");
639 return 1;
640 }
641
642 /*
643 * Do we have "valid" schedule variables?
644 */
645 if((tspec->npackets < 1) || (tspec->nslots < 1) || !tspec->slots){
646 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
647 "Invalid test distribution parameters");
648 return OWPErrFATAL;
649 }
650
651 /*
652 * set simple values
653 */
654 buf[0] = 1; /* Request-Session message # */
655 buf[1] = version & 0xF;
656 buf[2] = (server_conf_sender)?1:0;
657 buf[3] = (server_conf_receiver)?1:0;
658
659 /*
660 * slots and npackets... convert to network byte order.
661 */
662 *(uint32_t*)&buf[4] = htonl(tspec->nslots);
663 *(uint32_t*)&buf[8] = htonl(tspec->npackets);
664
665 /*
666 * Now set addr values. (sockaddr vars should already have
667 * values in network byte order.)
668 */
669 switch(version){
670 struct sockaddr_in *saddr4;
671 #ifdef AF_INET6
672 struct sockaddr_in6 *saddr6;
673 case 6:
674 /* sender address and port */
675 saddr6 = (struct sockaddr_in6*)sender;
676 memcpy(&buf[16],saddr6->sin6_addr.s6_addr,16);
677 *(uint16_t*)&buf[12] = saddr6->sin6_port;
678
679 /* receiver address and port */
680 saddr6 = (struct sockaddr_in6*)receiver;
681 memcpy(&buf[32],saddr6->sin6_addr.s6_addr,16);
682 *(uint16_t*)&buf[14] = saddr6->sin6_port;
683
684 break;
685 #endif
686 case 4:
687 /* sender address and port */
688 saddr4 = (struct sockaddr_in*)sender;
689 *(uint32_t*)&buf[16] = saddr4->sin_addr.s_addr;
690 *(uint16_t*)&buf[12] = saddr4->sin_port;
691
692 /* receiver address and port */
693 saddr4 = (struct sockaddr_in*)receiver;
694 *(uint32_t*)&buf[32] = saddr4->sin_addr.s_addr;
695 *(uint16_t*)&buf[14] = saddr4->sin_port;
696
697 break;
698 default:
699 /*
700 * This can't happen, but default keeps compiler
701 * warnings away.
702 */
703 abort();
704 break;
705 }
706
707 if(sid)
708 memcpy(&buf[48],sid,16);
709
710 *(uint32_t*)&buf[64] = htonl(tspec->packet_size_padding);
711
712 /*
713 * timestamps...
714 */
715 tstamp.owptime = tspec->start_time;
716 _OWPEncodeTimeStamp((uint8_t *)&buf[68],&tstamp);
717 tstamp.owptime = tspec->loss_timeout;
718 _OWPEncodeTimeStamp((uint8_t *)&buf[76],&tstamp);
719
720 *(uint32_t*)&buf[84] = htonl(tspec->typeP);
721
722 /*
723 * Set MBZ and HMAC area to 0
724 */
725 memset(&buf[88],0,24);
726
727 *len_ret = 112;
728
729 return 0;
730 }
731 OWPErrSeverity
_OWPDecodeTestRequestPreamble(OWPContext ctx,OWPBoolean request,uint32_t * msg,uint32_t msg_len,struct sockaddr * sender,struct sockaddr * receiver,socklen_t * socklen,uint8_t * ipvn,OWPBoolean * server_conf_sender,OWPBoolean * server_conf_receiver,OWPSID sid,OWPTestSpec * tspec)732 _OWPDecodeTestRequestPreamble(
733 OWPContext ctx,
734 OWPBoolean request,
735 uint32_t *msg,
736 uint32_t msg_len,
737 struct sockaddr *sender,
738 struct sockaddr *receiver,
739 socklen_t *socklen,
740 uint8_t *ipvn,
741 OWPBoolean *server_conf_sender,
742 OWPBoolean *server_conf_receiver,
743 OWPSID sid,
744 OWPTestSpec *tspec
745 )
746 {
747 char *buf = (char *)msg;
748 OWPTimeStamp tstamp;
749
750 if(msg_len != 112){
751 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
752 "_OWPDecodeTestRequestPreamble: Invalid message size");
753 return OWPErrFATAL;
754 }
755
756 *ipvn = buf[1] & 0xF;
757 tspec->nslots = ntohl(*(uint32_t*)&buf[4]);
758 tspec->npackets = ntohl(*(uint32_t*)&buf[8]);
759
760 switch(buf[2]){
761 case 0:
762 *server_conf_sender = False;
763 break;
764 case 1:
765 default:
766 *server_conf_sender = True;
767 break;
768 }
769 switch(buf[3]){
770 case 0:
771 *server_conf_receiver = False;
772 break;
773 case 1:
774 default:
775 *server_conf_receiver = True;
776 break;
777 }
778
779 if(!*server_conf_sender && !*server_conf_receiver){
780 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
781 "_OWPDecodeTestRequestPreamble: Invalid null request");
782 return OWPErrWARNING;
783 }
784
785 switch(*ipvn){
786 struct sockaddr_in *saddr4;
787 #ifdef AF_INET6
788 struct sockaddr_in6 *saddr6;
789 case 6:
790 if(*socklen < sizeof(struct sockaddr_in6)){
791 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
792 "_OWPDecodeTestRequestPreamble: socklen not large enough (%d < %d)",
793 *socklen,sizeof(struct sockaddr_in6));
794 *socklen = 0;
795 return OWPErrFATAL;
796 }
797 *socklen = sizeof(struct sockaddr_in6);
798
799 /* sender address and port */
800 saddr6 = (struct sockaddr_in6*)sender;
801 saddr6->sin6_family = AF_INET6;
802 memcpy(saddr6->sin6_addr.s6_addr,&buf[16],16);
803 if(request && *server_conf_sender)
804 saddr6->sin6_port = 0;
805 else
806 saddr6->sin6_port = *(uint16_t*)&buf[12];
807
808 /* receiver address and port */
809 saddr6 = (struct sockaddr_in6*)receiver;
810 saddr6->sin6_family = AF_INET6;
811 memcpy(saddr6->sin6_addr.s6_addr,&buf[32],16);
812 if(request && *server_conf_receiver)
813 saddr6->sin6_port = 0;
814 else
815 saddr6->sin6_port = *(uint16_t*)&buf[14];
816
817 break;
818 #endif
819 case 4:
820 if(*socklen < sizeof(struct sockaddr_in)){
821 *socklen = 0;
822 OWPError(ctx,OWPErrFATAL,OWPErrINVALID,
823 "_OWPDecodeTestRequestPreamble: socklen not large enough (%d < %d)",
824 *socklen,sizeof(struct sockaddr_in));
825 return OWPErrFATAL;
826 }
827 *socklen = sizeof(struct sockaddr_in);
828
829 /* sender address and port */
830 saddr4 = (struct sockaddr_in*)sender;
831 saddr4->sin_family = AF_INET;
832 saddr4->sin_addr.s_addr = *(uint32_t*)&buf[16];
833 if(request && *server_conf_sender)
834 saddr4->sin_port = 0;
835 else
836 saddr4->sin_port = *(uint16_t*)&buf[12];
837
838 /* receiver address and port */
839 saddr4 = (struct sockaddr_in*)receiver;
840 saddr4->sin_family = AF_INET;
841 saddr4->sin_addr.s_addr = *(uint32_t*)&buf[32];
842 if(request && *server_conf_receiver)
843 saddr4->sin_port = 0;
844 else
845 saddr4->sin_port = *(uint16_t*)&buf[14];
846
847 break;
848 default:
849 OWPError(ctx,OWPErrWARNING,OWPErrINVALID,
850 "_OWPDecodeTestRequestPreamble: Unsupported IP version (%d)",
851 *ipvn);
852 return OWPErrWARNING;
853 }
854
855 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
856 sender->sa_len = receiver->sa_len = *socklen;
857 #endif
858
859 memcpy(sid,&buf[48],16);
860
861 tspec->packet_size_padding = ntohl(*(uint32_t*)&buf[64]);
862
863 _OWPDecodeTimeStamp(&tstamp,(uint8_t *)&buf[68]);
864 tspec->start_time = tstamp.owptime;
865 _OWPDecodeTimeStamp(&tstamp,(uint8_t *)&buf[76]);
866 tspec->loss_timeout = tstamp.owptime;
867
868 /*
869 * Rely on implementation in endpoint.c to verify bits.
870 * (This allows typeP to be expanded in the future for
871 * implementations that understand it.)
872 */
873 tspec->typeP = ntohl(*(uint32_t*)&buf[84]);
874
875 return OWPErrOK;
876 }
877
878
879 /*
880 * Encode/Decode Slot
881 *
882 * 0 1 2 3
883 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
884 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
885 * 00| Slot Type | |
886 * +-+-+-+-+-+-+-+-+ MBZ +
887 * 04| |
888 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
889 * 08| Slot Parameter (Timestamp) |
890 * 12| |
891 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
892 */
893 /*
894 * Function: _OWPEncodeSlot
895 *
896 * Description:
897 * This function is used to encode a slot record in a single block
898 * in the format needed to send a slot over the wire.
899 *
900 * In Args:
901 *
902 * Out Args:
903 *
904 * Scope:
905 * Returns:
906 * Side Effect:
907 */
908 OWPErrSeverity
_OWPEncodeSlot(uint32_t msg[4],OWPSlot * slot)909 _OWPEncodeSlot(
910 uint32_t msg[4], /* 1 block 32bit aligned */
911 OWPSlot *slot
912 )
913 {
914 char *buf = (char *)msg;
915 OWPTimeStamp tstamp;
916
917 /*
918 * Initialize block to zero
919 */
920 memset(buf,0,16);
921
922 switch(slot->slot_type){
923 case OWPSlotRandExpType:
924 buf[0] = 0;
925 tstamp.owptime = slot->rand_exp.mean;
926 break;
927 case OWPSlotLiteralType:
928 buf[0] = 1;
929 tstamp.owptime = slot->literal.offset;
930 break;
931 default:
932 return OWPErrFATAL;
933 }
934 _OWPEncodeTimeStamp((uint8_t *)&buf[8],&tstamp);
935
936 return OWPErrOK;
937 }
938 /*
939 * Function: _OWPDecodeSlot
940 *
941 * Description:
942 * This function is used to read a slot in protocol format into a
943 * slot structure record.
944 *
945 * In Args:
946 *
947 * Out Args:
948 *
949 * Scope:
950 * Returns:
951 * Side Effect:
952 */
953 OWPErrSeverity
_OWPDecodeSlot(OWPSlot * slot,uint32_t msg[4])954 _OWPDecodeSlot(
955 OWPSlot *slot,
956 uint32_t msg[4] /* 1 block 32bit aligned */
957 )
958 {
959 char *buf = (char *)msg;
960 OWPTimeStamp tstamp;
961
962 _OWPDecodeTimeStamp(&tstamp,(uint8_t *)&buf[8]);
963 switch(buf[0]){
964 case 0:
965 slot->slot_type = OWPSlotRandExpType;
966 slot->rand_exp.mean = tstamp.owptime;
967 break;
968 case 1:
969 slot->slot_type = OWPSlotLiteralType;
970 slot->literal.offset = tstamp.owptime;
971 break;
972 default:
973 return OWPErrFATAL;
974 }
975
976 return OWPErrOK;
977 }
978
979 OWPErrSeverity
_OWPWriteTestRequest(OWPControl cntrl,int * retn_on_intr,struct sockaddr * sender,struct sockaddr * receiver,OWPBoolean server_conf_sender,OWPBoolean server_conf_receiver,OWPSID sid,OWPTestSpec * test_spec)980 _OWPWriteTestRequest(
981 OWPControl cntrl,
982 int *retn_on_intr,
983 struct sockaddr *sender,
984 struct sockaddr *receiver,
985 OWPBoolean server_conf_sender,
986 OWPBoolean server_conf_receiver,
987 OWPSID sid,
988 OWPTestSpec *test_spec
989 )
990 {
991 char *buf = (char *)cntrl->msg;
992 uint32_t buf_len = sizeof(cntrl->msg);
993 uint32_t i;
994
995 /*
996 * Ensure cntrl is in correct state.
997 */
998 if(!_OWPStateIsRequest(cntrl) || _OWPStateIsPending(cntrl)){
999 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1000 "_OWPWriteTestRequest:called in wrong state.");
1001 return OWPErrFATAL;
1002 }
1003
1004 /*
1005 * Encode test request variables that were passed in into
1006 * the "buf" in the format required by V5 of owamp spec section 4.3.
1007 */
1008 if((_OWPEncodeTestRequestPreamble(cntrl->ctx,cntrl->msg,&buf_len,
1009 sender,receiver,server_conf_sender,
1010 server_conf_receiver,sid,test_spec) != 0) ||
1011 (buf_len != 112)){
1012 return OWPErrFATAL;
1013 }
1014
1015 /* Add everything up to the HMAC block into the HMAC */
1016 _OWPSendHMACAdd(cntrl,buf,6);
1017 /* Fetch the digest out into the final HMAC block */
1018 _OWPSendHMACDigestClear(cntrl,&buf[96]);
1019
1020 /*
1021 * Now - send the request! 112 octets == 7 blocks.
1022 */
1023 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,7,retn_on_intr) != 7){
1024 cntrl->state = _OWPStateInvalid;
1025 return OWPErrFATAL;
1026 }
1027
1028 /*
1029 * Send slots
1030 */
1031 for(i=0;i<test_spec->nslots;i++){
1032 if(_OWPEncodeSlot(cntrl->msg,&test_spec->slots[i]) != OWPErrOK){
1033 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1034 "_OWPWriteTestRequest: Invalid slot record");
1035 cntrl->state = _OWPStateInvalid;
1036 return OWPErrFATAL;
1037 }
1038 _OWPSendHMACAdd(cntrl,buf,1);
1039 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1040 cntrl->state = _OWPStateInvalid;
1041 return OWPErrFATAL;
1042 }
1043 }
1044
1045 /*
1046 * Send HMAC digest block
1047 */
1048 _OWPSendHMACDigestClear(cntrl,buf);
1049 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1050 cntrl->state = _OWPStateInvalid;
1051 return OWPErrFATAL;
1052 }
1053
1054 cntrl->state |= _OWPStateAcceptSession;
1055
1056 return OWPErrOK;
1057 }
1058
1059
1060 /*
1061 * Function: _OWPReadTestRequestSlots
1062 *
1063 * Description:
1064 * This function reads nslot slot descriptions off of the socket.
1065 * If slots is non-null, each slot description is decoded and
1066 * placed in the "slots" array. It is assumed to be of at least
1067 * length "nslots". If "slots" is NULL, then nslots are read
1068 * off the socket and discarded.
1069 *
1070 * The _OWPDecodeSlot function is called to decode each individual
1071 * slot. Then the last block of integrity zero padding is checked
1072 * to complete the reading of the TestRequest.
1073 *
1074 * The formats are as follows:
1075 *
1076 * size: Each Slot is 16 octets. All slots are followed by 16 octets
1077 * of Integrity Zero Padding.
1078 *
1079 * 0 1 2 3
1080 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1081 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1082 * 00| Slot Type | |
1083 * +-+-+-+-+-+-+-+-+ MBZ +
1084 * 04| |
1085 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1086 * 08| Slot Parameter (Timestamp) |
1087 * 12| |
1088 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1089 * ...
1090 * ...
1091 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1092 * 00| |
1093 * 04| Integrity Zero Padding (16 octets) |
1094 * 08| |
1095 * 12| |
1096 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1097 *
1098 * In Args:
1099 *
1100 * Out Args:
1101 *
1102 * Scope:
1103 * Returns:
1104 * Side Effect:
1105 */
1106 static OWPErrSeverity
_OWPReadTestRequestSlots(OWPControl cntrl,int * intr,uint32_t nslots,OWPSlot * slots)1107 _OWPReadTestRequestSlots(
1108 OWPControl cntrl,
1109 int *intr,
1110 uint32_t nslots,
1111 OWPSlot *slots
1112 )
1113 {
1114 char *buf = (char *)cntrl->msg;
1115 uint32_t i;
1116 int len;
1117
1118 if(!_OWPStateIs(_OWPStateTestRequestSlots,cntrl)){
1119 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1120 "_OWPReadTestRequestSlots called in wrong state.");
1121 return OWPErrFATAL;
1122 }
1123
1124 for(i=0;i<nslots;i++){
1125
1126 /*
1127 * Read slot into buffer.
1128 */
1129 if((len =_OWPReceiveBlocksIntr(cntrl,(uint8_t *)&buf[0],1,intr)) != 1){
1130 cntrl->state = _OWPStateInvalid;
1131 if((len < 0) && *intr && (errno==EINTR)){
1132 return OWPErrFATAL;
1133 }
1134 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1135 "_OWPReadTestRequestSlots: Read Error: %M");
1136 return OWPErrFATAL;
1137 }
1138 _OWPRecvHMACAdd(cntrl,buf,1);
1139
1140 /*
1141 * slots will be null if we are just reading the slots
1142 * to get the control connection in the correct state
1143 * to respond with a denied Accept message.
1144 */
1145 if(!slots){
1146 continue;
1147 }
1148
1149 /*
1150 * Decode slot from buffer into slot record.
1151 */
1152 if(_OWPDecodeSlot(&slots[i],cntrl->msg) != OWPErrOK){
1153 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1154 "_OWPReadTestRequestSlots: Invalid Slot");
1155 cntrl->state = _OWPStateInvalid;
1156 return OWPErrFATAL;
1157 }
1158
1159 }
1160
1161 /*
1162 * Now read slot HMAC digest
1163 */
1164 if((len=_OWPReceiveBlocksIntr(cntrl,(uint8_t *)&buf[0],1,intr)) != 1){
1165 cntrl->state = _OWPStateInvalid;
1166 if((len<0) && *intr && (errno == EINTR)){
1167 return OWPErrFATAL;
1168 }
1169 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1170 "_OWPReadTestRequestSlots: Read Error: %M");
1171 return OWPErrFATAL;
1172 }
1173
1174 /*
1175 * Now check the integrity.
1176 */
1177 if(!_OWPRecvHMACCheckClear(cntrl,buf)){
1178 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1179 "_OWPReadTestRequestSlots: Invalid HMAC");
1180 cntrl->state = _OWPStateInvalid;
1181 return OWPErrFATAL;
1182 }
1183
1184 /*
1185 * TestRequestSlots are read, now ready to send AcceptSession message.
1186 */
1187 cntrl->state &= ~_OWPStateTestRequestSlots;
1188
1189 return OWPErrOK;
1190 }
1191
1192 /*
1193 * Function: _OWPReadTestRequest
1194 *
1195 * Description:
1196 * This function reads a test request off the wire and encodes
1197 * the information in a TestSession record.
1198 *
1199 * If it is called in a server context, the acceptval pointer will
1200 * be non-null and will be set. (i.e. if there is a memory allocation
1201 * error, it will be set to OWP_CNTRL_FAILURE. If there is invalid
1202 * data in the TestRequest it will be set to OWP_CNTRL_REJECT.)
1203 *
1204 * In Args:
1205 *
1206 * Out Args:
1207 *
1208 * Scope:
1209 * Returns:
1210 * Side Effect:
1211 */
1212 OWPErrSeverity
_OWPReadTestRequest(OWPControl cntrl,int * retn_on_intr,OWPTestSession * test_session,OWPAcceptType * accept_ret)1213 _OWPReadTestRequest(
1214 OWPControl cntrl,
1215 int *retn_on_intr,
1216 OWPTestSession *test_session,
1217 OWPAcceptType *accept_ret
1218 )
1219 {
1220 char *buf = (char *)cntrl->msg;
1221 OWPErrSeverity err_ret=OWPErrOK;
1222 struct sockaddr_storage sendaddr_rec;
1223 struct sockaddr_storage recvaddr_rec;
1224 socklen_t addrlen = sizeof(sendaddr_rec);
1225 I2Addr SendAddr=NULL;
1226 I2Addr RecvAddr=NULL;
1227 uint8_t ipvn;
1228 OWPBoolean conf_sender;
1229 OWPBoolean conf_receiver;
1230 OWPSID sid;
1231 OWPTestSpec tspec;
1232 int rc;
1233 OWPTestSession tsession;
1234 OWPAcceptType accept_mem;
1235 OWPAcceptType *accept_ptr = &accept_mem;
1236 int ival=0;
1237 int *intr=&ival;
1238
1239 *test_session = NULL;
1240 memset(&sendaddr_rec,0,addrlen);
1241 memset(&recvaddr_rec,0,addrlen);
1242 memset(&tspec,0,sizeof(tspec));
1243 memset(sid,0,sizeof(sid));
1244
1245 if(!_OWPStateIs(_OWPStateTestRequest,cntrl)){
1246 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1247 "_OWPReadTestRequest: called in wrong state.");
1248 return OWPErrFATAL;
1249 }
1250
1251 /*
1252 * Setup an OWPAcceptType return in the event this function is
1253 * called in a "server" context.
1254 */
1255 if(accept_ret)
1256 accept_ptr = accept_ret;
1257 *accept_ptr = OWP_CNTRL_ACCEPT;
1258
1259 if(retn_on_intr){
1260 intr = retn_on_intr;
1261 }
1262
1263 /*
1264 * If this was called from the client side, we need to read
1265 * one block of data into the cntrl buffer. (Server side already
1266 * did this to determine the message type - client is doing this
1267 * as part of a fetch session.
1268 */
1269 if(!accept_ret && (_OWPReceiveBlocksIntr(cntrl,(uint8_t *)&buf[0],1,intr) != 1)){
1270 OWPError(cntrl->ctx,OWPErrFATAL,errno,
1271 "_OWPReadTestRequest: Unable to read from socket.");
1272 cntrl->state = _OWPStateInvalid;
1273 *accept_ptr = OWP_CNTRL_INVALID;
1274 return OWPErrFATAL;
1275 }
1276
1277 /*
1278 * Already read the first block - read the rest for this message
1279 * type.
1280 */
1281 if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)&buf[16],_OWP_TEST_REQUEST_BLK_LEN-1,
1282 intr) != (_OWP_TEST_REQUEST_BLK_LEN-1)){
1283 OWPError(cntrl->ctx,OWPErrFATAL,errno,
1284 "_OWPReadTestRequest: Unable to read from socket.");
1285 cntrl->state = _OWPStateInvalid;
1286 *accept_ptr = OWP_CNTRL_INVALID;
1287 return OWPErrFATAL;
1288 }
1289
1290 /*
1291 * Add data to HMAC and verify digest before decoding message
1292 */
1293 _OWPRecvHMACAdd(cntrl,buf,6);
1294 if(!_OWPRecvHMACCheckClear(cntrl,&buf[96])){
1295 OWPError(cntrl->ctx,OWPErrFATAL,EACCES,
1296 "_OWPReadTestRequest: Invalid HMAC");
1297 cntrl->state = _OWPStateInvalid;
1298 *accept_ptr = OWP_CNTRL_INVALID;
1299 return OWPErrFATAL;
1300 }
1301
1302 /*
1303 * Now - fill in the Addr records, ipvn, server_conf varaibles,
1304 * sid and "tspec" with the values in the msg buffer.
1305 */
1306 if( (err_ret = _OWPDecodeTestRequestPreamble(cntrl->ctx,
1307 (accept_ret!=NULL),cntrl->msg,
1308 _OWP_TEST_REQUEST_BLK_LEN*_OWP_RIJNDAEL_BLOCK_SIZE,
1309 (struct sockaddr*)&sendaddr_rec,
1310 (struct sockaddr*)&recvaddr_rec,&addrlen,&ipvn,
1311 &conf_sender,&conf_receiver,sid,&tspec)) != OWPErrOK){
1312 /*
1313 * INFO/WARNING indicates a request that we cannot honor.
1314 * FATAL indicates inproper formatting, and probable
1315 * control connection corruption.
1316 */
1317 if(err_ret < OWPErrWARNING){
1318 cntrl->state = _OWPStateInvalid;
1319 *accept_ptr = OWP_CNTRL_INVALID;
1320 return OWPErrFATAL;
1321 }else if(accept_ret){
1322 /*
1323 * only return in server context
1324 */
1325 *accept_ptr = OWP_CNTRL_UNSUPPORTED;
1326 return OWPErrFATAL;
1327 }
1328 }
1329
1330 /*
1331 * TestRequest Preamble is read, now ready to read slots.
1332 */
1333 cntrl->state &= ~_OWPStateTestRequest;
1334 cntrl->state |= _OWPStateTestRequestSlots;
1335
1336 /*
1337 * Prepare the address buffers.
1338 * (Don't bother checking for null return - it will be checked
1339 * by _OWPTestSessionAlloc.)
1340 */
1341 SendAddr = I2AddrBySAddr(OWPContextErrHandle(cntrl->ctx),
1342 (struct sockaddr*)&sendaddr_rec,addrlen,SOCK_DGRAM,IPPROTO_UDP);
1343 RecvAddr = I2AddrBySAddr(OWPContextErrHandle(cntrl->ctx),
1344 (struct sockaddr*)&recvaddr_rec,addrlen,SOCK_DGRAM,IPPROTO_UDP);
1345
1346 /*
1347 * Allocate a record for this test.
1348 */
1349 if( !(tsession = _OWPTestSessionAlloc(cntrl,SendAddr,conf_sender,
1350 RecvAddr,conf_receiver,&tspec))){
1351 err_ret = OWPErrWARNING;
1352 *accept_ptr = OWP_CNTRL_FAILURE;
1353 goto error;
1354 }
1355
1356 /*
1357 * copy sid into tsession - if the sid still needs to be
1358 * generated - it still will be in sapi.c:OWPProcessTestRequest
1359 */
1360 memcpy(tsession->sid,sid,sizeof(sid));
1361
1362 /*
1363 * Allocate memory for slots...
1364 */
1365 if(tsession->test_spec.nslots > _OWPSLOT_BUFSIZE){
1366 /*
1367 * Will check for memory allocation failure after
1368 * reading slots from socket. (We can gracefully
1369 * decline the request even if we can't allocate memory
1370 * to hold the slots this way.)
1371 */
1372 tsession->test_spec.slots =
1373 calloc(tsession->test_spec.nslots,sizeof(OWPSlot));
1374 }else{
1375 tsession->test_spec.slots = tsession->slot_buffer;
1376 }
1377
1378 /*
1379 * Now, read the slots of the control socket.
1380 */
1381 if( (rc = _OWPReadTestRequestSlots(cntrl,intr,
1382 tsession->test_spec.nslots,
1383 tsession->test_spec.slots)) < OWPErrOK){
1384 cntrl->state = _OWPStateInvalid;
1385 err_ret = (OWPErrSeverity)rc;
1386 *accept_ptr = OWP_CNTRL_INVALID;
1387 goto error;
1388 }
1389
1390 /*
1391 * We were unable to save the slots - server should decline the request.
1392 */
1393 if(!tsession->test_spec.slots){
1394 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
1395 "calloc(%d,OWPSlot): %M",
1396 tsession->test_spec.nslots);
1397 *accept_ptr = OWP_CNTRL_FAILURE;
1398 err_ret = OWPErrFATAL;
1399 goto error;
1400 }
1401
1402 /*
1403 * In the server context, we are going to _OWPStateAcceptSession.
1404 * In the client "fetching" context we are ready to read the
1405 * record header and the records.
1406 */
1407 if(accept_ret){
1408 cntrl->state |= _OWPStateAcceptSession;
1409 }else{
1410 cntrl->state |= _OWPStateFetching;
1411 }
1412
1413 *test_session = tsession;
1414
1415 return OWPErrOK;
1416
1417 error:
1418 if(tsession){
1419 _OWPTestSessionFree(tsession,OWP_CNTRL_FAILURE);
1420 }else{
1421 I2AddrFree(SendAddr);
1422 I2AddrFree(RecvAddr);
1423 }
1424
1425 return err_ret;
1426 }
1427
1428 /*
1429 *
1430 * AcceptSession message format:
1431 *
1432 * size: 48 octets
1433 *
1434 * 0 1 2 3
1435 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1436 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1437 * 00| Accept | MBZ | Port |
1438 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1439 * 04| |
1440 * 08| SID (16 octets) |
1441 * 12| |
1442 * 16| |
1443 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1444 * 20| |
1445 * 24| MBZ (12 octets) |
1446 * 28| |
1447 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1448 * 32| |
1449 * 36| HMAC (16 octets) |
1450 * 40| |
1451 * 44| |
1452 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1453 *
1454 */
1455 OWPErrSeverity
_OWPWriteAcceptSession(OWPControl cntrl,int * intr,OWPAcceptType acceptval,uint16_t port,OWPSID sid)1456 _OWPWriteAcceptSession(
1457 OWPControl cntrl,
1458 int *intr,
1459 OWPAcceptType acceptval,
1460 uint16_t port,
1461 OWPSID sid
1462 )
1463 {
1464 char *buf = (char *)cntrl->msg;
1465
1466 if(!_OWPStateIs(_OWPStateAcceptSession,cntrl)){
1467 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1468 "_OWPWriteAcceptSession called in wrong state.");
1469 return OWPErrFATAL;
1470 }
1471
1472 memset(&buf[0],0,_OWP_MAX_MSG_SIZE);
1473 buf[0] = acceptval & 0xff;
1474 *(uint16_t *)&buf[2] = htons(port);
1475 if(sid)
1476 memcpy(&buf[4],sid,16);
1477
1478 /*
1479 * Add this block to HMAC, and then put the digest in the message.
1480 */
1481 _OWPSendHMACAdd(cntrl,buf,2);
1482 _OWPSendHMACDigestClear(cntrl,&buf[32]);
1483
1484 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,3,intr) != 3){
1485 cntrl->state = _OWPStateInvalid;
1486 return OWPErrFATAL;
1487 }
1488
1489 cntrl->state &= ~_OWPStateAcceptSession;
1490
1491 return OWPErrOK;
1492 }
1493
1494 OWPErrSeverity
_OWPReadAcceptSession(OWPControl cntrl,int * retn_on_intr,OWPAcceptType * acceptval,uint16_t * port,OWPSID sid)1495 _OWPReadAcceptSession(
1496 OWPControl cntrl,
1497 int *retn_on_intr,
1498 OWPAcceptType *acceptval,
1499 uint16_t *port,
1500 OWPSID sid
1501 )
1502 {
1503 char *buf = (char *)cntrl->msg;
1504
1505 if(!_OWPStateIs(_OWPStateAcceptSession,cntrl)){
1506 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1507 "_OWPReadAcceptSession called in wrong state.");
1508 return OWPErrFATAL;
1509 }
1510
1511 /*
1512 * Get the servers response.
1513 */
1514 if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,3,retn_on_intr) != 3){
1515 OWPError(cntrl->ctx,OWPErrFATAL,errno,
1516 "_OWPReadAcceptSession:Unable to read from socket.");
1517 cntrl->state = _OWPStateInvalid;
1518 return OWPErrFATAL;
1519 }
1520
1521 /*
1522 * Add blocks to HMAC, then check digest.
1523 */
1524 _OWPRecvHMACAdd(cntrl,buf,2);
1525 if(!_OWPRecvHMACCheckClear(cntrl,&buf[32])){
1526 cntrl->state = _OWPStateInvalid;
1527 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1528 "Invalid HMAC in Accept-Session message");
1529 return OWPErrFATAL;
1530 }
1531
1532 *acceptval = GetAcceptType(cntrl,buf[0]);
1533 if(*acceptval == OWP_CNTRL_INVALID){
1534 cntrl->state = _OWPStateInvalid;
1535 return OWPErrFATAL;
1536 }
1537
1538 if(port)
1539 *port = ntohs(*(uint16_t*)&buf[2]);
1540
1541 if(sid)
1542 memcpy(sid,&buf[4],16);
1543
1544 cntrl->state &= ~_OWPStateAcceptSession;
1545
1546 return OWPErrOK;
1547 }
1548
1549 /*
1550 *
1551 * StartSessions message format:
1552 *
1553 * size: 32 octets
1554 *
1555 * 0 1 2 3
1556 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1557 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1558 * 00| 2 | |
1559 * +-+-+-+-+-+-+-+-+ |
1560 * 04| MBZ (15 octets) |
1561 * 08| |
1562 * 12| |
1563 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1564 * 16| |
1565 * 20| HMAC (16 octets) |
1566 * 24| |
1567 * 28| |
1568 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1569 *
1570 */
1571 OWPErrSeverity
_OWPWriteStartSessions(OWPControl cntrl,int * retn_on_intr)1572 _OWPWriteStartSessions(
1573 OWPControl cntrl,
1574 int *retn_on_intr
1575 )
1576 {
1577 char *buf = (char *)cntrl->msg;
1578
1579 if(!_OWPStateIsRequest(cntrl) || _OWPStateIsPending(cntrl)){
1580 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1581 "_OWPWriteStartSessions:called in wrong state.");
1582 return OWPErrFATAL;
1583 }
1584
1585 buf[0] = 2; /* start-session identifier */
1586 #ifndef NDEBUG
1587 memset(&buf[1],0,15); /* Unused */
1588 #endif
1589 memset(&buf[16],0,16); /* Zero padding */
1590
1591 /*
1592 * Add text to HMAC and put digest in second block of message
1593 */
1594 _OWPSendHMACAdd(cntrl,buf,1);
1595 _OWPSendHMACDigestClear(cntrl,&buf[16]);
1596
1597 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,2,retn_on_intr) != 2){
1598 cntrl->state = _OWPStateInvalid;
1599 return OWPErrFATAL;
1600 }
1601
1602 cntrl->state |= _OWPStateStartAck;
1603 cntrl->state |= _OWPStateTest;
1604 return OWPErrOK;
1605 }
1606
1607 OWPErrSeverity
_OWPReadStartSessions(OWPControl cntrl,int * retn_on_intr)1608 _OWPReadStartSessions(
1609 OWPControl cntrl,
1610 int *retn_on_intr
1611 )
1612 {
1613 int n;
1614 char *buf = (char *)cntrl->msg;
1615
1616 if(!_OWPStateIs(_OWPStateStartSessions,cntrl)){
1617 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1618 "_OWPReadStartSessions: called in wrong state.");
1619 return OWPErrFATAL;
1620 }
1621
1622 /*
1623 * Already read the first block - read the rest for this message
1624 * type.
1625 */
1626 n = _OWPReceiveBlocksIntr(cntrl,(uint8_t *)&buf[16],
1627 _OWP_STOP_SESSIONS_BLK_LEN-1,retn_on_intr);
1628
1629 if((n < 0) && *retn_on_intr && (errno == EINTR)){
1630 return OWPErrFATAL;
1631 }
1632
1633 if(n != (_OWP_STOP_SESSIONS_BLK_LEN-1)){
1634 OWPError(cntrl->ctx,OWPErrFATAL,errno,
1635 "_OWPReadStartSessions: Unable to read from socket.");
1636 cntrl->state = _OWPStateInvalid;
1637 return OWPErrFATAL;
1638 }
1639
1640 /*
1641 * Put first block in HMAC, then check to see if the digest matches
1642 * the second block.
1643 */
1644 _OWPRecvHMACAdd(cntrl,buf,1);
1645 if(!_OWPRecvHMACCheckClear(cntrl,&buf[16])){
1646 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1647 "_OWPReadStartSessions: Invalid HMAC");
1648 cntrl->state = _OWPStateInvalid;
1649 return OWPErrFATAL;
1650 }
1651
1652 if(buf[0] != 2){
1653 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1654 "_OWPReadStartSessions: Not a StartSessions message...");
1655 cntrl->state = _OWPStateInvalid;
1656 return OWPErrFATAL;
1657 }
1658
1659 /*
1660 * The control connection is now ready to send the response.
1661 */
1662 cntrl->state &= ~_OWPStateStartSessions;
1663 cntrl->state |= _OWPStateStartAck;
1664 cntrl->state |= _OWPStateTest;
1665
1666 return OWPErrOK;
1667 }
1668
1669 /*
1670 *
1671 * StartAck message format:
1672 *
1673 * size: 32 octets
1674 *
1675 * 0 1 2 3
1676 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1677 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1678 * 00| Accept | |
1679 * +-+-+-+-+-+-+-+-+ +
1680 * 04| MBZ (15 octets) |
1681 * 08| |
1682 * 12| |
1683 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1684 * 16| |
1685 * 20| HMAC (16 octets) |
1686 * 24| |
1687 * 28| |
1688 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1689 *
1690 */
1691 OWPErrSeverity
_OWPWriteStartAck(OWPControl cntrl,int * retn_on_intr,OWPAcceptType acceptval)1692 _OWPWriteStartAck(
1693 OWPControl cntrl,
1694 int *retn_on_intr,
1695 OWPAcceptType acceptval
1696 )
1697 {
1698 int n;
1699 char *buf = (char *)cntrl->msg;
1700
1701 if(!_OWPStateIs(_OWPStateStartAck,cntrl)){
1702 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1703 "_OWPWriteStartAck called in wrong state.");
1704 return OWPErrFATAL;
1705 }
1706
1707 buf[0] = acceptval & 0xff;
1708 memset(&buf[1],0,15); /* MBZ */
1709
1710 _OWPSendHMACAdd(cntrl,buf,1);
1711 _OWPSendHMACDigestClear(cntrl,&buf[16]);
1712
1713 n = _OWPSendBlocksIntr(cntrl,(uint8_t *)buf,2,retn_on_intr);
1714
1715 if((n < 0) && *retn_on_intr && (errno == EINTR)){
1716 return OWPErrFATAL;
1717 }
1718
1719 if(n != 2){
1720 cntrl->state = _OWPStateInvalid;
1721 return OWPErrFATAL;
1722 }
1723
1724 /*
1725 * StartAck has been sent, leave that state.
1726 */
1727 cntrl->state &= ~_OWPStateStartAck;
1728
1729 /*
1730 * Test was denied - go back to Request state.
1731 */
1732 if(acceptval != OWP_CNTRL_ACCEPT){
1733 cntrl->state &= ~_OWPStateTest;
1734 }
1735
1736 return OWPErrOK;
1737 }
1738
1739 OWPErrSeverity
_OWPReadStartAck(OWPControl cntrl,int * retn_on_intr,OWPAcceptType * acceptval)1740 _OWPReadStartAck(
1741 OWPControl cntrl,
1742 int *retn_on_intr,
1743 OWPAcceptType *acceptval
1744 )
1745 {
1746 char *buf = (char *)cntrl->msg;
1747
1748 *acceptval = OWP_CNTRL_INVALID;
1749
1750 if(!_OWPStateIs(_OWPStateStartAck,cntrl)){
1751 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1752 "_OWPReadStartAck: called in wrong state.");
1753 return OWPErrFATAL;
1754 }
1755
1756 if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)&buf[0],2,retn_on_intr) !=
1757 (_OWP_START_ACK_BLK_LEN)){
1758 OWPError(cntrl->ctx,OWPErrFATAL,errno,
1759 "_OWPReadStartAck: Unable to read from socket.");
1760 cntrl->state = _OWPStateInvalid;
1761 return OWPErrFATAL;
1762 }
1763
1764 /*
1765 * Put first block in HMAC, then check to see if the digest matches
1766 * the second block.
1767 */
1768 _OWPRecvHMACAdd(cntrl,buf,1);
1769 if(!_OWPRecvHMACCheckClear(cntrl,&buf[16])){
1770 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1771 "_OWPReadStartAck: Invalid HMAC");
1772 cntrl->state = _OWPStateInvalid;
1773 return OWPErrFATAL;
1774 }
1775
1776 *acceptval = GetAcceptType(cntrl,buf[0]);
1777 if(*acceptval == OWP_CNTRL_INVALID){
1778 cntrl->state = _OWPStateInvalid;
1779 return OWPErrFATAL;
1780 }
1781
1782 /*
1783 * received StartAck - leave that state.
1784 */
1785 cntrl->state &= ~_OWPStateStartAck;
1786
1787 /* If StartSessions was rejected get back into StateRequest */
1788 if (*acceptval != OWP_CNTRL_ACCEPT){
1789 cntrl->state &= ~_OWPStateTest;
1790 cntrl->state |= _OWPStateRequest;
1791 }
1792
1793 return OWPErrOK;
1794 }
1795
1796 /*
1797 * Full StopSessions message format:
1798 *
1799 * size: variable
1800 *
1801 * header portion: size 16 octets
1802 *
1803 * 0 1 2 3
1804 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1805 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1806 * 00| 3 | Accept | MBZ |
1807 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1808 * 04| Number of Sessions |
1809 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1810 * 08| MBZ (8 octets) |
1811 * 12| |
1812 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1813 *
1814 ** [ N Session Description Records]
1815 ** Session Description Record: size variable
1816 ** (Number of Sessions above indicates how many of these)
1817 **
1818 ** header of this sub-record: size 24 octets
1819 **
1820 ** 0 1 2 3
1821 ** 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1822 ** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1823 ** 00| |
1824 ** 04| SID (16 octets) |
1825 ** 08| |
1826 ** 12| |
1827 ** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1828 ** 16| Next Seqno |
1829 ** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1830 ** 24| Number of Skip Ranges |
1831 ** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1832 **
1833 *** [ N Skip Ranges]
1834 ***
1835 *** Skip Ranges: size 8 octets each
1836 *** Number of Skip Ranges above indicates how many of these in this
1837 *** session description record.
1838 ***
1839 *** SkipRecord format:
1840 ***
1841 *** size: 8 octets
1842 ***
1843 *** 0 1 2 3
1844 *** 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1845 *** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1846 *** 00| First Seqno Skipped |
1847 *** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1848 *** 04| Last Seqno Skipped |
1849 *** +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1850 ***
1851 *** [END Skip Ranges]
1852 ***
1853 *** Then the Session Description Record is padded out to complete the
1854 *** current block.
1855 ***
1856 *** [END SessionDescription Records]
1857 *
1858 * After all SessionDescription Records a final block of IZP completes
1859 * the StopSession message:
1860 *
1861 * 0 1 2 3
1862 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1863 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1864 * 00| |
1865 * 04| HMAC (16 octets) |
1866 * 08| |
1867 * 12| |
1868 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1869 */
1870 /*
1871 * Function:
1872 * _OWPWriteStopSessions
1873 *
1874 * Description:
1875 * Sends the StopSessions message as described above. Also
1876 * stops local sessions.
1877 *
1878 * In Args:
1879 *
1880 * Out Args:
1881 *
1882 * Scope:
1883 * Returns:
1884 * Side Effect:
1885 * All local sessions are stopped.
1886 */
1887 OWPErrSeverity
_OWPWriteStopSessions(OWPControl cntrl,int * retn_on_intr,OWPAcceptType acceptval,uint32_t num_sessions)1888 _OWPWriteStopSessions(
1889 OWPControl cntrl,
1890 int *retn_on_intr,
1891 OWPAcceptType acceptval,
1892 uint32_t num_sessions
1893 )
1894 {
1895 OWPTestSession sptr;
1896 char *buf = (char *)cntrl->msg;
1897
1898 if(!(_OWPStateIs(_OWPStateRequest,cntrl) &&
1899 _OWPStateIs(_OWPStateTest,cntrl))){
1900 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1901 "_OWPWriteStopSessions: called in wrong state.");
1902 return OWPErrFATAL;
1903 }
1904
1905
1906 /*
1907 * StopSessions header
1908 */
1909 memset(&buf[0],0,16);
1910
1911 buf[0] = 3;
1912 buf[1] = acceptval & 0xff;
1913 *(uint32_t*)&buf[4] = htonl(num_sessions);
1914
1915 /*
1916 * Add 'header' into HMAC and send
1917 */
1918 _OWPSendHMACAdd(cntrl,buf,1);
1919 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1920 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1921 }
1922
1923
1924 /*
1925 * Loop through each session, write out a session description
1926 * record for each "send" session.
1927 */
1928 for(sptr=cntrl->tests; sptr; sptr = sptr->next){
1929 off_t sd_size;
1930
1931 /*
1932 * Check for invalid sessions
1933 */
1934 if(!sptr->endpoint){
1935 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
1936 "_OWPWriteStopSessions: invalid session information.");
1937 continue;
1938 }
1939
1940 /*
1941 * Receive sessions don't need more work here.
1942 */
1943 if(!sptr->endpoint->send) continue;
1944
1945 _OWPSendHMACAdd(cntrl,(char *)sptr->sid,1);
1946 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)sptr->sid,1,retn_on_intr) != 1){
1947 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1948 }
1949
1950 sd_size = sptr->endpoint->skiprecsize;
1951
1952 /*
1953 * First send out complete blocks
1954 */
1955 while(sd_size >= 16){
1956 if(I2Readni(sptr->endpoint->skiprecfd,buf,16,retn_on_intr) != 16){
1957 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1958 }
1959 _OWPSendHMACAdd(cntrl,buf,1);
1960 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1961 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1962 }
1963 sd_size -= 16;
1964 }
1965
1966 /*
1967 * If last skip record does not end on a block boundry, then
1968 * there can be 8 octets of skip records left to send.
1969 */
1970 if(sd_size == 8){
1971 if(I2Readni(sptr->endpoint->skiprecfd,buf,8,retn_on_intr) != 8){
1972 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1973 }
1974 /* pad with 0 */
1975 memset(&buf[8],0,8);
1976 _OWPSendHMACAdd(cntrl,buf,1);
1977 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1978 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1979 }
1980 sd_size -= 8;
1981 }
1982
1983 /*
1984 * If all data has not been sent, there is an error.
1985 */
1986 if(sd_size != 0){
1987 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1988 }
1989 }
1990
1991 /*
1992 * Complete WriteStopSessions by sending HMAC.
1993 */
1994 _OWPSendHMACDigestClear(cntrl,buf);
1995 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,1,retn_on_intr) != 1){
1996 return _OWPFailControlSession(cntrl,OWPErrFATAL);
1997 }
1998
1999 return OWPErrOK;
2000 }
2001
2002 /*
2003 * SkipRecord format:
2004 *
2005 * size: 8 octets
2006 *
2007 * 0 1 2 3
2008 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2009 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2010 * 00| First Seqno Skipped |
2011 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2012 * 04| Last Seqno Skipped |
2013 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2014 *
2015 */
2016
2017 /*
2018 * Function: _OWPEncodeSkipRecord
2019 *
2020 * Description:
2021 * This function is used to encode a single 8 octet/2 integer skip
2022 * record used to indicate a range of test packets that were never
2023 * sent due to scheduling issues on the sender host.
2024 *
2025 * In Args:
2026 *
2027 * Out Args:
2028 *
2029 * Scope:
2030 * Returns:
2031 * Side Effect:
2032 */
2033 void
_OWPEncodeSkipRecord(uint8_t buf[_OWP_SKIPREC_SIZE],OWPSkip skip)2034 _OWPEncodeSkipRecord(
2035 uint8_t buf[_OWP_SKIPREC_SIZE],
2036 OWPSkip skip
2037 )
2038 {
2039 uint32_t nlbuf;
2040
2041 /* begin seq */
2042 nlbuf = htonl(skip->begin);
2043 memcpy(&buf[0],&nlbuf,4);
2044
2045 /* end seq */
2046 nlbuf = htonl(skip->end);
2047 memcpy(&buf[4],&nlbuf,4);
2048
2049 return;
2050 }
2051
2052
2053 /*
2054 * Function: OWPDecodeSkipRecord
2055 *
2056 * Description:
2057 * This function is used to decode the "skip record" and
2058 * place the values in the given _OWPSkipRec.
2059 *
2060 * In Args:
2061 *
2062 * Out Args:
2063 *
2064 * Scope:
2065 * Returns:
2066 * Side Effect:
2067 */
2068 void
_OWPDecodeSkipRecord(OWPSkip skip,char buf[_OWP_SKIPREC_SIZE])2069 _OWPDecodeSkipRecord(
2070 OWPSkip skip,
2071 char buf[_OWP_SKIPREC_SIZE]
2072 )
2073 {
2074 /*
2075 * memcpy buf in case it is not 32bit aligned.
2076 */
2077 memcpy(&skip->begin,&buf[0],4);
2078 skip->begin = ntohl(skip->begin);
2079
2080 memcpy(&skip->end,&buf[4],4);
2081 skip->end = ntohl(skip->end);
2082
2083 return;
2084 }
2085
2086 /*
2087 * Function: _OWPReadStopSessions
2088 *
2089 * Description:
2090 * This function updates the "recv" side sessions with
2091 * the data from the senders in the Stop Sessions message.
2092 * This includes updating the recv file record. Therefore,
2093 * there are possible race-conditions. (This is done by the
2094 * recv process - a control process could potentially be
2095 * reading the file at any time.) Therefore, it is imperative
2096 * that things be done in the correct order to avoid this.
2097 *
2098 * Correct order:
2099 * No skip records can be added into the file until
2100 * after the number of data records in the file has
2101 * become fixed. This way ProcessFetchSessions can
2102 * use the file size to determine the number of records
2103 * if the file is not "complete". Also, the "finished"
2104 * field of the file should not be modified to "complete"
2105 * until all other field have been updated. Therefore,
2106 * for the basic receiver, the order should be:
2107 * 1. write header - no num_records or num_skips
2108 * 2. write data records
2109 * 3. write num_datarecs
2110 * 4. write skips
2111 * 5. write num_skips
2112 * 6. write next_seqno/finished
2113 *
2114 *
2115 * TODO: Eventually should probably read this message into a temp
2116 * buffer of some sort, and check the HMAC BEFORE modifying
2117 * the recv files.
2118 * In Args:
2119 *
2120 * Out Args:
2121 *
2122 * Scope:
2123 * Returns:
2124 * Side Effect:
2125 */
2126 OWPErrSeverity
_OWPReadStopSessions(OWPControl cntrl,int * intr,OWPAcceptType * acceptval,OWPTimeStamp stoptime)2127 _OWPReadStopSessions(
2128 OWPControl cntrl,
2129 int *intr,
2130 OWPAcceptType *acceptval,
2131 OWPTimeStamp stoptime
2132 )
2133 {
2134 int n;
2135 char *buf = (char *)cntrl->msg;
2136 OWPAcceptType aval;
2137 uint32_t i,j,num_sessions;
2138 OWPTestSession *sptr,tptr;
2139 OWPTestSession receivers = NULL;
2140 off_t toff;
2141
2142 if(!(_OWPStateIs(_OWPStateRequest,cntrl) &&
2143 _OWPStateIs(_OWPStateTest,cntrl))){
2144 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2145 "_OWPReadStopSessions called in wrong state.");
2146 return OWPErrFATAL;
2147 }
2148
2149 /*
2150 * Decode first block of StopSessions message.
2151 */
2152 aval = GetAcceptType(cntrl,buf[1]);
2153 if(acceptval)
2154 *acceptval = aval;
2155
2156 if(aval == OWP_CNTRL_INVALID){
2157 goto err;
2158 }
2159
2160 num_sessions = ntohl(*(uint32_t*)&buf[4]);
2161
2162 _OWPRecvHMACAdd(cntrl,buf,1);
2163
2164 /*
2165 * Parse test session list and pull recv sessions into the receivers
2166 * list - the StopSessions message must account for all of them.
2167 */
2168 sptr = &cntrl->tests;
2169 while(*sptr){
2170 tptr = *sptr;
2171 if(!tptr->endpoint){
2172 OWPError(cntrl->ctx,OWPErrFATAL,EINVAL,
2173 "_OWPReadStopSessions: no endpoint state!");
2174 goto err;
2175 }
2176
2177 /*
2178 * Leave send sessions in the "tests" list.
2179 */
2180 if(tptr->endpoint->send){
2181 sptr = &(*sptr)->next;
2182 continue;
2183 }
2184
2185 /*
2186 * Pull this node out of the "tests" list and add it to the
2187 * receivers list.
2188 */
2189 *sptr = tptr->next;
2190 tptr->next = receivers;
2191 receivers = tptr;
2192 }
2193
2194 /*
2195 * Now read and decode the variable length portion of the
2196 * StopSessions message.
2197 */
2198 for(i=0;i<num_sessions;i++){
2199 FILE *rfp;
2200 char sid_name[sizeof(OWPSID)*2+1];
2201 _OWPSessionHeaderInitialRec fhdr;
2202 struct flock flk;
2203 OWPSkipRec prev_skip, curr_skip;
2204 uint32_t next_seqno;
2205 uint32_t num_skips;
2206
2207 /*
2208 * Read sid from session description record
2209 */
2210 n = _OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,intr);
2211 if(n != 1){
2212 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2213 "_OWPReadStopSessions: Unable to read session record (%d)",
2214 i);
2215 goto err;
2216 }
2217 _OWPRecvHMACAdd(cntrl,buf,1);
2218
2219 /*
2220 * Match TestSession record with session description record
2221 */
2222 sptr = &receivers;
2223 tptr = NULL;
2224 while(*sptr){
2225 /*
2226 * If this is not it, try the next one.
2227 */
2228 if(memcmp(buf,(*sptr)->sid,sizeof(OWPSID))){
2229 sptr = &(*sptr)->next;
2230 continue;
2231 }
2232
2233 /*
2234 * Found: remove this record from the receivers list
2235 * and put it back in the "tests" list and break out
2236 * of this loop.
2237 */
2238 tptr = *sptr;
2239 *sptr = tptr->next;
2240 tptr->next = cntrl->tests;
2241 cntrl->tests = tptr;
2242 break;
2243 }
2244
2245 /*
2246 * If sid not found, this is an invalid StopSessions message.
2247 */
2248 if(!tptr){
2249 OWPError(cntrl->ctx,OWPErrFATAL,EINVAL,
2250 "_OWPReadStopSessions: sid from StopSessions not valid.");
2251 goto err;
2252 }
2253
2254 /*
2255 * Read next_seqno, num_skips from SessionDescription record
2256 */
2257 n = _OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,intr);
2258 if(n != 1){
2259 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2260 "_OWPReadStopSessions: Unable to read session record (%d)",
2261 i);
2262 goto err;
2263 }
2264 _OWPRecvHMACAdd(cntrl,buf,1);
2265 next_seqno = ntohl(*(uint32_t*)&buf[0]);
2266 num_skips = ntohl(*(uint32_t*)&buf[4]);
2267
2268 I2HexEncode(sid_name,tptr->sid,sizeof(OWPSID));
2269
2270 rfp = tptr->endpoint->datafile;
2271
2272 /*
2273 * Lock the data file for writing. This is needed so FetchSessions
2274 * coming in from other control connections will get consistent
2275 * information.
2276 */
2277 memset(&flk,0,sizeof(flk));
2278 flk.l_start = 0;
2279 flk.l_len = 0;
2280 flk.l_whence = SEEK_SET;
2281 flk.l_type = F_WRLCK;
2282
2283 if( fcntl(fileno(rfp), F_SETLKW, &flk) < 0){
2284 OWPError(cntrl->ctx,OWPErrFATAL,errno,
2285 "_OWPReadStopSessions: Unable to lock file sid(%s): %M",
2286 sid_name);
2287 goto err;
2288 }
2289
2290 if( !_OWPCleanDataRecs(cntrl->ctx,tptr,next_seqno,stoptime,NULL,NULL)){
2291 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
2292 "_OWPReadStopSessions: Unable to clean data sid(%s): %M",
2293 sid_name);
2294 goto err;
2295 }
2296
2297 /*
2298 * Read needed file header info.
2299 */
2300 if(!_OWPReadDataHeaderInitial(cntrl->ctx,rfp,&fhdr)){
2301 goto err;
2302 }
2303
2304 /*
2305 * Advance fp beyond datarecords, write skip records and write
2306 * NumSkipRecords
2307 */
2308 if(!num_skips) goto done_skips;
2309 toff = fhdr.oset_datarecs + (fhdr.num_datarecs * fhdr.rec_size);
2310 if(fseeko(rfp,toff,SEEK_SET) != 0){
2311 OWPError(cntrl->ctx,OWPErrFATAL,errno,"fseeko(): %M");
2312 goto err;
2313 }
2314
2315 prev_skip.begin = prev_skip.end = 0;
2316 for(j=0; j < num_skips; j++){
2317 uint8_t bufi;
2318
2319 /*
2320 * Index into buffer for this skip record. (Either 0 or 8)
2321 */
2322 bufi = ((j+1) % 2) * 8;
2323
2324 /*
2325 * Only need to read another record when bufi == 0
2326 */
2327 if(!bufi){
2328 /*
2329 * Read next block
2330 */
2331 n = _OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,intr);
2332 if(n != 1){
2333 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2334 "_OWPReadStopSessions: Unable to read skip record sid(%s)",
2335 sid_name);
2336 goto err;
2337 }
2338 _OWPRecvHMACAdd(cntrl,buf,1);
2339 }
2340
2341 /*
2342 * Validate skip record. (begin <= end) and this skip_range
2343 * is greater-than the previous.
2344 */
2345 _OWPDecodeSkipRecord(&curr_skip,&buf[bufi]);
2346 if(curr_skip.end < curr_skip.begin){
2347 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2348 "_OWPReadStopSessions: Invalid skip record sid(%s): end < begin",
2349 sid_name);
2350 goto err;
2351 }
2352 if(prev_skip.end && (curr_skip.begin < prev_skip.end)){
2353 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2354 "_OWPReadStopSessions: Invalid skip record sid(%s): skips out of order",
2355 sid_name);
2356 goto err;
2357 }
2358
2359 /*
2360 * Write this skip record into the file.
2361 *
2362 * Using 8 for test so this will fail immediately if skip record
2363 * size changes. This whole routine will need to be modified...
2364 */
2365 if(fwrite(&buf[bufi],1,_OWP_SKIPREC_SIZE,rfp) != 8){
2366 OWPError(cntrl->ctx,OWPErrFATAL,errno,
2367 "fwrite(): Writing session file sid(%s): %M",
2368 sid_name);
2369 goto err;
2370 }
2371 }
2372
2373 done_skips:
2374 /*
2375 * If num_skips is even, then there should be 8 bytes of zero
2376 * padding to complete the block. Verify.
2377 */
2378 if( !(num_skips % 2)){
2379 if(memcmp(cntrl->zero,&buf[8],8)){
2380 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2381 "_OWPReadStopSessions: Session sid(%s): Invalid zero padding",
2382 sid_name);
2383 goto err;
2384 }
2385 }
2386
2387 /*
2388 * Write num_skips and "finished" into file.
2389 */
2390 if( !OWPWriteDataHeaderNumSkipRecs(cntrl->ctx,rfp,num_skips)){
2391 goto err;
2392 }
2393
2394 if( !_OWPWriteDataHeaderFinished(cntrl->ctx,rfp,OWP_SESSION_FINISHED_NORMAL,
2395 next_seqno)){
2396 goto err;
2397 }
2398
2399 flk.l_type = F_UNLCK;
2400 if( fcntl(fileno(rfp), F_SETLKW, &flk) < 0){
2401 OWPError(cntrl->ctx,OWPErrFATAL,errno,
2402 "_OWPReadStopSessions: Unable to unlock file sid(%s): %M",
2403 sid_name);
2404 goto err;
2405 }
2406 }
2407
2408 if(*sptr){
2409 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2410 "_OWPReadStopSessions: Message does not account for all recv sessions");
2411 goto err;
2412 }
2413
2414 /*
2415 * HMAC completes the StopSessions message.
2416 */
2417 n = _OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,1,intr);
2418 if(n != 1){
2419 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2420 "_OWPReadStopSessions: Unable to read final HMAC block");
2421 goto err;
2422 }
2423 if(!_OWPRecvHMACCheckClear(cntrl,buf)){
2424 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2425 "_OWPReadStopSessions: Invalid HMAC");
2426 goto err;
2427 }
2428
2429 /*
2430 * The control connection is now ready to send the response.
2431 */
2432 cntrl->state &= ~_OWPStateStopSessions;
2433 cntrl->state |= _OWPStateRequest;
2434
2435 return OWPErrOK;
2436
2437 err:
2438 /*
2439 * take everything in receivers list and put it back in tests list
2440 * so error cleanup at higher levels will work.
2441 */
2442 while(receivers){
2443 tptr = receivers;
2444 receivers = receivers->next;
2445
2446 tptr->next = cntrl->tests;
2447 cntrl->tests = tptr;
2448 }
2449
2450 if(acceptval){
2451 *acceptval = OWP_CNTRL_FAILURE;
2452 }
2453 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrUNKNOWN,
2454 "_OWPReadStopSessions: Failed");
2455 return _OWPFailControlSession(cntrl,OWPErrFATAL);
2456 }
2457
2458 /*
2459 * FetchSession message format:
2460 *
2461 * size: 48 octets
2462 *
2463 * 0 1 2 3
2464 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2465 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2466 * 00| 4 | |
2467 * +-+-+-+-+-+-+-+-+ +
2468 * 04| MBZ (7 octets) |
2469 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2470 * 08| Begin Seq |
2471 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2472 * 12| End Seq |
2473 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2474 * 16| |
2475 * 20| SID (16 octets) |
2476 * 24| |
2477 * 28| |
2478 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2479 * 32| |
2480 * 36| HMAC (16 octets) |
2481 * 40| |
2482 * 44| |
2483 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2484 *
2485 */
2486 OWPErrSeverity
_OWPWriteFetchSession(OWPControl cntrl,int * retn_on_intr,uint32_t begin,uint32_t end,OWPSID sid)2487 _OWPWriteFetchSession(
2488 OWPControl cntrl,
2489 int *retn_on_intr,
2490 uint32_t begin,
2491 uint32_t end,
2492 OWPSID sid
2493 )
2494 {
2495 char *buf = (char *)cntrl->msg;
2496
2497 if(!_OWPStateIs(_OWPStateRequest,cntrl) || _OWPStateIsTest(cntrl)){
2498 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2499 "_OWPWriteFetchSession called in wrong state.");
2500 return OWPErrFATAL;
2501 }
2502
2503 buf[0] = 4;
2504 #ifndef NDEBUG
2505 memset(&buf[1],0,7); /* Unused */
2506 #endif
2507 *(uint32_t*)&buf[8] = htonl(begin);
2508 *(uint32_t*)&buf[12] = htonl(end);
2509 memcpy(&buf[16],sid,16);
2510
2511 _OWPSendHMACAdd(cntrl,buf,2);
2512 _OWPSendHMACDigestClear(cntrl,&buf[32]);
2513
2514 if(_OWPSendBlocksIntr(cntrl,(uint8_t *)buf,3,retn_on_intr) != 3)
2515 return OWPErrFATAL;
2516
2517 cntrl->state |= (_OWPStateFetchAck | _OWPStateFetchSession);
2518 cntrl->state &= ~(_OWPStateRequest);
2519 return OWPErrOK;
2520 }
2521
2522 OWPErrSeverity
_OWPReadFetchSession(OWPControl cntrl,int * retn_on_intr,uint32_t * begin,uint32_t * end,OWPSID sid)2523 _OWPReadFetchSession(
2524 OWPControl cntrl,
2525 int *retn_on_intr,
2526 uint32_t *begin,
2527 uint32_t *end,
2528 OWPSID sid
2529 )
2530 {
2531 int n;
2532 char *buf = (char *)cntrl->msg;
2533
2534 if(!_OWPStateIs(_OWPStateFetchSession,cntrl)){
2535 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2536 "_OWPReadFetchSession: called in wrong state.");
2537 return OWPErrFATAL;
2538 }
2539
2540 /*
2541 * Already read the first block - read the rest for this message
2542 * type.
2543 */
2544 n = _OWPReceiveBlocksIntr(cntrl,(uint8_t *)&buf[16],_OWP_FETCH_SESSION_BLK_LEN-1,
2545 retn_on_intr);
2546
2547 if((n < 0) && *retn_on_intr && (errno == EINTR)){
2548 return OWPErrFATAL;
2549 }
2550
2551 if(n != (_OWP_FETCH_SESSION_BLK_LEN-1)){
2552 OWPError(cntrl->ctx,OWPErrFATAL,errno,
2553 "_OWPReadFetchSession: Unable to read from socket.");
2554 cntrl->state = _OWPStateInvalid;
2555 return OWPErrFATAL;
2556 }
2557
2558 _OWPRecvHMACAdd(cntrl,buf,2);
2559 if(!_OWPRecvHMACCheckClear(cntrl,&buf[32])){
2560 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2561 "_OWPReadFetchSession: Invalid HMAC");
2562 cntrl->state = _OWPStateInvalid;
2563 return OWPErrFATAL;
2564 }
2565
2566 if(buf[0] != 4){
2567 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2568 "_OWPReadFetchSession: Invalid message...");
2569 cntrl->state = _OWPStateInvalid;
2570 return OWPErrFATAL;
2571 }
2572
2573 *begin = ntohl(*(uint32_t*)&buf[8]);
2574 *end = ntohl(*(uint32_t*)&buf[12]);
2575 memcpy(sid,&buf[16],16);
2576
2577 /*
2578 * The control connection is now ready to send the response.
2579 * (We are no-longer in FetchSession/Request state, we are
2580 * in FetchAck/Fetching state.)
2581 */
2582 cntrl->state &= (~_OWPStateFetchSession & ~_OWPStateRequest);
2583 cntrl->state |= _OWPStateFetchAck|_OWPStateFetching;
2584
2585 return OWPErrOK;
2586 }
2587
2588 /*
2589 *
2590 * FetchAck message format:
2591 *
2592 * size: 32 octets
2593 *
2594 * 0 1 2 3
2595 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2596 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2597 * 00| Accept | Finished | MBZ (2 octets) |
2598 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2599 * 04| Next Seqno |
2600 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2601 * 08| Number of Skip Ranges |
2602 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2603 * 12| Number of Records |
2604 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2605 * 16| |
2606 * 20| HMAC (16 octets) |
2607 * 24| |
2608 * 28| |
2609 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2610 *
2611 */
2612 OWPErrSeverity
_OWPWriteFetchAck(OWPControl cntrl,int * retn_on_intr,OWPAcceptType acceptval,uint8_t finished,uint32_t next_seqno,uint32_t num_skiprecs,uint32_t num_datarecs)2613 _OWPWriteFetchAck(
2614 OWPControl cntrl,
2615 int *retn_on_intr,
2616 OWPAcceptType acceptval,
2617 uint8_t finished,
2618 uint32_t next_seqno,
2619 uint32_t num_skiprecs,
2620 uint32_t num_datarecs
2621 )
2622 {
2623 int n;
2624 char *buf = (char *)cntrl->msg;
2625
2626 if(!_OWPStateIs(_OWPStateFetchAck,cntrl)){
2627 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2628 "_OWPWriteFetchAck called in wrong state.");
2629 return OWPErrFATAL;
2630 }
2631
2632 /* initialize */
2633 memset(&buf[0],0,32);
2634
2635 buf[0] = acceptval & 0xff;
2636 buf[1] = finished & 0xff;
2637
2638
2639 if(finished){
2640 *(uint32_t*)&buf[4] = htonl(next_seqno);
2641 *(uint32_t*)&buf[8] = htonl(num_skiprecs);
2642 }
2643
2644 *(uint32_t*)&buf[12] = htonl(num_datarecs);
2645
2646 _OWPSendHMACAdd(cntrl,buf,1);
2647 _OWPSendHMACDigestClear(cntrl,&buf[16]);
2648
2649 n = _OWPSendBlocksIntr(cntrl,(uint8_t *)buf,2,retn_on_intr);
2650
2651 /*
2652 * Return control to a higher level on interrupt.
2653 */
2654 if((n < 0) && *retn_on_intr && (errno == EINTR)){
2655 return OWPErrFATAL;
2656 }
2657
2658 if(n != 2){
2659 cntrl->state = _OWPStateInvalid;
2660 return OWPErrFATAL;
2661 }
2662
2663 /*
2664 * FetchAck has been sent, leave that state.
2665 */
2666 cntrl->state &= ~_OWPStateFetchAck;
2667
2668 /*
2669 * Fetch was denied - this short-cuts fetch response to "only"
2670 * the actual FetchAck message - no data will follow.
2671 * So, leave Fetching state and go back to plain Request state.
2672 */
2673 if(acceptval != OWP_CNTRL_ACCEPT){
2674 cntrl->state &= ~_OWPStateFetching;
2675 cntrl->state |= _OWPStateRequest;
2676 }
2677
2678 return OWPErrOK;
2679 }
2680
2681 OWPErrSeverity
_OWPReadFetchAck(OWPControl cntrl,int * retn_on_intr,OWPAcceptType * acceptval,uint8_t * finished,uint32_t * next_seqno,uint32_t * num_skiprecs,uint32_t * num_datarecs)2682 _OWPReadFetchAck(
2683 OWPControl cntrl,
2684 int *retn_on_intr,
2685 OWPAcceptType *acceptval,
2686 uint8_t *finished,
2687 uint32_t *next_seqno,
2688 uint32_t *num_skiprecs,
2689 uint32_t *num_datarecs
2690 )
2691 {
2692 char *buf = (char *)cntrl->msg;
2693
2694 *acceptval = OWP_CNTRL_INVALID;
2695
2696 if(!_OWPStateIs(_OWPStateFetchAck,cntrl)){
2697 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2698 "_OWPReadFetchAck: called in wrong state.");
2699 return OWPErrFATAL;
2700 }
2701
2702 if(_OWPReceiveBlocksIntr(cntrl,(uint8_t *)buf,2,retn_on_intr) != 2){
2703 OWPError(cntrl->ctx,OWPErrFATAL,errno,
2704 "_OWPReadFetchAck: Unable to read from socket.");
2705 cntrl->state = _OWPStateInvalid;
2706 return OWPErrFATAL;
2707 }
2708
2709 _OWPRecvHMACAdd(cntrl,buf,1);
2710 if(!_OWPRecvHMACCheckClear(cntrl,&buf[16])){
2711 OWPError(cntrl->ctx,OWPErrFATAL,OWPErrINVALID,
2712 "_OWPReadFetchAck: Invalid HMAC");
2713 cntrl->state = _OWPStateInvalid;
2714 return OWPErrFATAL;
2715 }
2716
2717 *acceptval = GetAcceptType(cntrl,buf[0]);
2718 if(*acceptval == OWP_CNTRL_INVALID){
2719 cntrl->state = _OWPStateInvalid;
2720 return OWPErrFATAL;
2721 }
2722
2723 *finished = buf[1];
2724 *next_seqno = ntohl(*(uint32_t*)&buf[4]);
2725 *num_skiprecs = ntohl(*(uint32_t*)&buf[8]);
2726 *num_datarecs = ntohl(*(uint32_t*)&buf[12]);
2727
2728 /*
2729 * received FetchAck - leave that state.
2730 */
2731 cntrl->state &= ~_OWPStateFetchAck;
2732 cntrl->state &= ~(_OWPStateFetchSession);
2733
2734 /* If FetchRequest was rejected get back into StateRequest */
2735 if(*acceptval != OWP_CNTRL_ACCEPT){
2736 cntrl->state |= _OWPStateRequest;
2737 }else{
2738 /* Otherwise prepare to read the TestRequest */
2739 cntrl->state |= _OWPStateTestRequest;
2740 }
2741
2742 return OWPErrOK;
2743 }
2744
2745 /*
2746 * DataRecord V2 format:
2747 *
2748 * size: 24 octets
2749 *
2750 * 0 1 2 3
2751 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2752 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2753 * 00| Seq Number |
2754 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2755 * 04| Send Timestamp |
2756 * 08| |
2757 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2758 * 12| Send Error Estimate | |
2759 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
2760 * 16| Receive Timestamp |
2761 * + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2762 * 20| | Receive Error Estimate |
2763 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2764 *
2765 */
2766 /*
2767 * DataRecord V3 format:
2768 *
2769 * size: 25 octets
2770 *
2771 * 0 1 2 3
2772 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2773 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2774 * 00| Seq Number |
2775 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2776 * 04| Send Error Estimate | Receive Error Estimate |
2777 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2778 * 08| Send Timestamp |
2779 * 12| |
2780 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2781 * 16| Receive Timestamp |
2782 * 20| |
2783 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2784 * 24| TTL |
2785 * +-+-+-+-+-+-+-+-+-+
2786 *
2787 */
2788
2789 /*
2790 * Function: _OWPEncodeDataRecord
2791 *
2792 * Description:
2793 * This function is used to encode the 25 octet "packet record" from
2794 * the values in the given OWPDataRec. It returns false if the
2795 * timestamp err estimates are invalid values.
2796 *
2797 * In Args:
2798 *
2799 * Out Args:
2800 *
2801 * Scope:
2802 * Returns:
2803 * Side Effect:
2804 */
2805 OWPBoolean
_OWPEncodeDataRecord(char buf[25],OWPDataRec * rec)2806 _OWPEncodeDataRecord(
2807 char buf[25],
2808 OWPDataRec *rec
2809 )
2810 {
2811 uint32_t nlbuf;
2812
2813 memset(buf,0,25);
2814 nlbuf = htonl(rec->seq_no);
2815
2816 /* seq no */
2817 memcpy(&buf[0],&nlbuf,4);
2818
2819 /* send stamp */
2820 _OWPEncodeTimeStamp((uint8_t *)&buf[8],&rec->send);
2821
2822 /* send err */
2823 if(!_OWPEncodeTimeStampErrEstimate((uint8_t *)&buf[4],&rec->send)){
2824 return False;
2825 }
2826
2827 /* recv err */
2828 if(!_OWPEncodeTimeStampErrEstimate((uint8_t *)&buf[6],&rec->recv)){
2829 return False;
2830 }
2831
2832 /* recv stamp */
2833 _OWPEncodeTimeStamp((uint8_t *)&buf[16],&rec->recv);
2834
2835 buf[24] = rec->ttl;
2836
2837 return True;
2838 }
2839
2840 /*
2841 * Function: OWPDecodeDataRecord
2842 *
2843 * Description:
2844 * This function is used to decode the "packet record" and
2845 * place the values in the given OWPDataRec. It returns false if the
2846 * timestamp err estimates are invalid values.
2847 *
2848 * In Args:
2849 *
2850 * Out Args:
2851 *
2852 * Scope:
2853 * Returns:
2854 * Side Effect:
2855 */
2856 OWPBoolean
_OWPDecodeDataRecord(uint32_t file_version,OWPDataRec * rec,char * buf)2857 _OWPDecodeDataRecord(
2858 uint32_t file_version,
2859 OWPDataRec *rec,
2860 char *buf
2861 )
2862 {
2863 /*
2864 * Have to memcpy buf because it is not 32bit aligned.
2865 */
2866 memset(rec,0,sizeof(OWPDataRec));
2867 memcpy(&rec->seq_no,&buf[0],4);
2868 rec->seq_no = ntohl(rec->seq_no);
2869
2870 switch(file_version){
2871 case 0:
2872 case 2:
2873 _OWPDecodeTimeStamp(&rec->send,(uint8_t *)&buf[4]);
2874 if(!_OWPDecodeTimeStampErrEstimate(&rec->send,(uint8_t *)&buf[12])){
2875 return False;
2876 }
2877
2878 _OWPDecodeTimeStamp(&rec->recv,(uint8_t *)&buf[14]);
2879 if(!_OWPDecodeTimeStampErrEstimate(&rec->recv,(uint8_t *)&buf[22])){
2880 return False;
2881 }
2882
2883 rec->ttl = 255;
2884 break;
2885 case 3:
2886 _OWPDecodeTimeStamp(&rec->send,(uint8_t *)&buf[8]);
2887 if(!_OWPDecodeTimeStampErrEstimate(&rec->send,(uint8_t *)&buf[4])){
2888 return False;
2889 }
2890
2891 _OWPDecodeTimeStamp(&rec->recv,(uint8_t *)&buf[16]);
2892 if(!_OWPDecodeTimeStampErrEstimate(&rec->recv,(uint8_t *)&buf[6])){
2893 return False;
2894 }
2895
2896 rec->ttl = buf[24];
2897 break;
2898 default:
2899 return False;
2900 }
2901
2902 return True;
2903 }
2904