Annotation of embedaddon/libpdel/ppp/ppp_node.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (c) 2001-2002 Packet Design, LLC.
                      4:  * All rights reserved.
                      5:  * 
                      6:  * Subject to the following obligations and disclaimer of warranty,
                      7:  * use and redistribution of this software, in source or object code
                      8:  * forms, with or without modifications are expressly permitted by
                      9:  * Packet Design; provided, however, that:
                     10:  * 
                     11:  *    (i)  Any and all reproductions of the source or object code
                     12:  *         must include the copyright notice above and the following
                     13:  *         disclaimer of warranties; and
                     14:  *    (ii) No rights are granted, in any manner or form, to use
                     15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
                     16:  *         on advertising, endorsements, or otherwise except as such
                     17:  *         appears in the above copyright notice or in the software.
                     18:  * 
                     19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
                     20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
                     21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
                     22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
                     23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
                     24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
                     25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
                     26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
                     27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
                     28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
                     29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
                     30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
                     31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
                     32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
                     33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
                     35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
                     36:  * THE POSSIBILITY OF SUCH DAMAGE.
                     37:  *
                     38:  * Author: Archie Cobbs <archie@freebsd.org>
                     39:  */
                     40: 
                     41: #include "ppp/ppp_defs.h"
                     42: #include "ppp/ppp_log.h"
                     43: #include "ppp/ppp_node.h"
                     44: 
                     45: #include <sys/queue.h>
                     46: #include <netgraph/ng_socket.h>
                     47: 
                     48: /*
                     49:  * This manages an ng_ppp(4) netgraph node.
                     50:  */
                     51: 
                     52: #define NODE_MTYPE             "ppp_node"
                     53: #define PKTBUFLEN              2000
                     54: #define NODE_HOOK              "ppp"
                     55: 
                     56: /* One recipient for incoming control messages */
                     57: struct ppp_node_recvmsg {
                     58:        u_int32_t                       cookie;
                     59:        u_int32_t                       cmd;
                     60:        ppp_node_recvmsg_t              *recvmsg;
                     61:        void                            *arg;
                     62:        TAILQ_ENTRY(ppp_node_recvmsg)   next;
                     63: };
                     64: 
                     65: /* PPP node structure */
                     66: struct ppp_node {
                     67:        int                     csock;          /* ng_socket ctrl socket */
                     68:        int                     dsock;          /* ng_socket data socket */
                     69:        struct pevent_ctx       *ev_ctx;        /* event context */
                     70:        pthread_mutex_t         *mutex;         /* mutex */
                     71:        struct pevent           *cevent;        /* incoming ctrl msg event */
                     72:        struct pevent           *devent;        /* incoming packet event */
                     73:        struct ppp_log          *log;           /* log */
                     74:        ppp_node_recv_t         *recv;          /* handler for packets */
                     75:        void                    *rarg;          /* recv() function arg */
                     76:        struct ng_ppp_node_conf conf;           /* ng_ppp(4) node config */
                     77:        char                    path[32];       /* netgraph path to node */
                     78:        u_char                  got_conf;       /* "conf" is valid */
                     79:        u_char                  connected[NG_PPP_MAX_LINKS];
                     80:        TAILQ_HEAD(,ppp_node_recvmsg) rmlist;   /* ng_mesg recipient list */
                     81: };
                     82: 
                     83: /* Internal functions */
                     84: static pevent_handler_t        ppp_node_read_packet;
                     85: static pevent_handler_t        ppp_node_read_message;
                     86: 
                     87: /* Macro for logging */
                     88: #define LOG(sev, fmt, args...) PPP_LOG(node->log, sev, fmt , ## args)
                     89: 
                     90: /***********************************************************************
                     91:                        PUBLIC FUNCTIONS
                     92: ***********************************************************************/
                     93: 
                     94: /*
                     95:  * Create a new PPP node from a newly created link.
                     96:  *
                     97:  * The "log" is consumed.
                     98:  */
                     99: struct ppp_node *
                    100: ppp_node_create(struct pevent_ctx *ev_ctx,
                    101:        pthread_mutex_t *mutex, struct ppp_log *log)
                    102: {
                    103:        union {
                    104:            u_char buf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
                    105:            struct ng_mesg reply;
                    106:        } repbuf;
                    107:        struct ng_mesg *reply = &repbuf.reply;
                    108:        struct nodeinfo ninfo;
                    109:        struct ngm_mkpeer mkpeer;
                    110:        struct ppp_node *node;
                    111: 
                    112:        /* Create new node structure */
                    113:        if ((node = MALLOC(NODE_MTYPE, sizeof(*node))) == NULL)
                    114:                return (NULL);
                    115:        memset(node, 0, sizeof(*node));
                    116:        node->ev_ctx = ev_ctx;
                    117:        node->mutex = mutex;
                    118:        node->log = log;
                    119:        node->csock = -1;
                    120:        node->dsock = -1;
                    121:        TAILQ_INIT(&node->rmlist);
                    122: 
                    123:        /* Create netgraph socket node */
                    124:        if (NgMkSockNode(NULL, &node->csock, &node->dsock) == -1) {
                    125:                LOG(LOG_ERR, "%s: %m", "creating socket node");
                    126:                goto fail;
                    127:        }
                    128:        (void)fcntl(node->csock, F_SETFD, 1);
                    129:        (void)fcntl(node->dsock, F_SETFD, 1);
                    130: 
                    131:        /* Attach a new ng_ppp(4) node to the socket node via "bypass" hook */
                    132:        memset(&mkpeer, 0, sizeof(mkpeer));
                    133:        strlcpy(mkpeer.type, NG_PPP_NODE_TYPE, sizeof(mkpeer.type));
                    134:        strlcpy(mkpeer.ourhook, NODE_HOOK, sizeof(mkpeer.ourhook));
                    135:        strlcpy(mkpeer.peerhook, NG_PPP_HOOK_BYPASS, sizeof(mkpeer.peerhook));
                    136:        if (NgSendMsg(node->csock, ".",
                    137:            NGM_GENERIC_COOKIE, NGM_MKPEER, &mkpeer, sizeof(mkpeer)) == -1) {
                    138:                LOG(LOG_ERR, "%s: %m", "attaching ppp node");
                    139:                goto fail;
                    140:        }
                    141: 
                    142:        /* Get node info including 'id' and create absolute path for node */
                    143:        if (NgSendMsg(node->csock, NODE_HOOK,
                    144:            NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) == -1) {
                    145:                LOG(LOG_ERR, "can't get node info: %m");
                    146:                goto fail;
                    147:        }
                    148:        memset(&repbuf, 0, sizeof(repbuf));
                    149:        if (NgRecvMsg(node->csock, reply, sizeof(repbuf), NULL) == -1) {
                    150:                LOG(LOG_ERR, "can't read node info: %m");
                    151:                goto fail;
                    152:        }
                    153:        memcpy(&ninfo, reply->data, sizeof(ninfo));
                    154:        snprintf(node->path, sizeof(node->path), "[%lx]:", (long)ninfo.id);
                    155: 
                    156:        /* Register event for reading incoming packets from bypass hook */
                    157:        if (pevent_register(node->ev_ctx, &node->devent, PEVENT_RECURRING,
                    158:            node->mutex, ppp_node_read_packet, node, PEVENT_READ,
                    159:            node->dsock) == -1) {
                    160:                LOG(LOG_ERR, "%s: %m", "adding read event");
                    161:                goto fail;
                    162:        }
                    163: 
                    164:        /* Register event for reading incoming control messages */
                    165:        if (pevent_register(node->ev_ctx, &node->cevent, PEVENT_RECURRING,
                    166:            node->mutex, ppp_node_read_message, node, PEVENT_READ,
                    167:            node->csock) == -1) {
                    168:                LOG(LOG_ERR, "%s: %m", "adding read event");
                    169:                goto fail;
                    170:        }
                    171: 
                    172:        /* Done */
                    173:        return (node);
                    174: 
                    175: fail:
                    176:        /* Clean up */
                    177:        if (node->csock != -1) {
                    178:                (void)NgSendMsg(node->csock, NODE_HOOK,
                    179:                    NGM_GENERIC_COOKIE, NGM_SHUTDOWN, NULL, 0);
                    180:                (void)close(node->csock);
                    181:                (void)close(node->dsock);
                    182:        }
                    183:        FREE(NODE_MTYPE, node);
                    184:        return (NULL);
                    185: }
                    186: 
                    187: /*
                    188:  * Destroy a node.
                    189:  */
                    190: void
                    191: ppp_node_destroy(struct ppp_node **nodep)
                    192: {
                    193:        struct ppp_node *const node = *nodep;
                    194:        const int esave = errno;
                    195: 
                    196:        if (node == NULL)
                    197:                return;
                    198:        *nodep = NULL;
                    199:        while (!TAILQ_EMPTY(&node->rmlist)) {
                    200:                struct ppp_node_recvmsg *const rm = TAILQ_FIRST(&node->rmlist);
                    201: 
                    202:                ppp_node_set_recvmsg(node, rm->cookie, rm->cmd, NULL, NULL);
                    203:        }
                    204:        (void)NgSendMsg(node->csock, NODE_HOOK,
                    205:            NGM_GENERIC_COOKIE, NGM_SHUTDOWN, NULL, 0);
                    206:        (void)close(node->csock);
                    207:        (void)close(node->dsock);
                    208:        pevent_unregister(&node->devent);
                    209:        pevent_unregister(&node->cevent);
                    210:        ppp_log_close(&node->log);
                    211:        FREE(NODE_MTYPE, node);
                    212:        errno = esave;
                    213: }
                    214: 
                    215: /*
                    216:  * Write to bypass hook.
                    217:  */
                    218: int
                    219: ppp_node_write(struct ppp_node *node, u_int link_num,
                    220:        u_int16_t proto, const void *data, size_t len)
                    221: {
                    222:        struct sockaddr_ng sag;
                    223:        u_int16_t hdr[2];
                    224:        u_char *buf;
                    225: 
                    226:        /* Build ng_ppp(4) bypass header */
                    227:        hdr[0] = htons(link_num);
                    228:        hdr[1] = htons(proto);
                    229: 
                    230:        /* Set destination hook */
                    231:        memset(&sag, 0, sizeof(sag));
                    232:        sag.sg_len = 2 + sizeof(NODE_HOOK);
                    233:        sag.sg_family = AF_NETGRAPH;
                    234:        strlcpy(sag.sg_data, NODE_HOOK, sizeof(sag.sg_data));
                    235: 
                    236:        /* Write packet */
                    237:        if ((buf = MALLOC(TYPED_MEM_TEMP, len + 4)) == NULL)
                    238:                return (-1);
                    239:        memcpy(buf, hdr, 4);
                    240:        memcpy(buf + 4, data, len);
                    241:        if (sendto(node->dsock, buf, len + 4, 0,
                    242:              (struct sockaddr *)&sag, sag.sg_len) == -1
                    243:            && errno != ENOBUFS) {
                    244:                FREE(TYPED_MEM_TEMP, buf);
                    245:                return (-1);
                    246:        }
                    247:        FREE(TYPED_MEM_TEMP, buf);
                    248: 
                    249:        /* Done */
                    250:        return (len);
                    251: }
                    252: 
                    253: /*
                    254:  * Connect a link.
                    255:  */
                    256: int
                    257: ppp_node_connect(struct ppp_node *node, u_int link_num,
                    258:        const char *path, const char *hook)
                    259: {
                    260:        struct ngm_connect connect;
                    261: 
                    262:        /* Sanity checks */
                    263:        if (link_num >= NG_PPP_MAX_LINKS) {
                    264:                errno = EINVAL;
                    265:                return (-1);
                    266:        }
                    267:        if (node->connected[link_num])
                    268:                ppp_node_disconnect(node, link_num);
                    269: 
                    270:        /* Connect ng_ppp(4) device hook */
                    271:        memset(&connect, 0, sizeof(connect));
                    272:        strlcpy(connect.path, path, sizeof(connect.path));
                    273:        snprintf(connect.ourhook, sizeof(connect.ourhook),
                    274:            "%s%u", NG_PPP_HOOK_LINK_PREFIX, link_num);
                    275:        strlcpy(connect.peerhook, hook, sizeof(connect.peerhook));
                    276:        if (NgSendMsg(node->csock, NODE_HOOK,
                    277:            NGM_GENERIC_COOKIE, NGM_CONNECT, &connect, sizeof(connect)) == -1) {
                    278:                LOG(LOG_ERR, "connecting %s%u: %m",
                    279:                    NG_PPP_HOOK_LINK_PREFIX, link_num);
                    280:                return (-1);
                    281:        }
                    282: 
                    283:        /* Done */
                    284:        node->connected[link_num] = 1;
                    285:        return (0);
                    286: }
                    287: 
                    288: /*
                    289:  * Disonnect a link.
                    290:  */
                    291: int
                    292: ppp_node_disconnect(struct ppp_node *node, u_int link_num)
                    293: {
                    294:        struct ngm_rmhook rmhook;
                    295: 
                    296:        /* Sanity check */
                    297:        if (link_num >= NG_PPP_MAX_LINKS) {
                    298:                errno = EINVAL;
                    299:                return (-1);
                    300:        }
                    301: 
                    302:        /* Remove hook */
                    303:        memset(&rmhook, 0, sizeof(rmhook));
                    304:        snprintf(rmhook.ourhook, sizeof(rmhook.ourhook),
                    305:            "%s%u", NG_PPP_HOOK_LINK_PREFIX, link_num);
                    306:        if (NgSendMsg(node->csock, NODE_HOOK, NGM_GENERIC_COOKIE,
                    307:              NGM_RMHOOK, &rmhook, sizeof(rmhook)) == -1
                    308:            && errno != ENOENT) {
                    309:                LOG(LOG_ERR, "disconnecting %s%u: %m",
                    310:                    NG_PPP_HOOK_LINK_PREFIX, link_num);
                    311:                return (-1);
                    312:        }
                    313: 
                    314:        /* Done */
                    315:        node->connected[link_num] = 0;
                    316:        return (0);
                    317: }
                    318: 
                    319: /*
                    320:  * Get absolute path to node.
                    321:  */
                    322: const char *
                    323: ppp_node_get_path(struct ppp_node *node)
                    324: {
                    325:        return (node->path);
                    326: }
                    327: 
                    328: /***********************************************************************
                    329:                    CONTROL MESSAGE FUNCTIONS
                    330: ***********************************************************************/
                    331: 
                    332: /*
                    333:  * Get node configuration.
                    334:  */
                    335: int
                    336: ppp_node_get_config(struct ppp_node *node, struct ng_ppp_node_conf *conf)
                    337: {
                    338:        union {
                    339:            u_char buf[sizeof(struct ng_mesg) + sizeof(*conf)];
                    340:            struct ng_mesg reply;
                    341:        } buf;
                    342:        struct ng_mesg *const reply = &buf.reply;
                    343: 
                    344:        if (!node->got_conf) {
                    345:                memset(&buf, 0, sizeof(buf));
                    346:                if (NgSendMsg(node->csock, NODE_HOOK,
                    347:                    NGM_PPP_COOKIE, NGM_PPP_GET_CONFIG, NULL, 0) < 0) {
                    348:                        LOG(LOG_ERR, "%s: %m", "getting node configuration");
                    349:                        return (-1);
                    350:                }
                    351:                if (NgRecvMsg(node->csock, reply, sizeof(buf), NULL) == -1) {
                    352:                        LOG(LOG_ERR, "%s: %m", "receiving node configuration");
                    353:                        return (-1);
                    354:                }
                    355:                memcpy(&node->conf, reply->data, sizeof(node->conf));
                    356:                node->got_conf = 1;
                    357:        }
                    358:        *conf = node->conf;
                    359:        return (0);
                    360: }
                    361: 
                    362: /*
                    363:  * Set node configuration.
                    364:  */
                    365: int
                    366: ppp_node_set_config(struct ppp_node *node, const struct ng_ppp_node_conf *conf)
                    367: {
                    368:        if (NgSendMsg(node->csock, NODE_HOOK, NGM_PPP_COOKIE,
                    369:            NGM_PPP_SET_CONFIG, conf, sizeof(*conf)) < 0) {
                    370:                LOG(LOG_ERR, "%s: %m", "configuring node");
                    371:                return (-1);
                    372:        }
                    373:        node->got_conf = 1;
                    374:        node->conf = *conf;
                    375:        return (0);
                    376: }
                    377: 
                    378: /*
                    379:  * Set incoming packet recipient.
                    380:  */
                    381: void
                    382: ppp_node_set_recv(struct ppp_node *node, ppp_node_recv_t *recv, void *arg)
                    383: {
                    384:        node->recv = recv;
                    385:        node->rarg = arg;
                    386: }
                    387: 
                    388: /*
                    389:  * Set incoming message recipient.
                    390:  */
                    391: int
                    392: ppp_node_set_recvmsg(struct ppp_node *node, u_int32_t cookie,
                    393:        u_int32_t cmd, ppp_node_recvmsg_t *recvmsg, void *arg)
                    394: {
                    395:        struct ppp_node_recvmsg *rm;
                    396:        int found = 0;
                    397: 
                    398:        /* Check if already exists */
                    399:        TAILQ_FOREACH(rm, &node->rmlist, next) {
                    400:                if (rm->cookie == cookie && rm->cmd == cmd) {
                    401:                        found = 1;
                    402:                        break;
                    403:                }
                    404:        }
                    405: 
                    406:        /* Removing it? */
                    407:        if (recvmsg == NULL) {
                    408:                if (found) {
                    409:                        TAILQ_REMOVE(&node->rmlist, rm, next);
                    410:                        FREE(NODE_MTYPE, rm);
                    411:                }
                    412:                return (0);
                    413:        } else if (found) {
                    414:                errno = EALREADY;
                    415:                return (-1);
                    416:        }
                    417: 
                    418:        /* Add new message receiver */
                    419:        if ((rm = MALLOC(NODE_MTYPE, sizeof(*rm))) == NULL)
                    420:                return (-1);
                    421:        memset(rm, 0, sizeof(*rm));
                    422:        rm->cookie = cookie;
                    423:        rm->cmd = cmd;
                    424:        rm->recvmsg = recvmsg;
                    425:        rm->arg = arg;
                    426:        TAILQ_INSERT_TAIL(&node->rmlist, rm, next);
                    427:        return (0);
                    428: }
                    429: 
                    430: int
                    431: ppp_node_send_msg(struct ppp_node *node, const char *relpath,
                    432:        u_int32_t cookie, u_int32_t cmd, const void *payload, size_t plen)
                    433: {
                    434:        char path[NG_PATHSIZ];
                    435: 
                    436:        if (relpath == NULL)
                    437:                strlcpy(path, NODE_HOOK, sizeof(path));
                    438:        else
                    439:                snprintf(path, sizeof(path), "%s.%s", NODE_HOOK, relpath);
                    440:        if (NgSendMsg(node->csock, path, cookie, cmd, payload, plen) == -1)
                    441:                return (-1);
                    442:        return (0);
                    443: }
                    444: 
                    445: int
                    446: ppp_node_recv_msg(struct ppp_node *node,
                    447:        struct ng_mesg *msg, size_t mlen, char *raddr)
                    448: {
                    449:        return (NgRecvMsg(node->csock, msg, mlen, raddr));
                    450: }
                    451: 
                    452: /***********************************************************************
                    453:                        INTERNAL FUNCTIONS
                    454: ***********************************************************************/
                    455: 
                    456: /*
                    457:  * Handle incoming data on the ng_ppp(4) bypass hook.
                    458:  */
                    459: static void
                    460: ppp_node_read_packet(void *arg)
                    461: {
                    462:        struct ppp_node *const node = arg;
                    463:        u_char buf[4 + PKTBUFLEN];
                    464:        u_int16_t link_num;
                    465:        u_int16_t proto;
                    466:        int len;
                    467: 
                    468:        /* Read packet */
                    469:        if ((len = read(node->dsock, buf, sizeof(buf))) == -1) {
                    470:                LOG(LOG_ERR, "error reading bypass hook: %m");
                    471:                return;
                    472:        }
                    473: 
                    474:        /* Extract protocol and link number */
                    475:        if (len < 4) {
                    476:                LOG(LOG_ERR, "read len %d bypass packet", len);
                    477:                return;
                    478:        }
                    479:        memcpy(&link_num, buf, 2);
                    480:        link_num = ntohs(link_num);
                    481:        memcpy(&proto, buf + 2, 2);
                    482:        proto = ntohs(proto);
                    483: 
                    484:        /* Deliver packet */
                    485:        if (node->recv != NULL)
                    486:                (*node->recv)(node->rarg, link_num, proto, buf + 4, len - 4);
                    487: }
                    488: 
                    489: /*
                    490:  * Handle incoming control message on the netgraph socket.
                    491:  */
                    492: static void
                    493: ppp_node_read_message(void *arg)
                    494: {
                    495:        struct ppp_node *const node = arg;
                    496:        const size_t max_msglen = 4096;
                    497:        char raddr[NG_PATHSIZ];
                    498:        struct ppp_node_recvmsg *rm;
                    499:        struct ng_mesg *msg;
                    500:        int found = 0;
                    501:        int len;
                    502: 
                    503:        /* Allocate buffer */
                    504:        if ((msg = MALLOC(TYPED_MEM_TEMP, max_msglen)) == NULL) {
                    505:                LOG(LOG_ERR, "malloc: %m");
                    506:                return;
                    507:        }
                    508: 
                    509:        /* Read incoming message */
                    510:        if ((len = NgRecvMsg(node->csock, msg, max_msglen, raddr)) == -1) {
                    511:                LOG(LOG_ERR, "reading ctrl message: %m");
                    512:                goto done;
                    513:        }
                    514: 
                    515:        /* Search for handler */
                    516:        TAILQ_FOREACH(rm, &node->rmlist, next) {
                    517:                if (rm->cookie == msg->header.typecookie
                    518:                    && rm->cmd == msg->header.cmd) {
                    519:                        found = 1;
                    520:                        break;
                    521:                }
                    522:        }
                    523:        if (!found)
                    524:                goto done;
                    525: 
                    526:        /* Invoke handler */
                    527:        (*rm->recvmsg)(rm->arg, msg);
                    528: 
                    529: done:
                    530:        /* Clean up */
                    531:        FREE(TYPED_MEM_TEMP, msg);
                    532: }
                    533: 

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