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