Annotation of embedaddon/strongswan/src/libimcv/ietf/swima/ietf_swima_attr_sw_ev.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2017 Andreas Steffen
        !             3:  * HSR Hochschule fuer Technik Rapperswil
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify it
        !             6:  * under the terms of the GNU General Public License as published by the
        !             7:  * Free Software Foundation; either version 2 of the License, or (at your
        !             8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !             9:  *
        !            10:  * This program is distributed in the hope that it will be useful, but
        !            11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            13:  * for more details.
        !            14:  */
        !            15: 
        !            16: #include "ietf_swima_attr_sw_ev.h"
        !            17: #include "swima/swima_event.h"
        !            18: 
        !            19: #include <pa_tnc/pa_tnc_msg.h>
        !            20: #include <bio/bio_writer.h>
        !            21: #include <bio/bio_reader.h>
        !            22: #include <utils/debug.h>
        !            23: 
        !            24: #define SW_EV_TIMESTAMP_SIZE   20
        !            25: 
        !            26: typedef struct private_ietf_swima_attr_sw_ev_t private_ietf_swima_attr_sw_ev_t;
        !            27: 
        !            28: /**
        !            29:  * Software [Identifier] Events
        !            30:  * see sections 5.9/5.11 of RFC 8412 SWIMA
        !            31:  *
        !            32:  *                       1                   2                   3
        !            33:  *   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
        !            34:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            35:  *  |     Flags     |           Software Identifier Count           |
        !            36:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            37:  *  |               Request ID Copy / Subscription ID               |
        !            38:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            39:  *  |                           EID Epoch                           |
        !            40:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            41:  *  |                           Last EID                            |
        !            42:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            43:  *  |                       Last Consulted EID                      |
        !            44:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            45:  *  |                              EID                              |
        !            46:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            47:  *  |                           Timestamp                           |
        !            48:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            49:  *  |                           Timestamp                           |
        !            50:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            51:  *  |                           Timestamp                           |
        !            52:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            53:  *  |                           Timestamp                           |
        !            54:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            55:  *  |                           Timestamp                           |
        !            56:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            57:  *  |                       Record Identifier                       |
        !            58:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            59:  *  |              Data Model Type PEN              |Data Model Type|
        !            60:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            61:  *  | Source ID Num |    Action     |  Software Identifier Length   |
        !            62:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            63:  *  |             Software Identifier (Variable Length)             |
        !            64:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            65:  *  |    Software Locator Length    |  Software Locator (Var. Len)  |
        !            66:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            67:  *
        !            68:  * Software Event only
        !            69:  * see section 5.11 of IETF SW Inventory Message and Attributes for PA-TNC
        !            70:  *
        !            71:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            72:  *  |                          Record Length                        |
        !            73:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            74:  *  |                   Record (Variable length)                    |
        !            75:  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        !            76:  */
        !            77: 
        !            78: /**
        !            79:  * Private data of an ietf_swima_attr_sw_ev_t object.
        !            80:  */
        !            81: struct private_ietf_swima_attr_sw_ev_t {
        !            82: 
        !            83:        /**
        !            84:         * Public members of ietf_swima_attr_sw_ev_t
        !            85:         */
        !            86:        ietf_swima_attr_sw_ev_t public;
        !            87: 
        !            88:        /**
        !            89:         * Vendor-specific attribute type
        !            90:         */
        !            91:        pen_type_t type;
        !            92: 
        !            93:        /**
        !            94:         * Length of attribute value
        !            95:         */
        !            96:        size_t length;
        !            97: 
        !            98:        /**
        !            99:         * Offset up to which attribute value has been processed
        !           100:         */
        !           101:        size_t offset;
        !           102: 
        !           103:        /**
        !           104:         * Current position of attribute value pointer
        !           105:         */
        !           106:        chunk_t value;
        !           107: 
        !           108:        /**
        !           109:         * Contains complete attribute or current segment
        !           110:         */
        !           111:        chunk_t segment;
        !           112: 
        !           113:        /**
        !           114:         * Noskip flag
        !           115:         */
        !           116:        bool noskip_flag;
        !           117: 
        !           118:        /**
        !           119:         * Request ID
        !           120:         */
        !           121:        uint32_t request_id;
        !           122: 
        !           123:        /**
        !           124:         * Attribute flags
        !           125:         */
        !           126:        uint8_t flags;
        !           127: 
        !           128:        /**
        !           129:         * Number of unprocessed software events in attribute
        !           130:         */
        !           131:        uint32_t event_count;
        !           132: 
        !           133:        /**
        !           134:         * Event list
        !           135:         */
        !           136:        swima_events_t *events;
        !           137: 
        !           138:        /**
        !           139:         * Reference count
        !           140:         */
        !           141:        refcount_t ref;
        !           142: };
        !           143: 
        !           144: METHOD(pa_tnc_attr_t, get_type, pen_type_t,
        !           145:        private_ietf_swima_attr_sw_ev_t *this)
        !           146: {
        !           147:        return this->type;
        !           148: }
        !           149: 
        !           150: METHOD(pa_tnc_attr_t, get_value, chunk_t,
        !           151:        private_ietf_swima_attr_sw_ev_t *this)
        !           152: {
        !           153:        return this->value;
        !           154: }
        !           155: 
        !           156: METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
        !           157:        private_ietf_swima_attr_sw_ev_t *this)
        !           158: {
        !           159:        return this->noskip_flag;
        !           160: }
        !           161: 
        !           162: METHOD(pa_tnc_attr_t, set_noskip_flag,void,
        !           163:        private_ietf_swima_attr_sw_ev_t *this, bool noskip)
        !           164: {
        !           165:        this->noskip_flag = noskip;
        !           166: }
        !           167: 
        !           168: /**
        !           169:  * This function is shared with ietf_swima_attr_sw_inv.c
        !           170:  **/
        !           171: void ietf_swima_attr_sw_ev_build_sw_record(bio_writer_t *writer,
        !           172:                uint8_t action, swima_record_t *sw_record, bool has_record)
        !           173: {
        !           174:        pen_type_t data_model;
        !           175:        chunk_t sw_locator;
        !           176: 
        !           177:        data_model = sw_record->get_data_model(sw_record);
        !           178: 
        !           179:        writer->write_uint32(writer, sw_record->get_record_id(sw_record));
        !           180:        writer->write_uint24(writer, data_model.vendor_id);
        !           181:        writer->write_uint8 (writer, data_model.type);
        !           182:        writer->write_uint8 (writer, sw_record->get_source_id(sw_record));
        !           183:        writer->write_uint8 (writer, action);
        !           184:        writer->write_data16(writer, sw_record->get_sw_id(sw_record, &sw_locator));
        !           185:        writer->write_data16(writer, sw_locator);
        !           186: 
        !           187:        if (has_record)
        !           188:        {
        !           189:                writer->write_data32(writer, sw_record->get_record(sw_record));
        !           190:        }
        !           191: }
        !           192: 
        !           193: METHOD(pa_tnc_attr_t, build, void,
        !           194:        private_ietf_swima_attr_sw_ev_t *this)
        !           195: {
        !           196:        bio_writer_t *writer;
        !           197:        swima_event_t *sw_event;
        !           198:        swima_record_t *sw_record;
        !           199:        chunk_t timestamp;
        !           200:        uint32_t last_eid, last_consulted_eid, eid_epoch;
        !           201:        uint8_t action;
        !           202:        enumerator_t *enumerator;
        !           203: 
        !           204:        if (this->value.ptr)
        !           205:        {
        !           206:                return;
        !           207:        }
        !           208:        last_consulted_eid = this->events->get_eid(this->events, &eid_epoch,
        !           209:                                                                                                                         &last_eid);
        !           210: 
        !           211:        writer = bio_writer_create(IETF_SWIMA_SW_EV_MIN_SIZE);
        !           212:        writer->write_uint8 (writer, this->flags);
        !           213:        writer->write_uint24(writer, this->events->get_count(this->events));
        !           214:        writer->write_uint32(writer, this->request_id);
        !           215:        writer->write_uint32(writer, eid_epoch);
        !           216:        writer->write_uint32(writer, last_eid);
        !           217:        writer->write_uint32(writer, last_consulted_eid);
        !           218: 
        !           219:        enumerator = this->events->create_enumerator(this->events);
        !           220:        while (enumerator->enumerate(enumerator, &sw_event))
        !           221:        {
        !           222:                action     = sw_event->get_action(sw_event);
        !           223:                sw_record  = sw_event->get_sw_record(sw_event);
        !           224: 
        !           225:                writer->write_uint32(writer, sw_event->get_eid(sw_event, &timestamp));
        !           226:                writer->write_data  (writer, timestamp);
        !           227: 
        !           228:                ietf_swima_attr_sw_ev_build_sw_record(writer, action, sw_record,
        !           229:                                                                this->type.type == IETF_ATTR_SW_EVENTS);
        !           230:        }
        !           231:        enumerator->destroy(enumerator);
        !           232: 
        !           233:        this->value = writer->extract_buf(writer);
        !           234:        this->segment = this->value;
        !           235:        this->length = this->value.len;
        !           236:        writer->destroy(writer);
        !           237: }
        !           238: 
        !           239: /**
        !           240:  * This function is shared with ietf_swima_attr_sw_inv.c
        !           241:  **/
        !           242: bool ietf_swima_attr_sw_ev_process_sw_record(bio_reader_t *reader,
        !           243:                uint8_t *action, swima_record_t **sw_record, bool has_record)
        !           244: {
        !           245:        pen_type_t data_model;
        !           246:        swima_record_t *sw_rec;
        !           247:        uint32_t data_model_pen, record_id;
        !           248:        uint8_t  data_model_type, source_id, reserved;
        !           249:        chunk_t sw_id, sw_locator, record = chunk_empty;
        !           250: 
        !           251:        if (!reader->read_uint32(reader, &record_id) ||
        !           252:                !reader->read_uint24(reader, &data_model_pen) ||
        !           253:                !reader->read_uint8 (reader, &data_model_type) ||
        !           254:                !reader->read_uint8 (reader, &source_id) ||
        !           255:                !reader->read_uint8 (reader, &reserved) ||
        !           256:                !reader->read_data16(reader, &sw_id) ||
        !           257:                !reader->read_data16(reader, &sw_locator))
        !           258:        {
        !           259:                return FALSE;
        !           260:        }
        !           261: 
        !           262:        if (action)
        !           263:        {
        !           264:                *action = reserved;
        !           265:        }
        !           266: 
        !           267:        if (has_record && !reader->read_data32(reader, &record))
        !           268:        {
        !           269:                return FALSE;
        !           270:        }
        !           271: 
        !           272:        data_model = pen_type_create(data_model_pen, data_model_type);
        !           273:        sw_rec = swima_record_create(record_id, sw_id, sw_locator);
        !           274:        sw_rec->set_data_model(sw_rec, data_model);
        !           275:        sw_rec->set_source_id(sw_rec, source_id);
        !           276:        sw_rec->set_record(sw_rec, record);
        !           277:        *sw_record = sw_rec;
        !           278: 
        !           279:        return TRUE;
        !           280: }
        !           281: 
        !           282: METHOD(pa_tnc_attr_t, process, status_t,
        !           283:        private_ietf_swima_attr_sw_ev_t *this, uint32_t *offset)
        !           284: {
        !           285:        bio_reader_t *reader;
        !           286:        uint32_t eid, eid_epoch, last_eid, last_consulted_eid;
        !           287:        uint8_t  action;
        !           288:        chunk_t timestamp;
        !           289:        swima_event_t *sw_event;
        !           290:        swima_record_t *sw_record;
        !           291:        status_t status = NEED_MORE;
        !           292: 
        !           293:        if (this->offset == 0)
        !           294:        {
        !           295:                if (this->length < IETF_SWIMA_SW_EV_MIN_SIZE)
        !           296:                {
        !           297:                        DBG1(DBG_TNC, "insufficient data for %N/%N", pen_names, PEN_IETF,
        !           298:                                                   ietf_attr_names, this->type.type);
        !           299:                        *offset = this->offset;
        !           300:                        return FAILED;
        !           301:                }
        !           302:                if (this->value.len < IETF_SWIMA_SW_EV_MIN_SIZE)
        !           303:                {
        !           304:                        return NEED_MORE;
        !           305:                }
        !           306:                reader = bio_reader_create(this->value);
        !           307:                reader->read_uint8 (reader, &this->flags);
        !           308:                reader->read_uint24(reader, &this->event_count);
        !           309:                reader->read_uint32(reader, &this->request_id);
        !           310:                reader->read_uint32(reader, &eid_epoch);
        !           311:                reader->read_uint32(reader, &last_eid);
        !           312:                reader->read_uint32(reader, &last_consulted_eid);
        !           313:                this->offset = IETF_SWIMA_SW_EV_MIN_SIZE;
        !           314:                this->events->set_eid(this->events, last_consulted_eid, eid_epoch);
        !           315:                this->events->set_last_eid(this->events, last_eid);
        !           316:                this->value = reader->peek(reader);
        !           317:                reader->destroy(reader);
        !           318:        }
        !           319: 
        !           320:        reader = bio_reader_create(this->value);
        !           321: 
        !           322:        while (this->event_count)
        !           323:        {
        !           324:                if (!reader->read_uint32(reader, &eid) ||
        !           325:                        !reader->read_data  (reader, SW_EV_TIMESTAMP_SIZE, &timestamp) ||
        !           326:                        !ietf_swima_attr_sw_ev_process_sw_record(reader, &action, &sw_record,
        !           327:                                                                this->type.type == IETF_ATTR_SW_EVENTS))
        !           328:                {
        !           329:                        goto end;
        !           330:                }
        !           331: 
        !           332:                if (action == SWIMA_EVENT_ACTION_NONE ||
        !           333:                        action  > SWIMA_EVENT_ACTION_LAST)
        !           334:                {
        !           335:                        DBG1(DBG_TNC, "invalid event action value for %N/%N", pen_names,
        !           336:                                                   PEN_IETF, ietf_attr_names, this->type.type);
        !           337:                        *offset = this->offset;
        !           338:                        sw_record->destroy(sw_record);
        !           339:                        reader->destroy(reader);
        !           340: 
        !           341:                        return FAILED;
        !           342:                }
        !           343: 
        !           344:                sw_event = swima_event_create(eid, timestamp, action, sw_record);
        !           345:                this->events->add(this->events, sw_event);
        !           346:                this->offset += this->value.len - reader->remaining(reader);
        !           347:                this->value = reader->peek(reader);
        !           348: 
        !           349:                /* at least one software event was processed */
        !           350:                status = SUCCESS;
        !           351:                this->event_count--;
        !           352:        }
        !           353: 
        !           354:        if (this->length == this->offset)
        !           355:        {
        !           356:                status = SUCCESS;
        !           357:        }
        !           358:        else
        !           359:        {
        !           360:                DBG1(DBG_TNC, "inconsistent length for %N/%N", pen_names, PEN_IETF,
        !           361:                                           ietf_attr_names, this->type.type);
        !           362:                *offset = this->offset;
        !           363:                status = FAILED;
        !           364:        }
        !           365: 
        !           366: end:
        !           367:        reader->destroy(reader);
        !           368:        return status;
        !           369: }
        !           370: 
        !           371: METHOD(pa_tnc_attr_t, add_segment, void,
        !           372:        private_ietf_swima_attr_sw_ev_t *this, chunk_t segment)
        !           373: {
        !           374:        this->value = chunk_cat("cc", this->value, segment);
        !           375:        chunk_free(&this->segment);
        !           376:        this->segment = this->value;
        !           377: }
        !           378: 
        !           379: METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
        !           380:        private_ietf_swima_attr_sw_ev_t *this)
        !           381: {
        !           382:        ref_get(&this->ref);
        !           383:        return &this->public.pa_tnc_attribute;
        !           384: }
        !           385: 
        !           386: METHOD(pa_tnc_attr_t, destroy, void,
        !           387:        private_ietf_swima_attr_sw_ev_t *this)
        !           388: {
        !           389:        if (ref_put(&this->ref))
        !           390:        {
        !           391:                this->events->destroy(this->events);
        !           392:                free(this->segment.ptr);
        !           393:                free(this);
        !           394:        }
        !           395: }
        !           396: 
        !           397: METHOD(ietf_swima_attr_sw_ev_t, get_flags, uint8_t,
        !           398:        private_ietf_swima_attr_sw_ev_t *this)
        !           399: {
        !           400:        return this->flags;
        !           401: }
        !           402: 
        !           403: METHOD(ietf_swima_attr_sw_ev_t, get_request_id, uint32_t,
        !           404:        private_ietf_swima_attr_sw_ev_t *this)
        !           405: {
        !           406:        return this->request_id;
        !           407: }
        !           408: 
        !           409: METHOD(ietf_swima_attr_sw_ev_t, get_event_count, uint32_t,
        !           410:        private_ietf_swima_attr_sw_ev_t *this)
        !           411: {
        !           412:        return this->event_count;
        !           413: }
        !           414: 
        !           415: METHOD(ietf_swima_attr_sw_ev_t, set_events, void,
        !           416:        private_ietf_swima_attr_sw_ev_t *this, swima_events_t *events)
        !           417: {
        !           418:        this->events->destroy(this->events);
        !           419:        this->events = events->get_ref(events);
        !           420: }
        !           421: 
        !           422: METHOD(ietf_swima_attr_sw_ev_t, get_events, swima_events_t*,
        !           423:        private_ietf_swima_attr_sw_ev_t *this)
        !           424: {
        !           425:        return this->events;
        !           426: }
        !           427: 
        !           428: METHOD(ietf_swima_attr_sw_ev_t, clear_events, void,
        !           429:        private_ietf_swima_attr_sw_ev_t *this)
        !           430: {
        !           431:        this->events->clear(this->events);
        !           432: }
        !           433: 
        !           434: /**
        !           435:  * Described in header.
        !           436:  */
        !           437: pa_tnc_attr_t *ietf_swima_attr_sw_ev_create(uint8_t flags, uint32_t request_id,
        !           438:                                                                                         bool sw_id_only)
        !           439: {
        !           440:        private_ietf_swima_attr_sw_ev_t *this;
        !           441:        ietf_attr_t type;
        !           442: 
        !           443:        type = sw_id_only ? IETF_ATTR_SW_ID_EVENTS : IETF_ATTR_SW_EVENTS;
        !           444: 
        !           445:        INIT(this,
        !           446:                .public = {
        !           447:                        .pa_tnc_attribute = {
        !           448:                                .get_type = _get_type,
        !           449:                                .get_value = _get_value,
        !           450:                                .get_noskip_flag = _get_noskip_flag,
        !           451:                                .set_noskip_flag = _set_noskip_flag,
        !           452:                                .build = _build,
        !           453:                                .process = _process,
        !           454:                                .add_segment = _add_segment,
        !           455:                                .get_ref = _get_ref,
        !           456:                                .destroy = _destroy,
        !           457:                        },
        !           458:                        .get_flags = _get_flags,
        !           459:                        .get_request_id = _get_request_id,
        !           460:                        .get_event_count = _get_event_count,
        !           461:                        .set_events = _set_events,
        !           462:                        .get_events = _get_events,
        !           463:                        .clear_events = _clear_events,
        !           464:                },
        !           465:                .type = { PEN_IETF, type },
        !           466:                .flags = flags,
        !           467:                .request_id = request_id,
        !           468:                .events = swima_events_create(),
        !           469:                .ref = 1,
        !           470:        );
        !           471: 
        !           472:        return &this->public.pa_tnc_attribute;
        !           473: }
        !           474: 
        !           475: 
        !           476: /**
        !           477:  * Described in header.
        !           478:  */
        !           479: pa_tnc_attr_t *ietf_swima_attr_sw_ev_create_from_data(size_t length,
        !           480:                                                                                chunk_t data, bool sw_id_only)
        !           481: {
        !           482:        private_ietf_swima_attr_sw_ev_t *this;
        !           483:        ietf_attr_t type;
        !           484: 
        !           485:        type = sw_id_only ? IETF_ATTR_SW_ID_EVENTS : IETF_ATTR_SW_EVENTS;
        !           486: 
        !           487:        INIT(this,
        !           488:                .public = {
        !           489:                        .pa_tnc_attribute = {
        !           490:                                .get_type = _get_type,
        !           491:                                .get_value = _get_value,
        !           492:                                .get_noskip_flag = _get_noskip_flag,
        !           493:                                .set_noskip_flag = _set_noskip_flag,
        !           494:                                .build = _build,
        !           495:                                .process = _process,
        !           496:                                .add_segment = _add_segment,
        !           497:                                .get_ref = _get_ref,
        !           498:                                .destroy = _destroy,
        !           499:                        },
        !           500:                        .get_flags = _get_flags,
        !           501:                        .get_request_id = _get_request_id,
        !           502:                        .get_event_count = _get_event_count,
        !           503:                        .set_events = _set_events,
        !           504:                        .get_events = _get_events,
        !           505:                        .clear_events = _clear_events,
        !           506:                },
        !           507:                .type = { PEN_IETF, type },
        !           508:                .length = length,
        !           509:                .segment = chunk_clone(data),
        !           510:                .events = swima_events_create(),
        !           511:                .ref = 1,
        !           512:        );
        !           513: 
        !           514:        /* received either complete attribute value or first segment */
        !           515:        this->value = this->segment;
        !           516: 
        !           517:        return &this->public.pa_tnc_attribute;
        !           518: }

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