Logo Search packages:      
Sourcecode: l2tpd version File versions  Download package

avp.c

/*
 * $Id$
 *
 * Layer Two Tunnelling Protocol Daemon
 * Copyright (C) 1998 Adtran, Inc.
 * Copyright (C) 2002 Jeff McAdams
 * Copyright (C) 2003 Jean-Francois Dive
 *
 * Mark Spencer
 *
 * 12/2003  parsing sanitization, Jean-Francois Dive
 *
 * This software is distributed under the terms
 * of the GPL, which you should have received
 * along with this source.
 *
 * Attribute Value Pair handler routines
 */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <netinet/in.h>
#include "l2tp.h"

/* TODO: 
 * - Tie breaker.
 * - Clean Proxy Authentication solution.
 */

/*****************************************************************************/
struct avp avps[] = {
    {0, AVP_F_MANDATORY|AVP_F_FIXLEN, 2, {0}, &message_type_avp, &validate_msgtype_avp, "Message Type"},
    {1, AVP_F_MANDATORY, MAXSTRLEN, {CDN, StopCCN}, &result_code_avp, &validate_gen_avp, "Result Code"},
    {2, AVP_F_MANDATORY|AVP_F_FIXLEN, 2, {SCCRP, SCCRQ}, &protocol_version_avp, &validate_gen_avp, "Protocol Version"},
    {3, AVP_F_MANDATORY|AVP_F_FIXLEN, 4, {SCCRP, SCCRQ}, &framing_caps_avp, &validate_gen_avp, "Framing Capabilities"},
    {4, AVP_F_MANDATORY|AVP_F_FIXLEN, 4, {SCCRP, SCCRQ}, &bearer_caps_avp, &validate_gen_avp, "Bearer Capabilities"},
    {5, 0, 0, {0}, NULL, NULL, "Tie Breaker"},
    {6, AVP_F_FIXLEN, 2, {SCCRP, SCCRQ}, &firmware_rev_avp, &validate_gen_avp, "Firmware Revision"},
    {7, AVP_F_ASCII, MAXSTRLEN, {SCCRP, SCCRQ}, &hostname_avp, &validate_gen_avp, "Host Name"},
    {8, AVP_F_MANDATORY|AVP_F_ASCII, MAXSTRLEN, {SCCRP, SCCRQ}, &vendor_avp, &validate_gen_avp, "Vendor Name"},
    {9, AVP_F_MANDATORY|AVP_F_FIXLEN, 2, {SCCRP, SCCRQ, StopCCN}, &assigned_tunnel_avp, &validate_gen_avp, "Assigned Tunnel ID"},
    {10, AVP_F_MANDATORY|AVP_F_FIXLEN, 2,{SCCRP, SCCRQ, OCRP, OCCN, StopCCN}, &receive_window_size_avp, &validate_gen_avp, "Receive Window Size"},
    {11, AVP_F_MANDATORY, 128, {SCCRP, SCCRQ}, &challenge_avp, &validate_gen_avp, "Challenge"},
    {12, 0, 0, {0}, NULL, NULL, "Q.931 Cause Code"},
    {13, AVP_F_MANDATORY, MD_SIG_SIZE, {SCCRP, SCCCN}, &chalresp_avp, &validate_gen_avp, "Challenge Response"},
    {14, AVP_F_MANDATORY|AVP_F_FIXLEN, 2, {CDN, ICRP, ICRQ, OCRP, OCRQ}, &assigned_session_avp, &validate_gen_avp, "Assigned Session ID"},
    {15, AVP_F_MANDATORY|AVP_F_FIXLEN, 4, {ICRQ, OCRQ}, &call_serno_avp, &validate_gen_avp, "Call Serial Number"},
    {16, AVP_F_MANDATORY|AVP_F_FIXLEN, 4, {0}, NULL, NULL, "Minimum BPS"},
    {17, AVP_F_MANDATORY|AVP_F_FIXLEN, 4, {0}, NULL, NULL, "Maximum BPS"},
    {18, AVP_F_MANDATORY|AVP_F_FIXLEN, 4, {ICRQ, OCRQ}, &bearer_type_avp, &validate_gen_avp, "Bearer Type"},
    {19, AVP_F_MANDATORY|AVP_F_FIXLEN, 4, {ICCN, OCRQ, OCCN}, &frame_type_avp, &validate_gen_avp, "Framing Type"},
    {20, AVP_F_MANDATORY|AVP_F_FIXLEN, 2, {ICRP, OCRQ, ICCN, OCRP, OCCN}, &packet_delay_avp, &validate_gen_avp, "Packet Processing Delay"},
    {21, AVP_F_MANDATORY|AVP_F_ASCII, MAXSTRLEN, {ICRQ, OCRQ}, &called_number_avp, &validate_gen_avp, "Called Number"},
    {22, AVP_F_MANDATORY|AVP_F_ASCII, MAXSTRLEN, {ICRQ}, &calling_number_avp, &validate_gen_avp, "Calling Number"},
    {23, AVP_F_MANDATORY|AVP_F_ASCII, MAXSTRLEN, {OCRP, ICRQ}, &sub_address_avp, &validate_gen_avp, "Sub-Address"},
    {24, AVP_F_MANDATORY|AVP_F_FIXLEN, 4, {ICCN, OCCN, OCRP}, &tx_speed_avp, &validate_gen_avp, "Transmit Connect Speed"},
    {25, AVP_F_MANDATORY|AVP_F_FIXLEN, 4, {ICRQ, OCRQ, OCRP, OCCN}, &call_physchan_avp, &validate_gen_avp, "Physical channel ID"},
    {26, 0, 0, {0}, NULL, NULL, "Initial Received LCP Confreq"},
    {27, 0, 0, {0}, NULL, NULL, "Last Sent LCP Confreq"},
    {28, 0, 0, {0}, NULL, NULL, "Last Received LCP Confreq"},
    {29, AVP_F_MANDATORY, 0, {0}, &ignore_avp, NULL, "Proxy Authen Type"},
    {30, 0, 0, {0}, &ignore_avp, NULL, "Proxy Authen Name"},
    {31, 0, 0, {0}, &ignore_avp, NULL, "Proxy Authen Challenge"},
    {32, 0, 0, {0}, &ignore_avp, NULL, "Proxy Authen ID"},
    {33, AVP_F_MANDATORY, 0, {0}, &ignore_avp, NULL, "Proxy Authen Response"},
    {34, AVP_F_MANDATORY|AVP_F_FIXLEN, 26, {0}, NULL, NULL, "Call Errors"},
    {35, AVP_F_MANDATORY|AVP_F_FIXLEN, 10, {0}, &ignore_avp, NULL, "ACCM"},
    {36, AVP_F_MANDATORY, 1024, {0}, &rand_vector_avp, &validate_gen_avp, "Random Vector"},
    {37, AVP_F_MANDATORY, 0, {0}, NULL, NULL, "Private Group ID"},
    {38, AVP_F_FIXLEN, 4, {ICCN, OCCN, OCRP}, &rx_speed_avp, &validate_gen_avp, "Receive Connect Speed"},
    {39, AVP_F_MANDATORY, 0, {ICCN, OCCN, OCRP}, &seq_reqd_avp, &validate_gen_avp, "Sequencing Required"}
};

char *msgtypes[] = {
    NULL,
    "Start-Control-Connection-Request",
    "Start-Control-Connection-Reply",
    "Start-Control-Connection-Connected",
    "Stop-Control-Connection-Notification",
    NULL,
    "Hello",
    "Outgoing-Call-Request",
    "Outgoing-Call-Reply",
    "Outgoing-Call-Connected",
    "Incoming-Call-Request",
    "Incoming-Call-Reply",
    "Incoming-Call-Connected",
    NULL,
    "Call-Disconnect-Notify",
    "WAN-Error-Notify",
    "Set-Link-Info"
};

char *stopccn_result_codes[] = {
    "Reserved",
    "General request to clear control connection",
    "General error--Error Code indicates the problem",
    "Control channel already exists",
    "Requester is not authorized to establish a control channel",
    "The protocol version of the requester is not supported--Error Code indicates the highest version supported",
    "Requester is being shut down",
    "Finite State Machine error"
};

char *cdn_result_codes[] = {
    "Reserved",
    "Call disconnected due to loss of carrier",
    "Call disconnected for the reason indicated in error code",
    "Call disconnected for administrative reasons",
    "Call failed due to lack of appropriate facilities being available (temporary condition)",
    "Call failed due to lack of appropriate facilities being available (permanent condition)",
    "Invalid destination",
    "Call failed due to no carrier detected",
    "Call failed due to lack of a dial tone",
    "Call was no established within time allotted by LAC",
    "Call was connected but no appropriate framing was detect"
};

/*****************************************************************************/
void wrong_length (struct call *c, char *field, int expected, int found,
                   int min)
{
    if (min)
        snprintf (c->errormsg, sizeof (c->errormsg),
                  "%s: expected at least %d, got %d", field, expected, found);
    else
        snprintf (c->errormsg, sizeof (c->errormsg),
                  "%s: expected %d, got %d", field, expected, found);

    c->error = ERROR_LENGTH;
    c->result = RESULT_ERROR;
    c->needclose = -1;
}

/*****************************************************************************/
int validate_msgtype_avp(int attr,  struct tunnel *t, struct call *c, 
                                     void *data, int datalen)
{
    /*
     * This will be with every control message.  It is critical that this
     * procedure check for the validity of sending this kind of a message
     * (assuming sanity check)
     */

      u_int8_t *p = data + sizeof(struct avp_hdr);
      c->msgtype = get16(p);

    if (t->sanity)
    {
        /*
         * Look ou our state for each message and make sure everything
         * make sense...
         */
        if ((c != t->self) && (c->msgtype < Hello))
        {
            if (DEBUG)
                log (LOG_DEBUG,
                     "%s: attempting to negotiate tunnel inside a call!\n",
                     __func__);
            return -EINVAL;
        }

        switch (get16(p))
        {
        case SCCRQ:
            if ((t->state != 0) && (t->state != SCCRQ))
            {
                /*
                 * When we handle tie breaker AVP's, then we'll check
                 * to see if we've both requested tunnels
                 */

                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate SCCRQ with state != 0\n",
                         __func__);
                return -EINVAL;
            }
            break;
        case SCCRP:
            if (t->state != SCCRQ)
            {
                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate SCCRP with state != SCCRQ!\n",
                         __func__);
                return -EINVAL;
            }
            break;
        case SCCCN:
            if (t->state != SCCRP)
            {
                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate SCCCN with state != SCCRP!\n",
                         __func__);
                return -EINVAL;
            }
            break;
        case ICRQ:
            if (t->state != SCCCN)
            {
                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate ICRQ when state != SCCCN\n",
                         __func__);
                return -EINVAL;
            }
            if (c != t->self)
            {
                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate ICRQ on a call!\n",
                         __func__);
                return -EINVAL;
            }
            break;
        case ICRP:
            if (t->state != SCCCN)
            {
                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate ICRP on tunnel!=SCCCN\n",
                         __func__);
                return -EINVAL;
            }
            if (c->state != ICRQ)
            {
                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate ICRP when state != ICRQ\n",
                         __func__);
                return -EINVAL;
            }
            break;
        case ICCN:
            if (c->state != ICRP)
            {
                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate ICCN when state != ICRP\n",
                         __func__);
                return -EINVAL;
            }
            break;
        case SLI:
            if (c->state != ICCN)
            {
                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate SLI when state != ICCN\n",
                         __func__);
                return -EINVAL;
            }
            break;
        case OCRP:             /* jz: case for ORCP */
            if (t->state != SCCCN)
            {
                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate OCRP on tunnel!=SCCCN\n",
                         __func__);
                return -EINVAL;
            }
            if (c->state != OCRQ)
            {
                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate OCRP when state != OCRQ\n",
                         __func__);
                return -EINVAL;
            }
            break;
        case OCCN:             /* jz: case for OCCN */

            if (c->state != OCRQ)
            {
                if (DEBUG)
                    log (LOG_DEBUG,
                         "%s: attempting to negotiate OCCN when state != OCRQ\n",
                         __func__);
                return -EINVAL;
            }
            break;
        case StopCCN:
        case CDN:
        case Hello:
            break;
        default:
            log (LOG_WARN, "%s: unknown messages type %d\n",
                 __func__, get16(p));
            return -EINVAL;
        }
    }
      return 0;
}

/*****************************************************************************/
int validate_gen_avp(int attr,  struct tunnel *t, struct call *c, 
                               void *data, int datalen) {
      (void)data; (void)datalen;
      int i = 0, found = 0;

    if(t->sanity) {
            for(i = 0; i < 8; i++) {
                  if(c->msgtype == avps[attr].allowed_states[i])
                        found++;
            }
            if(!found) 
                  return -EINVAL;
      }
      return 0;
}

/* t, c, data, and datalen may be assumed to be defined for all avp's        */
/*****************************************************************************/
int ignore_avp (struct tunnel *t, struct call *c, void *data, int datalen)
{
    /*
     * The spec says we have to accept authentication information
     * even if we just ignore it, so that's exactly what
     * we're going to do at this point.  Proxy authentication is such
     * a rediculous security threat anyway except from local
     * controled machines.
     *
     * FIXME: I need to handle proxy authentication as an option.
     * One option is to simply change the options we pass to pppd.
     *
     */
    if (debug_avp)
      log (LOG_DEBUG, "%s : Ignoring AVP\n", __func__);
    return 0;
}

/*****************************************************************************/
int message_type_avp (struct tunnel *t, struct call *c, void *data,
                      int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
      
      if(!c->msgtype)
            c->msgtype = get16(p);

    if ((c->msgtype > MAX_MSG) || (!msgtypes[c->msgtype]))
    {
        log (LOG_DEBUG, "%s: unknown message type %d\n", __func__,
             c->msgtype);
        return -EINVAL;
    }
    if (debug_avp)
        log (LOG_DEBUG, "%s: message type %d (%s)\n", __func__,
             c->msgtype, msgtypes[c->msgtype]);
    if (c->msgtype == ICRQ)
    {
        struct call *tmp;
        if (debug_avp)
            log (LOG_DEBUG, "%s: new incoming call\n", __func__);
        tmp = new_call (t);
        if (!tmp)
        {
            log (LOG_WARN, "%s: unable to create new call\n", __func__);
            return -EINVAL;
        }
        tmp->next = t->call_head;
        t->call_head = tmp;
        t->count++;
        /*
         * Is this still safe to assume that the head will always
         * be the most recent call being negotiated?
         * Probably...  FIXME anyway...
         */
    }
    return 0;
}

/*****************************************************************************/
int rand_vector_avp (struct tunnel *t, struct call *c, void *data,
                     int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
      int datalen = avplen - sizeof(struct avp_hdr);
    if (debug_avp)
        log (LOG_DEBUG, "%s: random vector len %d\n", __func__, datalen);
    t->chal_us.vector = (unsigned char *)p;
    t->chal_us.vector_len = datalen;
    return 0;
}

/*****************************************************************************/
int seq_reqd_avp (struct tunnel *t, struct call *c, void *data, int datalen)
{
    if (debug_avp)
      log (LOG_DEBUG, "%s: peer requires sequencing.\n", __func__);
    c->seq_reqd = -1;
    return 0;
}

/*****************************************************************************/
int result_code_avp (struct tunnel *t, struct call *c, void *data,
                     int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
      int datalen = avplen - sizeof(struct avp_hdr);
    u_int16_t result = get16(p);
    u_int16_t error = get16(p + 2);

    if ((c->msgtype == StopCCN) && ((result > 7) || (result < 1)))
    {
        if (DEBUG)
            log (LOG_DEBUG,
                 "%s: (StopCCN) result code out of range ! (1 < %d < 7)\n",
                 __func__, result);
        return 0;
    }

    if ((c->msgtype == CDN) && ((result > 11) || (result < 1)))
    {
        if (DEBUG)
            log (LOG_DEBUG,
                 "%s: (CDN) result code out of range !(1 < %d < 11)\n",
                 __func__, result);
        return 0;
    }

    c->error = error;
    c->result = result;
      memcpy(c->errormsg, (char*)p + 4, datalen - 4);
      c->errormsg[datalen - 4] = '\0';

    if (debug_avp)
    {
        if(c->msgtype == StopCCN)
        {
            log (LOG_DEBUG,
                 "%s: peer closing for reason %d (%s), error = %d (%s)\n",
                 __func__, result, stopccn_result_codes[result], error,
                 c->errormsg);
        }
        else
        {
            log (LOG_DEBUG,
                 "%s: peer closing for reason %d (%s), error = %d (%s)\n",
                 __func__, result, cdn_result_codes[result], error,
                 c->errormsg);
        }
    }
    return 0;
}

/*****************************************************************************/
int protocol_version_avp (struct tunnel *t, struct call *c, void *data,
                          int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);

    if (debug_avp)
      log (LOG_DEBUG, "%s: peer is using version %d, revision %d.\n", 
                   __func__,*p, *(p+1));
    return 0;
}

/*****************************************************************************/
int framing_caps_avp (struct tunnel *t, struct call *c, void *data,
                      int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
    u_int16_t caps = get16(p + 2);

    if (debug_avp)
      log (LOG_DEBUG, "%s: supported peer frames:%s %s\n", __func__,
             caps & ASYNC_FRAMING ? "async" : "",
             caps & SYNC_FRAMING ? "sync" : "");

    t->fc = caps & (ASYNC_FRAMING | SYNC_FRAMING);
    return 0;
}

/*****************************************************************************/
int bearer_caps_avp (struct tunnel *t, struct call *c, void *data,
                     int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
    u_int16_t caps = get16(p + 2);

    if (debug_avp)
      log (LOG_DEBUG, "%s: supported peer bearers:%s %s\n",
              __func__,
              caps & ANALOG_BEARER ? "analog" : "",
              caps & DIGITAL_BEARER ? "digital" : "");

    t->bc = caps & (ANALOG_BEARER | DIGITAL_BEARER);
    return 0;
}

/*****************************************************************************/
int firmware_rev_avp (struct tunnel *t, struct call *c, void *data,
                      int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);

    t->firmware = get16(p);
    if (debug_avp)
      log (LOG_DEBUG, "%s: peer reports firmware version %d (0x%.4X)\n",
              __func__, t->firmware, t->firmware);
    return 0;
}

/*****************************************************************************/
int bearer_type_avp (struct tunnel *t, struct call *c, void *data,
                     int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);

      t->call_head->bearer = get16(p + 2);
    if (debug_avp)
      log (LOG_DEBUG, "%s: peer bears: %s\n", __func__,
             (t->call_head->bearer & ANALOG_BEARER) ? "analog" : "digital");
    return 0;
}

/*****************************************************************************/
int frame_type_avp (struct tunnel *t, struct call *c, void *data, int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);

      c->frame = get16(p + 2);
    if (debug_avp)
      log (LOG_DEBUG, "%s: peer uses:%s frames\n", __func__,
             (c->frame & ASYNC_FRAMING) ? "async" : "sync");
    return 0;
}

/*****************************************************************************/
int hostname_avp (struct tunnel *t, struct call *c, void *data, int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
      int datalen = avplen - sizeof(struct avp_hdr);

    memcpy(t->hostname, p, datalen);
      t->hostname[datalen] = '\0';

    if (debug_avp)
      log (LOG_DEBUG, "%s: peer reports hostname '%s'\n", __func__,
             t->hostname);

    return 0;
}

/*****************************************************************************/
int calling_number_avp (struct tunnel *t, struct call *c, void *data,
                        int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
      int datalen = avplen - sizeof(struct avp_hdr);

    memcpy(t->call_head->dialing, p, datalen);
      t->call_head->dialing[datalen] = '\0';

    if (debug_avp)
      log (LOG_DEBUG, "%s: peer reports dialing number '%s'\n", __func__,
             t->call_head->dialing);

    return 0;
}

/*****************************************************************************/
int called_number_avp (struct tunnel *t, struct call *c, void *data,
                       int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
      int datalen = avplen - sizeof(struct avp_hdr);

    memcpy(t->call_head->dialed, p, datalen);
      t->call_head->dialed[datalen] = '\0';

    if (debug_avp)
      log (LOG_DEBUG, "%s: peer reports dialed number '%s'\n", __func__,
             t->call_head->dialed);

    return 0;
}

/*****************************************************************************/
int sub_address_avp (struct tunnel *t, struct call *c, void *data,
                     int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
      int datalen = avplen - sizeof(struct avp_hdr);

      memcpy(t->call_head->subaddy, p, datalen);
      t->call_head->subaddy[datalen] = '\0';

    if (debug_avp)
      log (LOG_DEBUG, "%s: peer reports subaddress '%s'\n", __func__,
             t->call_head->subaddy);
    return 0;
}

/*****************************************************************************/
int vendor_avp (struct tunnel *t, struct call *c, void *data, int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
      int datalen = avplen - sizeof(struct avp_hdr);

      memcpy(t->vendor, p, datalen);
      t->vendor[datalen] = '\0';

    if (debug_avp)
      log (LOG_DEBUG, "%s: peer reports vendor '%s'\n", __func__, t->vendor);
    return 0;
}

/*****************************************************************************/
int challenge_avp (struct tunnel *t, struct call *c, void *data, int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
      int datalen = avplen - sizeof(struct avp_hdr);

    t->chal_us.challenge = calloc(datalen, 1);
    if (!t->chal_us.challenge)
        return -ENOMEM;
    memcpy(t->chal_us.challenge, p, datalen);
    t->chal_us.state = STATE_CHALLENGED;

    if (debug_avp)
      log (LOG_DEBUG, "%s: challenge avp found\n", __func__);

    return 0;
}

/*****************************************************************************/
int chalresp_avp (struct tunnel *t, struct call *c, void *data, int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);

    memcpy(t->chal_them.reply, p, MD_SIG_SIZE);
    if(debug_avp)
      log(LOG_DEBUG, "%s: Challenge reply found\n", __func__);
    return 0;
}

/*****************************************************************************/
int assigned_tunnel_avp (struct tunnel *t, struct call *c, void *data,
                         int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
      u_int16_t id = get16(p);

    if (c->msgtype == StopCCN)
        t->qtid = id;
    else
        t->tid = id;
    if (debug_avp)
      log (LOG_DEBUG, "%s: using peer's tunnel %d\n", __func__, id);
    return 0;
}

/*****************************************************************************/
int assigned_session_avp (struct tunnel *t, struct call *c, void *data,
                       int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);
      u_int16_t id = get16(p);

      switch(c->msgtype) {
            case CDN:
            case ICRP:
            case OCRP:
                  c->cid = id;
                  break;
            case ICRQ:
                  t->call_head->cid = id;
                  break;
      };

    if (debug_avp)
      log (LOG_DEBUG, "%s: assigned session id: %d\n", __func__, id);
    return 0;
}

/*****************************************************************************/
int packet_delay_avp (struct tunnel *t, struct call *c, void *data,
                      int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);

    c->ppd = get16(p);
    if (debug_avp)
      log (LOG_DEBUG, "%s: peer's delay is %d 1/10's of a second\n", __func__,
             c->ppd);
    return 0;
}

/*****************************************************************************/
int call_serno_avp (struct tunnel *t, struct call *c, void *data, int avplen)
{
    /*
     * What is the serial number of the call?
     */
      u_int8_t *p = data + sizeof(struct avp_hdr);

    t->call_head->serno = get32(p);
    if (debug_avp)
      log (LOG_DEBUG, "%s: serial number is %d\n", __func__, 
                   t->call_head->serno);
    return 0;
}

/*****************************************************************************/
int rx_speed_avp (struct tunnel *t, struct call *c, void *data, int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);

    c->rxspeed = get32(p);
    if(debug_avp)
      log(LOG_DEBUG, "%s: receive baud rate is %d\n", __func__, c->rxspeed);
    return 0;
}

/*****************************************************************************/
int tx_speed_avp (struct tunnel *t, struct call *c, void *data, int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);

    c->txspeed = get32(p);
    if (debug_avp)
      log (LOG_DEBUG, "%s: transmit baud rate is %d\n", 
                   __func__, c->txspeed);
    return 0;
}

/*****************************************************************************/
int call_physchan_avp (struct tunnel *t, struct call *c, void *data,
                       int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);

    t->call_head->physchan = get32(p);
    if (debug_avp)
      log(LOG_DEBUG, "%s: physical channel is %d\n", __func__,
                  t->call_head->physchan);
    return 0;
}

/*****************************************************************************/
int receive_window_size_avp (struct tunnel *t, struct call *c, void *data,
                             int avplen)
{
      u_int8_t *p = data + sizeof(struct avp_hdr);

    t->rws = get16(p);
/*    if (c->rws >= 0)
            c->fbit = FBIT; */
    if (debug_avp)
            log (LOG_DEBUG, "%s: peer wants RWS of %d.  Will use flow control.\n",
             __func__, t->rws);
    return 0;
}


/*****************************************************************************/
int handle_avps (struct buffer *buf, struct tunnel *t, struct call *c)
{
    /*
     * buf's start should point to the beginning of a packet. We assume it's
     * a valid packet and has had check_control done to it, so no error
     * checking is done at this point.
     */

    struct avp_hdr *avp;
    int len = buf->len - sizeof (struct control_hdr);
      u_int16_t rlen = 0;
      u_int16_t attr = 0;
    int firstavp = -1;
    int hidlen = 0;
    char *data = buf->start + sizeof (struct control_hdr);
    avp = (struct avp_hdr *) data;

    if (debug_avp)
        log (LOG_DEBUG, "%s: handling avp's for tunnel %d, call %d\n",
             __func__, t->ourtid, c->ourcid);

      if(len < 6) {
      log (LOG_WARN, "%s: packet too small\n", __func__);
        set_error(c, ERROR_LENGTH, "Invalid message length");
        return -EINVAL;
      }

    while (len > 0)
    {
            rlen = get16((u_int8_t*)&avp->length);
            attr = get16((u_int8_t*)&avp->attr);

            /* AVP header checks */
        if (attr > AVP_MAX)
        {
            if (AMBIT(rlen))
            {
                log (LOG_WARN,
                     "%s:  unhandeled mandatory attribute %d.  Closing %s.\n", 
                     __func__, attr, (c != t->self) ? "call" : "tunnel");
                set_error (c, VENDOR_ERROR, 
                                       "mandatory attribute %d cannot be handled", attr);
                return -EINVAL;
            }
            else
            {
                if (DEBUG)
                    log (LOG_WARN,
                         "%s: handeled attribute %d.\n",
                         __func__, attr);
                goto next;
            }
        }
        if (ALENGTH (rlen) > len)
        {
            log (LOG_WARN,
                 "%s: AVP reported length > remaining packet length\n",
                 __func__);
            set_error (c, ERROR_LENGTH, "Invalid AVP length");
            return -EINVAL;
        }
            if (ALENGTH (rlen) < sizeof (struct avp_hdr))
        {
            log (LOG_WARN, "%s: AVP reported length too small (%d).\n",
                 __func__, ALENGTH (rlen));
            set_error (c, ERROR_LENGTH, "AVP too small");
            return -EINVAL;
        }
            if (avps[attr].sz) {
                  if((avps[attr].flags & AVP_F_FIXLEN) ?  
                     (ALENGTH(rlen) - sizeof(struct avp_hdr)) != avps[attr].sz :
                     (ALENGTH(rlen) - sizeof(struct avp_hdr)) > avps[attr].sz) {
                        log (LOG_DEBUG, "%s: %s avp size mismatch  (%d %s %d)\n", 
                              __func__,
                              avps[attr].description, 
                              (avps[attr].flags & AVP_F_FIXLEN) ? "!=" : "<", 
                              ALENGTH(rlen), avps[attr].sz);
                        set_error (c, ERROR_LENGTH, "AVP size check failed");
                        return -EINVAL;
                  }
            }
        if (attr && firstavp)
        {
            log (LOG_WARN, "%s: First AVP was not message type.\n",
                 __func__);
            set_error (c, VENDOR_ERROR, "First AVP must be message type");
            return -EINVAL;
        }
        if (AZBITS (rlen))
        {
            log (LOG_WARN, "%s: %sAVP has reserved bits set.\n", __func__,
                 AMBIT (rlen) ? "Mandatory " : "");
            if (AMBIT (rlen))
            {
                set_error (c, ERROR_RESERVED, "reserved bits set in AVP");
                return -EINVAL;
            }
            goto next;
        }

            /* decryption */
        if (AHBIT (rlen))
        {
            log (LOG_DEBUG, "%s: Hidden bit set on AVP.\n", __func__);
            /* We want to rewrite the AVP as an unhidden AVP
               and then pass it along as normal.  Remeber how
               long the AVP was in the first place though! */
            hidlen = avp->length;
            if (decrypt_avp (data, t))
            {
                if (debug_avp)
                    log (LOG_WARN, "%s: Unable to handle hidden %sAVP\n:",
                         __func__,
                         (AMBIT (rlen) ? "mandatory " : ""));
                if (AMBIT (rlen))
                {
                    set_error (c, VENDOR_ERROR, "Invalid Hidden AVP");
                    return -EINVAL;
                }
                goto next;
            };
            len -= 2;
            hidlen -= 2;
            data += 2;
            avp = (struct avp_hdr *) data;
            /* Now we should look like a normal AVP */
        }
        else
            hidlen = 0;

            /* validate */
            if (avps[attr].validate) 
            {
                  if(avps[attr].validate(attr, t, c, avp, ALENGTH (rlen))) {
                         if (AMBIT (rlen))
                {
                    log (LOG_WARN,
                         "%s: verification of AVP %d (%s) failed.\n",
                         __func__, attr,
                         avps[attr].description);
                              set_error (c, VENDOR_ERROR, "processing failed on mandatory AVP");
                    return -EINVAL;
                }
                else
                {
                    if (DEBUG)
                        log (LOG_DEBUG,
                             "%s: Bad exit status handling attribute %d (%s).\n",
                             __func__, attr,
                             avps[attr].description);
                }
                  }
            }

            /* handling */
        if (avps[attr].handle)
        {
            if (avps[attr].handle(t, c, avp, ALENGTH (rlen)))
            {
                if (AMBIT (rlen))
                {
                    log (LOG_WARN,
                         "%s: Bad exit status handling mandatory attribute %d (%s).\n",
                         __func__, attr,
                         avps[attr].description);
                              set_error (c, VENDOR_ERROR, "processing failed on mandatory AVP");
                    return -EINVAL;
                }
                else
                {
                    if (DEBUG)
                        log (LOG_DEBUG,
                             "%s: Bad exit status handling attribute %d (%s).\n",
                             __func__, attr,
                             avps[attr].description);
                }
            }
        }
        else
        {
            if (AMBIT (rlen))
            {
                log (LOG_WARN,
                     "%s:  No handler for mandatory attribute %d (%s).  Closing %s.\n",
                     __func__, attr, 
                               avps[attr].description,
                     (c != t->self) ? "call" : "tunnel");
                set_error (c, VENDOR_ERROR, "No handler for attr %d (%s)\n",
                           attr, 
                                       avps[attr].description);
                return -EINVAL;
            }
            else
            {
                if (DEBUG)
                    log (LOG_WARN, "%s:  no handler for atribute %d (%s).\n",
                         __func__, attr,
                         avps[attr].description);
            }
        }
      next:
        if (hidlen)
        {
            /* Skip over the complete length of the hidden AVP */
            len -= ALENGTH (hidlen);
            data += ALENGTH (hidlen);
        }
        else
        {
            len -= ALENGTH (rlen);
            data += ALENGTH (rlen);      /* Next AVP, please */
        }
        avp = (struct avp_hdr *) data;
        firstavp = 0;
    }
    if (len != 0)
    {
        log (LOG_WARN, "%s: negative overall packet length\n", __func__);
        return -EINVAL;
    }

    return 0;
}

Generated by  Doxygen 1.6.0   Back to index