LCOV - code coverage report
Current view: top level - net - if_pppx.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 503 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 30 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_pppx.c,v 1.66 2018/07/11 21:18:23 nayden Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2010 Claudio Jeker <claudio@openbsd.org>
       5             :  * Copyright (c) 2010 David Gwynne <dlg@openbsd.org>
       6             :  *
       7             :  * Permission to use, copy, modify, and distribute this software for any
       8             :  * purpose with or without fee is hereby granted, provided that the above
       9             :  * copyright notice and this permission notice appear in all copies.
      10             :  *
      11             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      12             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      13             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      14             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      15             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      16             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      17             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      18             :  */
      19             : 
      20             : /*-
      21             :  * Copyright (c) 2009 Internet Initiative Japan Inc.
      22             :  * All rights reserved.
      23             :  *
      24             :  * Redistribution and use in source and binary forms, with or without
      25             :  * modification, are permitted provided that the following conditions
      26             :  * are met:
      27             :  * 1. Redistributions of source code must retain the above copyright
      28             :  *    notice, this list of conditions and the following disclaimer.
      29             :  * 2. Redistributions in binary form must reproduce the above copyright
      30             :  *    notice, this list of conditions and the following disclaimer in the
      31             :  *    documentation and/or other materials provided with the distribution.
      32             :  *
      33             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
      34             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      35             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      36             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      37             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      38             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      39             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      40             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      41             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      42             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      43             :  * SUCH DAMAGE.
      44             :  */
      45             : #include <sys/param.h>
      46             : #include <sys/systm.h>
      47             : #include <sys/buf.h>
      48             : #include <sys/kernel.h>
      49             : #include <sys/malloc.h>
      50             : #include <sys/device.h>
      51             : #include <sys/conf.h>
      52             : #include <sys/queue.h>
      53             : #include <sys/rwlock.h>
      54             : #include <sys/pool.h>
      55             : #include <sys/mbuf.h>
      56             : #include <sys/errno.h>
      57             : #include <sys/protosw.h>
      58             : #include <sys/socket.h>
      59             : #include <sys/ioctl.h>
      60             : #include <sys/vnode.h>
      61             : #include <sys/poll.h>
      62             : #include <sys/selinfo.h>
      63             : 
      64             : #include <net/if.h>
      65             : #include <net/if_types.h>
      66             : #include <net/netisr.h>
      67             : #include <netinet/in.h>
      68             : #include <netinet/if_ether.h>
      69             : #include <net/if_dl.h>
      70             : 
      71             : #include <netinet/in_var.h>
      72             : #include <netinet/ip.h>
      73             : #include <netinet/ip_var.h>
      74             : 
      75             : #ifdef INET6
      76             : #include <netinet6/in6_var.h>
      77             : #include <netinet/ip6.h>
      78             : #include <netinet6/nd6.h>
      79             : #endif /* INET6 */
      80             : 
      81             : #include "bpfilter.h"
      82             : #if NBPFILTER > 0
      83             : #include <net/bpf.h>
      84             : #endif
      85             : 
      86             : #include <net/ppp_defs.h>
      87             : #include <net/ppp-comp.h>
      88             : #include <crypto/arc4.h>
      89             : 
      90             : #ifdef PIPEX
      91             : #include <net/radix.h>
      92             : #include <net/pipex.h>
      93             : #include <net/pipex_local.h>
      94             : #else
      95             : #error PIPEX option not enabled
      96             : #endif
      97             : 
      98             : #ifdef PPPX_DEBUG
      99             : #define PPPX_D_INIT     (1<<0)
     100             : 
     101             : int pppxdebug = 0;
     102             : 
     103             : #define DPRINTF(_m, _p...)      do { \
     104             :                                         if (ISSET(pppxdebug, (_m))) \
     105             :                                                 printf(_p); \
     106             :                                 } while (0)
     107             : #else
     108             : #define DPRINTF(_m, _p...)      /* _m, _p */
     109             : #endif
     110             : 
     111             : 
     112             : struct pppx_if;
     113             : 
     114             : struct pppx_dev {
     115             :         LIST_ENTRY(pppx_dev)    pxd_entry;
     116             :         int                     pxd_unit;
     117             : 
     118             :         /* kq shizz */
     119             :         struct selinfo          pxd_rsel;
     120             :         struct mutex            pxd_rsel_mtx;
     121             :         struct selinfo          pxd_wsel;
     122             :         struct mutex            pxd_wsel_mtx;
     123             : 
     124             :         /* queue of packets for userland to service - protected by splnet */
     125             :         struct mbuf_queue       pxd_svcq;
     126             :         int                     pxd_waiting;
     127             :         LIST_HEAD(,pppx_if)     pxd_pxis;
     128             : };
     129             : 
     130             : struct rwlock                   pppx_devs_lk = RWLOCK_INITIALIZER("pppxdevs");
     131             : LIST_HEAD(, pppx_dev)           pppx_devs = LIST_HEAD_INITIALIZER(pppx_devs);
     132             : struct pool                     *pppx_if_pl;
     133             : 
     134             : struct pppx_dev                 *pppx_dev_lookup(dev_t);
     135             : struct pppx_dev                 *pppx_dev2pxd(dev_t);
     136             : 
     137             : struct pppx_if_key {
     138             :         int                     pxik_session_id;
     139             :         int                     pxik_protocol;
     140             : };
     141             : 
     142             : struct pppx_if {
     143             :         struct pppx_if_key      pxi_key; /* must be first in the struct */
     144             : 
     145             :         RBT_ENTRY(pppx_if)      pxi_entry;
     146             :         LIST_ENTRY(pppx_if)     pxi_list;
     147             : 
     148             :         int                     pxi_ready;
     149             : 
     150             :         int                     pxi_unit;
     151             :         struct ifnet            pxi_if;
     152             :         struct pppx_dev         *pxi_dev;
     153             :         struct pipex_session    pxi_session;
     154             :         struct pipex_iface_context      pxi_ifcontext;
     155             : };
     156             : 
     157             : static inline int
     158           0 : pppx_if_cmp(const struct pppx_if *a, const struct pppx_if *b)
     159             : {
     160           0 :         return memcmp(&a->pxi_key, &b->pxi_key, sizeof(a->pxi_key));
     161             : }
     162             : 
     163             : struct rwlock                   pppx_ifs_lk = RWLOCK_INITIALIZER("pppxifs");
     164             : RBT_HEAD(pppx_ifs, pppx_if)     pppx_ifs = RBT_INITIALIZER(&pppx_ifs);
     165           0 : RBT_PROTOTYPE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
     166             : 
     167             : int             pppx_if_next_unit(void);
     168             : struct pppx_if *pppx_if_find(struct pppx_dev *, int, int);
     169             : int             pppx_add_session(struct pppx_dev *,
     170             :                     struct pipex_session_req *);
     171             : int             pppx_del_session(struct pppx_dev *,
     172             :                     struct pipex_session_close_req *);
     173             : int             pppx_set_session_descr(struct pppx_dev *,
     174             :                     struct pipex_session_descr_req *);
     175             : 
     176             : void            pppx_if_destroy(struct pppx_dev *, struct pppx_if *);
     177             : void            pppx_if_start(struct ifnet *);
     178             : int             pppx_if_output(struct ifnet *, struct mbuf *,
     179             :                     struct sockaddr *, struct rtentry *);
     180             : int             pppx_if_ioctl(struct ifnet *, u_long, caddr_t);
     181             : 
     182             : 
     183             : void            pppxattach(int);
     184             : 
     185             : void            filt_pppx_rdetach(struct knote *);
     186             : int             filt_pppx_read(struct knote *, long);
     187             : 
     188             : struct filterops pppx_rd_filtops = {
     189             :         1,
     190             :         NULL,
     191             :         filt_pppx_rdetach,
     192             :         filt_pppx_read
     193             : };
     194             : 
     195             : void            filt_pppx_wdetach(struct knote *);
     196             : int             filt_pppx_write(struct knote *, long);
     197             : 
     198             : struct filterops pppx_wr_filtops = {
     199             :         1,
     200             :         NULL,
     201             :         filt_pppx_wdetach,
     202             :         filt_pppx_write
     203             : };
     204             : 
     205             : struct pppx_dev *
     206           0 : pppx_dev_lookup(dev_t dev)
     207             : {
     208             :         struct pppx_dev *pxd;
     209           0 :         int unit = minor(dev);
     210             : 
     211             :         /* must hold pppx_devs_lk */
     212             : 
     213           0 :         LIST_FOREACH(pxd, &pppx_devs, pxd_entry) {
     214           0 :                 if (pxd->pxd_unit == unit)
     215           0 :                         return (pxd);
     216             :         }
     217             : 
     218           0 :         return (NULL);
     219           0 : }
     220             : 
     221             : struct pppx_dev *
     222           0 : pppx_dev2pxd(dev_t dev)
     223             : {
     224             :         struct pppx_dev *pxd;
     225             : 
     226           0 :         rw_enter_read(&pppx_devs_lk);
     227           0 :         pxd = pppx_dev_lookup(dev);
     228           0 :         rw_exit_read(&pppx_devs_lk);
     229             : 
     230           0 :         return (pxd);
     231             : }
     232             : 
     233             : void
     234           0 : pppxattach(int n)
     235             : {
     236           0 :         pipex_init();
     237           0 : }
     238             : 
     239             : int
     240           0 : pppxopen(dev_t dev, int flags, int mode, struct proc *p)
     241             : {
     242             :         struct pppx_dev *pxd;
     243             :         int rv = 0;
     244             : 
     245           0 :         rv = rw_enter(&pppx_devs_lk, RW_WRITE | RW_INTR);
     246           0 :         if (rv != 0)
     247           0 :                 return (rv);
     248             : 
     249           0 :         pxd = pppx_dev_lookup(dev);
     250           0 :         if (pxd != NULL) {
     251             :                 rv = EBUSY;
     252           0 :                 goto out;
     253             :         }
     254             : 
     255           0 :         if (LIST_EMPTY(&pppx_devs) && pppx_if_pl == NULL) {
     256           0 :                 pppx_if_pl = malloc(sizeof(*pppx_if_pl), M_DEVBUF, M_WAITOK);
     257           0 :                 pool_init(pppx_if_pl, sizeof(struct pppx_if), 0, IPL_NONE,
     258             :                     PR_WAITOK, "pppxif", NULL);
     259           0 :         }
     260             : 
     261           0 :         pxd = malloc(sizeof(*pxd), M_DEVBUF, M_WAITOK | M_ZERO);
     262             : 
     263           0 :         pxd->pxd_unit = minor(dev);
     264           0 :         mtx_init(&pxd->pxd_rsel_mtx, IPL_NET);
     265           0 :         mtx_init(&pxd->pxd_wsel_mtx, IPL_NET);
     266           0 :         LIST_INIT(&pxd->pxd_pxis);
     267             : 
     268           0 :         mq_init(&pxd->pxd_svcq, 128, IPL_NET);
     269           0 :         LIST_INSERT_HEAD(&pppx_devs, pxd, pxd_entry);
     270             : 
     271             : out:
     272           0 :         rw_exit(&pppx_devs_lk);
     273           0 :         return (rv);
     274           0 : }
     275             : 
     276             : int
     277           0 : pppxread(dev_t dev, struct uio *uio, int ioflag)
     278             : {
     279           0 :         struct pppx_dev *pxd = pppx_dev2pxd(dev);
     280             :         struct mbuf *m, *m0;
     281             :         int error = 0;
     282             :         size_t len;
     283             : 
     284           0 :         if (!pxd)
     285           0 :                 return (ENXIO);
     286             : 
     287           0 :         while ((m0 = mq_dequeue(&pxd->pxd_svcq)) == NULL) {
     288           0 :                 if (ISSET(ioflag, IO_NDELAY))
     289           0 :                         return (EWOULDBLOCK);
     290             : 
     291           0 :                 NET_LOCK();
     292           0 :                 pxd->pxd_waiting = 1;
     293           0 :                 error = rwsleep(pxd, &netlock,
     294             :                     (PZERO + 1)|PCATCH, "pppxread", 0);
     295           0 :                 NET_UNLOCK();
     296           0 :                 if (error != 0) {
     297           0 :                         return (error);
     298             :                 }
     299             :         }
     300             : 
     301           0 :         while (m0 != NULL && uio->uio_resid > 0 && error == 0) {
     302           0 :                 len = ulmin(uio->uio_resid, m0->m_len);
     303           0 :                 if (len != 0)
     304           0 :                         error = uiomove(mtod(m0, caddr_t), len, uio);
     305           0 :                 m = m_free(m0);
     306             :                 m0 = m;
     307             :         }
     308             : 
     309           0 :         m_freem(m0);
     310             : 
     311           0 :         return (error);
     312           0 : }
     313             : 
     314             : int
     315           0 : pppxwrite(dev_t dev, struct uio *uio, int ioflag)
     316             : {
     317           0 :         struct pppx_dev *pxd = pppx_dev2pxd(dev);
     318             :         struct pppx_hdr *th;
     319             :         struct pppx_if  *pxi;
     320             :         uint32_t proto;
     321           0 :         struct mbuf *top, **mp, *m;
     322             :         int tlen;
     323             :         int error = 0;
     324             :         size_t mlen;
     325             : 
     326           0 :         if (uio->uio_resid < sizeof(*th) + sizeof(uint32_t) ||
     327           0 :             uio->uio_resid > MCLBYTES)
     328           0 :                 return (EMSGSIZE);
     329             : 
     330           0 :         tlen = uio->uio_resid;
     331             : 
     332           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
     333           0 :         if (m == NULL)
     334           0 :                 return (ENOBUFS);
     335             :         mlen = MHLEN;
     336           0 :         if (uio->uio_resid >= MINCLSIZE) {
     337           0 :                 MCLGET(m, M_DONTWAIT);
     338           0 :                 if (!(m->m_flags & M_EXT)) {
     339           0 :                         m_free(m);
     340           0 :                         return (ENOBUFS);
     341             :                 }
     342             :                 mlen = MCLBYTES;
     343           0 :         }
     344             : 
     345           0 :         top = NULL;
     346             :         mp = &top;
     347             : 
     348           0 :         while (error == 0 && uio->uio_resid > 0) {
     349           0 :                 m->m_len = ulmin(mlen, uio->uio_resid);
     350           0 :                 error = uiomove(mtod (m, caddr_t), m->m_len, uio);
     351           0 :                 *mp = m;
     352           0 :                 mp = &m->m_next;
     353           0 :                 if (error == 0 && uio->uio_resid > 0) {
     354           0 :                         MGET(m, M_DONTWAIT, MT_DATA);
     355           0 :                         if (m == NULL) {
     356             :                                 error = ENOBUFS;
     357           0 :                                 break;
     358             :                         }
     359             :                         mlen = MLEN;
     360           0 :                         if (uio->uio_resid >= MINCLSIZE) {
     361           0 :                                 MCLGET(m, M_DONTWAIT);
     362           0 :                                 if (!(m->m_flags & M_EXT)) {
     363             :                                         error = ENOBUFS;
     364           0 :                                         m_free(m);
     365           0 :                                         break;
     366             :                                 }
     367             :                                 mlen = MCLBYTES;
     368           0 :                         }
     369             :                 }
     370             :         }
     371             : 
     372           0 :         if (error) {
     373           0 :                 m_freem(top);
     374           0 :                 return (error);
     375             :         }
     376             : 
     377           0 :         top->m_pkthdr.len = tlen;
     378             : 
     379             :         /* Find the interface */
     380           0 :         th = mtod(top, struct pppx_hdr *);
     381           0 :         m_adj(top, sizeof(struct pppx_hdr));
     382           0 :         pxi = pppx_if_find(pxd, th->pppx_id, th->pppx_proto);
     383           0 :         if (pxi == NULL) {
     384           0 :                 m_freem(top);
     385           0 :                 return (EINVAL);
     386             :         }
     387           0 :         top->m_pkthdr.ph_ifidx = pxi->pxi_if.if_index;
     388             : 
     389             : #if NBPFILTER > 0
     390           0 :         if (pxi->pxi_if.if_bpf)
     391           0 :                 bpf_mtap(pxi->pxi_if.if_bpf, top, BPF_DIRECTION_IN);
     392             : #endif
     393             :         /* strip the tunnel header */
     394           0 :         proto = ntohl(*(uint32_t *)(th + 1));
     395           0 :         m_adj(top, sizeof(uint32_t));
     396             : 
     397           0 :         NET_LOCK();
     398             : 
     399           0 :         switch (proto) {
     400             :         case AF_INET:
     401           0 :                 ipv4_input(&pxi->pxi_if, top);
     402           0 :                 break;
     403             : #ifdef INET6
     404             :         case AF_INET6:
     405           0 :                 ipv6_input(&pxi->pxi_if, top);
     406           0 :                 break;
     407             : #endif
     408             :         default:
     409           0 :                 m_freem(top);
     410             :                 error = EAFNOSUPPORT;
     411           0 :                 break;
     412             :         }
     413             : 
     414           0 :         NET_UNLOCK();
     415             : 
     416           0 :         return (error);
     417           0 : }
     418             : 
     419             : int
     420           0 : pppxioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
     421             : {
     422           0 :         struct pppx_dev *pxd = pppx_dev2pxd(dev);
     423             :         int error = 0;
     424             : 
     425           0 :         NET_LOCK();
     426           0 :         switch (cmd) {
     427             :         case PIPEXSMODE:
     428             :                 /*
     429             :                  * npppd always enables on open, and only disables before
     430             :                  * closing. we cheat and let open and close do that, so lie
     431             :                  * to npppd.
     432             :                  */
     433             :                 break;
     434             :         case PIPEXGMODE:
     435           0 :                 *(int *)addr = 1;
     436           0 :                 break;
     437             : 
     438             :         case PIPEXASESSION:
     439           0 :                 error = pppx_add_session(pxd,
     440           0 :                     (struct pipex_session_req *)addr);
     441           0 :                 break;
     442             : 
     443             :         case PIPEXDSESSION:
     444           0 :                 error = pppx_del_session(pxd,
     445           0 :                     (struct pipex_session_close_req *)addr);
     446           0 :                 break;
     447             : 
     448             :         case PIPEXCSESSION:
     449           0 :                 error = pipex_config_session(
     450           0 :                     (struct pipex_session_config_req *)addr);
     451           0 :                 break;
     452             : 
     453             :         case PIPEXGSTAT:
     454           0 :                 error = pipex_get_stat((struct pipex_session_stat_req *)addr);
     455           0 :                 break;
     456             : 
     457             :         case PIPEXGCLOSED:
     458           0 :                 error = pipex_get_closed((struct pipex_session_list_req *)addr);
     459           0 :                 break;
     460             : 
     461             :         case PIPEXSIFDESCR:
     462           0 :                 error = pppx_set_session_descr(pxd,
     463           0 :                     (struct pipex_session_descr_req *)addr);
     464           0 :                 break;
     465             : 
     466             :         case FIONBIO:
     467             :         case FIOASYNC:
     468             :         case FIONREAD:
     469             :                 break;
     470             : 
     471             :         default:
     472             :                 error = ENOTTY;
     473           0 :                 break;
     474             :         }
     475           0 :         NET_UNLOCK();
     476             : 
     477           0 :         return (error);
     478             : }
     479             : 
     480             : int
     481           0 : pppxpoll(dev_t dev, int events, struct proc *p)
     482             : {
     483           0 :         struct pppx_dev *pxd = pppx_dev2pxd(dev);
     484             :         int revents = 0;
     485             : 
     486           0 :         if (events & (POLLIN | POLLRDNORM)) {
     487           0 :                 if (!mq_empty(&pxd->pxd_svcq))
     488           0 :                         revents |= events & (POLLIN | POLLRDNORM);
     489             :         }
     490           0 :         if (events & (POLLOUT | POLLWRNORM))
     491           0 :                 revents |= events & (POLLOUT | POLLWRNORM);
     492             : 
     493           0 :         if (revents == 0) {
     494           0 :                 if (events & (POLLIN | POLLRDNORM))
     495           0 :                         selrecord(p, &pxd->pxd_rsel);
     496             :         }
     497             : 
     498           0 :         return (revents);
     499             : }
     500             : 
     501             : int
     502           0 : pppxkqfilter(dev_t dev, struct knote *kn)
     503             : {
     504           0 :         struct pppx_dev *pxd = pppx_dev2pxd(dev);
     505             :         struct mutex *mtx;
     506             :         struct klist *klist;
     507             : 
     508           0 :         switch (kn->kn_filter) {
     509             :         case EVFILT_READ:
     510           0 :                 mtx = &pxd->pxd_rsel_mtx;
     511           0 :                 klist = &pxd->pxd_rsel.si_note;
     512           0 :                 kn->kn_fop = &pppx_rd_filtops;
     513           0 :                 break;
     514             :         case EVFILT_WRITE:
     515           0 :                 mtx = &pxd->pxd_wsel_mtx;
     516           0 :                 klist = &pxd->pxd_wsel.si_note;
     517           0 :                 kn->kn_fop = &pppx_wr_filtops;
     518           0 :                 break;
     519             :         default:
     520           0 :                 return (EINVAL);
     521             :         }
     522             : 
     523           0 :         kn->kn_hook = (caddr_t)pxd;
     524             : 
     525           0 :         mtx_enter(mtx);
     526           0 :         SLIST_INSERT_HEAD(klist, kn, kn_selnext);
     527           0 :         mtx_leave(mtx);
     528             : 
     529           0 :         return (0);
     530           0 : }
     531             : 
     532             : void
     533           0 : filt_pppx_rdetach(struct knote *kn)
     534             : {
     535           0 :         struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
     536           0 :         struct klist *klist = &pxd->pxd_rsel.si_note;
     537             : 
     538           0 :         if (ISSET(kn->kn_status, KN_DETACHED))
     539           0 :                 return;
     540             : 
     541           0 :         mtx_enter(&pxd->pxd_rsel_mtx);
     542           0 :         SLIST_REMOVE(klist, kn, knote, kn_selnext);
     543           0 :         mtx_leave(&pxd->pxd_rsel_mtx);
     544           0 : }
     545             : 
     546             : int
     547           0 : filt_pppx_read(struct knote *kn, long hint)
     548             : {
     549           0 :         struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
     550             : 
     551           0 :         if (ISSET(kn->kn_status, KN_DETACHED)) {
     552           0 :                 kn->kn_data = 0;
     553           0 :                 return (1);
     554             :         }
     555             : 
     556           0 :         kn->kn_data = mq_len(&pxd->pxd_svcq);
     557             : 
     558           0 :         return (kn->kn_data > 0);
     559           0 : }
     560             : 
     561             : void
     562           0 : filt_pppx_wdetach(struct knote *kn)
     563             : {
     564           0 :         struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
     565           0 :         struct klist *klist = &pxd->pxd_wsel.si_note;
     566             : 
     567           0 :         if (ISSET(kn->kn_status, KN_DETACHED))
     568           0 :                 return;
     569             : 
     570           0 :         mtx_enter(&pxd->pxd_wsel_mtx);
     571           0 :         SLIST_REMOVE(klist, kn, knote, kn_selnext);
     572           0 :         mtx_leave(&pxd->pxd_wsel_mtx);
     573           0 : }
     574             : 
     575             : int
     576           0 : filt_pppx_write(struct knote *kn, long hint)
     577             : {
     578             :         /* We're always ready to accept a write. */
     579           0 :         return (1);
     580             : }
     581             : 
     582             : int
     583           0 : pppxclose(dev_t dev, int flags, int mode, struct proc *p)
     584             : {
     585             :         struct pppx_dev *pxd;
     586             :         struct pppx_if  *pxi;
     587             : 
     588           0 :         rw_enter_write(&pppx_devs_lk);
     589             : 
     590           0 :         pxd = pppx_dev_lookup(dev);
     591             : 
     592             :         /* XXX */
     593           0 :         NET_LOCK();
     594           0 :         while ((pxi = LIST_FIRST(&pxd->pxd_pxis)))
     595           0 :                 pppx_if_destroy(pxd, pxi);
     596           0 :         NET_UNLOCK();
     597             : 
     598           0 :         LIST_REMOVE(pxd, pxd_entry);
     599             : 
     600           0 :         mq_purge(&pxd->pxd_svcq);
     601             : 
     602           0 :         free(pxd, M_DEVBUF, 0);
     603             : 
     604           0 :         if (LIST_EMPTY(&pppx_devs)) {
     605           0 :                 pool_destroy(pppx_if_pl);
     606           0 :                 free(pppx_if_pl, M_DEVBUF, 0);
     607           0 :                 pppx_if_pl = NULL;
     608           0 :         }
     609             : 
     610           0 :         rw_exit_write(&pppx_devs_lk);
     611           0 :         return (0);
     612             : }
     613             : 
     614             : int
     615           0 : pppx_if_next_unit(void)
     616             : {
     617             :         struct pppx_if *pxi;
     618             :         int unit = 0;
     619             : 
     620           0 :         rw_assert_wrlock(&pppx_ifs_lk);
     621             : 
     622             :         /* this is safe without splnet since we're not modifying it */
     623           0 :         do {
     624             :                 int found = 0;
     625           0 :                 RBT_FOREACH(pxi, pppx_ifs, &pppx_ifs) {
     626           0 :                         if (pxi->pxi_unit == unit) {
     627             :                                 found = 1;
     628           0 :                                 break;
     629             :                         }
     630             :                 }
     631             : 
     632           0 :                 if (found == 0)
     633           0 :                         break;
     634           0 :                 unit++;
     635           0 :         } while (unit > 0);
     636             : 
     637           0 :         return (unit);
     638             : }
     639             : 
     640             : struct pppx_if *
     641           0 : pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
     642             : {
     643             :         struct pppx_if *s, *p;
     644           0 :         s = malloc(sizeof(*s), M_DEVBUF, M_WAITOK | M_ZERO);
     645             : 
     646           0 :         s->pxi_key.pxik_session_id = session_id;
     647           0 :         s->pxi_key.pxik_protocol = protocol;
     648             : 
     649           0 :         rw_enter_read(&pppx_ifs_lk);
     650           0 :         p = RBT_FIND(pppx_ifs, &pppx_ifs, s);
     651           0 :         if (p && p->pxi_ready == 0)
     652           0 :                 p = NULL;
     653           0 :         rw_exit_read(&pppx_ifs_lk);
     654             : 
     655           0 :         free(s, M_DEVBUF, 0);
     656           0 :         return (p);
     657             : }
     658             : 
     659             : int
     660           0 : pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
     661             : {
     662             :         struct pppx_if *pxi;
     663             :         struct pipex_session *session;
     664             :         struct pipex_hash_head *chain;
     665             :         struct ifnet *ifp;
     666             :         int unit, error = 0;
     667             :         struct in_ifaddr *ia;
     668           0 :         struct sockaddr_in ifaddr;
     669             : #ifdef PIPEX_PPPOE
     670             :         struct ifnet *over_ifp = NULL;
     671             : #endif
     672             : 
     673           0 :         switch (req->pr_protocol) {
     674             : #ifdef PIPEX_PPPOE
     675             :         case PIPEX_PROTO_PPPOE:
     676           0 :                 over_ifp = ifunit(req->pr_proto.pppoe.over_ifname);
     677           0 :                 if (over_ifp == NULL)
     678           0 :                         return (EINVAL);
     679           0 :                 if (req->pr_peer_address.ss_family != AF_UNSPEC)
     680           0 :                         return (EINVAL);
     681             :                 break;
     682             : #endif
     683             : #ifdef PIPEX_PPTP
     684             :         case PIPEX_PROTO_PPTP:
     685             : #endif
     686             : #ifdef PIPEX_L2TP
     687             :         case PIPEX_PROTO_L2TP:
     688             : #endif
     689           0 :                 switch (req->pr_peer_address.ss_family) {
     690             :                 case AF_INET:
     691           0 :                         if (req->pr_peer_address.ss_len != sizeof(struct sockaddr_in))
     692           0 :                                 return (EINVAL);
     693             :                         break;
     694             : #ifdef INET6
     695             :                 case AF_INET6:
     696           0 :                         if (req->pr_peer_address.ss_len != sizeof(struct sockaddr_in6))
     697           0 :                                 return (EINVAL);
     698             :                         break;
     699             : #endif
     700             :                 default:
     701           0 :                         return (EPROTONOSUPPORT);
     702             :                 }
     703           0 :                 if (req->pr_peer_address.ss_family !=
     704           0 :                     req->pr_local_address.ss_family ||
     705           0 :                     req->pr_peer_address.ss_len !=
     706           0 :                     req->pr_local_address.ss_len)
     707           0 :                         return (EINVAL);
     708             :                 break;
     709             :         default:
     710           0 :                 return (EPROTONOSUPPORT);
     711             :         }
     712             : 
     713           0 :         pxi = pool_get(pppx_if_pl, PR_WAITOK | PR_ZERO);
     714           0 :         if (pxi == NULL)
     715           0 :                 return (ENOMEM);
     716             : 
     717           0 :         session = &pxi->pxi_session;
     718           0 :         ifp = &pxi->pxi_if;
     719             : 
     720             :         /* fake a pipex interface context */
     721           0 :         session->pipex_iface = &pxi->pxi_ifcontext;
     722           0 :         session->pipex_iface->ifnet_this = ifp;
     723           0 :         session->pipex_iface->pipexmode = PIPEX_ENABLED;
     724             : 
     725             :         /* setup session */
     726           0 :         session->state = PIPEX_STATE_OPENED;
     727           0 :         session->protocol = req->pr_protocol;
     728           0 :         session->session_id = req->pr_session_id;
     729           0 :         session->peer_session_id = req->pr_peer_session_id;
     730           0 :         session->peer_mru = req->pr_peer_mru;
     731           0 :         session->timeout_sec = req->pr_timeout_sec;
     732           0 :         session->ppp_flags = req->pr_ppp_flags;
     733           0 :         session->ppp_id = req->pr_ppp_id;
     734             : 
     735           0 :         session->ip_forward = 1;
     736             : 
     737           0 :         session->ip_address.sin_family = AF_INET;
     738           0 :         session->ip_address.sin_len = sizeof(struct sockaddr_in);
     739           0 :         session->ip_address.sin_addr = req->pr_ip_address;
     740             : 
     741           0 :         session->ip_netmask.sin_family = AF_INET;
     742           0 :         session->ip_netmask.sin_len = sizeof(struct sockaddr_in);
     743           0 :         session->ip_netmask.sin_addr = req->pr_ip_netmask;
     744             : 
     745           0 :         if (session->ip_netmask.sin_addr.s_addr == 0L)
     746           0 :                 session->ip_netmask.sin_addr.s_addr = 0xffffffffL;
     747           0 :         session->ip_address.sin_addr.s_addr &=
     748           0 :             session->ip_netmask.sin_addr.s_addr;
     749             : 
     750           0 :         if (req->pr_peer_address.ss_len > 0)
     751           0 :                 memcpy(&session->peer, &req->pr_peer_address,
     752             :                     MIN(req->pr_peer_address.ss_len, sizeof(session->peer)));
     753           0 :         if (req->pr_local_address.ss_len > 0)
     754           0 :                 memcpy(&session->local, &req->pr_local_address,
     755             :                     MIN(req->pr_local_address.ss_len, sizeof(session->local)));
     756             : #ifdef PIPEX_PPPOE
     757           0 :         if (req->pr_protocol == PIPEX_PROTO_PPPOE)
     758           0 :                 session->proto.pppoe.over_ifidx = over_ifp->if_index;
     759             : #endif
     760             : #ifdef PIPEX_PPTP
     761           0 :         if (req->pr_protocol == PIPEX_PROTO_PPTP) {
     762           0 :                 struct pipex_pptp_session *sess_pptp = &session->proto.pptp;
     763             : 
     764           0 :                 sess_pptp->snd_gap = 0;
     765           0 :                 sess_pptp->rcv_gap = 0;
     766           0 :                 sess_pptp->snd_una = req->pr_proto.pptp.snd_una;
     767           0 :                 sess_pptp->snd_nxt = req->pr_proto.pptp.snd_nxt;
     768           0 :                 sess_pptp->rcv_nxt = req->pr_proto.pptp.rcv_nxt;
     769           0 :                 sess_pptp->rcv_acked = req->pr_proto.pptp.rcv_acked;
     770             : 
     771           0 :                 sess_pptp->winsz = req->pr_proto.pptp.winsz;
     772           0 :                 sess_pptp->maxwinsz = req->pr_proto.pptp.maxwinsz;
     773           0 :                 sess_pptp->peer_maxwinsz = req->pr_proto.pptp.peer_maxwinsz;
     774             :                 /* last ack number */
     775           0 :                 sess_pptp->ul_snd_una = sess_pptp->snd_una - 1;
     776           0 :         }
     777             : #endif
     778             : #ifdef PIPEX_L2TP
     779           0 :         if (req->pr_protocol == PIPEX_PROTO_L2TP) {
     780           0 :                 struct pipex_l2tp_session *sess_l2tp = &session->proto.l2tp;
     781             : 
     782             :                 /* session keys */
     783           0 :                 sess_l2tp->tunnel_id = req->pr_proto.l2tp.tunnel_id;
     784           0 :                 sess_l2tp->peer_tunnel_id = req->pr_proto.l2tp.peer_tunnel_id;
     785             : 
     786             :                 /* protocol options */
     787           0 :                 sess_l2tp->option_flags = req->pr_proto.l2tp.option_flags;
     788             : 
     789             :                 /* initial state of dynamic context */
     790           0 :                 sess_l2tp->ns_gap = sess_l2tp->nr_gap = 0;
     791           0 :                 sess_l2tp->ns_nxt = req->pr_proto.l2tp.ns_nxt;
     792           0 :                 sess_l2tp->nr_nxt = req->pr_proto.l2tp.nr_nxt;
     793           0 :                 sess_l2tp->ns_una = req->pr_proto.l2tp.ns_una;
     794           0 :                 sess_l2tp->nr_acked = req->pr_proto.l2tp.nr_acked;
     795             :                 /* last ack number */
     796           0 :                 sess_l2tp->ul_ns_una = sess_l2tp->ns_una - 1;
     797           0 :         }
     798             : #endif
     799             : #ifdef PIPEX_MPPE
     800           0 :         if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED) != 0)
     801           0 :                 pipex_session_init_mppe_recv(session,
     802           0 :                     req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits,
     803           0 :                     req->pr_mppe_recv.master_key);
     804           0 :         if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED) != 0)
     805           0 :                 pipex_session_init_mppe_send(session,
     806           0 :                     req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits,
     807           0 :                     req->pr_mppe_send.master_key);
     808             : 
     809           0 :         if (pipex_session_is_mppe_required(session)) {
     810           0 :                 if (!pipex_session_is_mppe_enabled(session) ||
     811           0 :                     !pipex_session_is_mppe_accepted(session)) {
     812           0 :                         pool_put(pppx_if_pl, pxi);
     813           0 :                         return (EINVAL);
     814             :                 }
     815             :         }
     816             : #endif
     817             : 
     818             :         /* try to set the interface up */
     819           0 :         rw_enter_write(&pppx_ifs_lk);
     820           0 :         unit = pppx_if_next_unit();
     821           0 :         if (unit < 0) {
     822           0 :                 pool_put(pppx_if_pl, pxi);
     823             :                 error = ENOMEM;
     824           0 :                 rw_exit_write(&pppx_ifs_lk);
     825           0 :                 goto out;
     826             :         }
     827             : 
     828           0 :         pxi->pxi_unit = unit;
     829           0 :         pxi->pxi_key.pxik_session_id = req->pr_session_id;
     830           0 :         pxi->pxi_key.pxik_protocol = req->pr_protocol;
     831           0 :         pxi->pxi_dev = pxd;
     832             : 
     833             :         /* this is safe without splnet since we're not modifying it */
     834           0 :         if (RBT_FIND(pppx_ifs, &pppx_ifs, pxi) != NULL) {
     835           0 :                 pool_put(pppx_if_pl, pxi);
     836             :                 error = EADDRINUSE;
     837           0 :                 rw_exit_write(&pppx_ifs_lk);
     838           0 :                 goto out;
     839             :         }
     840             : 
     841           0 :         if (RBT_INSERT(pppx_ifs, &pppx_ifs, pxi) != NULL)
     842           0 :                 panic("%s: pppx_ifs modified while lock was held", __func__);
     843           0 :         LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list);
     844           0 :         rw_exit_write(&pppx_ifs_lk);
     845             : 
     846           0 :         snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", "pppx", unit);
     847           0 :         ifp->if_mtu = req->pr_peer_mru;   /* XXX */
     848           0 :         ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST | IFF_UP;
     849           0 :         ifp->if_start = pppx_if_start;
     850           0 :         ifp->if_output = pppx_if_output;
     851           0 :         ifp->if_ioctl = pppx_if_ioctl;
     852           0 :         ifp->if_rtrequest = p2p_rtrequest;
     853           0 :         ifp->if_type = IFT_PPP;
     854           0 :         IFQ_SET_MAXLEN(&ifp->if_snd, 1);
     855           0 :         ifp->if_softc = pxi;
     856             :         /* ifp->if_rdomain = req->pr_rdomain; */
     857             : 
     858             :         /* hook up pipex context */
     859           0 :         chain = PIPEX_ID_HASHTABLE(session->session_id);
     860           0 :         LIST_INSERT_HEAD(chain, session, id_chain);
     861           0 :         LIST_INSERT_HEAD(&pipex_session_list, session, session_list);
     862           0 :         switch (req->pr_protocol) {
     863             :         case PIPEX_PROTO_PPTP:
     864             :         case PIPEX_PROTO_L2TP:
     865           0 :                 chain = PIPEX_PEER_ADDR_HASHTABLE(
     866             :                     pipex_sockaddr_hash_key(&session->peer.sa));
     867           0 :                 LIST_INSERT_HEAD(chain, session, peer_addr_chain);
     868           0 :                 break;
     869             :         }
     870             : 
     871             :         /* if first session is added, start timer */
     872           0 :         if (LIST_NEXT(session, session_list) == NULL)
     873           0 :                 pipex_timer_start();
     874             : 
     875             :         /* XXXSMP breaks atomicity */
     876           0 :         NET_UNLOCK();
     877           0 :         if_attach(ifp);
     878           0 :         NET_LOCK();
     879             : 
     880           0 :         if_addgroup(ifp, "pppx");
     881           0 :         if_alloc_sadl(ifp);
     882             : 
     883             : #if NBPFILTER > 0
     884           0 :         bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
     885             : #endif
     886           0 :         SET(ifp->if_flags, IFF_RUNNING);
     887             : 
     888             :         /* XXX ipv6 support?  how does the caller indicate it wants ipv6
     889             :          * instead of ipv4?
     890             :          */
     891           0 :         memset(&ifaddr, 0, sizeof(ifaddr));
     892           0 :         ifaddr.sin_family = AF_INET;
     893           0 :         ifaddr.sin_len = sizeof(ifaddr);
     894           0 :         ifaddr.sin_addr = req->pr_ip_srcaddr;
     895             : 
     896           0 :         ia = malloc(sizeof (*ia), M_IFADDR, M_WAITOK | M_ZERO);
     897             : 
     898           0 :         ia->ia_addr.sin_family = AF_INET;
     899           0 :         ia->ia_addr.sin_len = sizeof(struct sockaddr_in);
     900           0 :         ia->ia_addr.sin_addr = req->pr_ip_srcaddr;
     901             : 
     902           0 :         ia->ia_dstaddr.sin_family = AF_INET;
     903           0 :         ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in);
     904           0 :         ia->ia_dstaddr.sin_addr = req->pr_ip_address;
     905             : 
     906           0 :         ia->ia_sockmask.sin_family = AF_INET;
     907           0 :         ia->ia_sockmask.sin_len = sizeof(struct sockaddr_in);
     908           0 :         ia->ia_sockmask.sin_addr = req->pr_ip_netmask;
     909             : 
     910           0 :         ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
     911           0 :         ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
     912           0 :         ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
     913           0 :         ia->ia_ifa.ifa_ifp = ifp;
     914             : 
     915           0 :         ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
     916             : 
     917           0 :         error = in_ifinit(ifp, ia, &ifaddr, 1);
     918           0 :         if (error) {
     919           0 :                 printf("pppx: unable to set addresses for %s, error=%d\n",
     920             :                     ifp->if_xname, error);
     921           0 :         } else {
     922           0 :                 dohooks(ifp->if_addrhooks, 0);
     923             :         }
     924           0 :         rw_enter_write(&pppx_ifs_lk);
     925           0 :         pxi->pxi_ready = 1;
     926           0 :         rw_exit_write(&pppx_ifs_lk);
     927             : 
     928             : out:
     929           0 :         return (error);
     930           0 : }
     931             : 
     932             : int
     933           0 : pppx_del_session(struct pppx_dev *pxd, struct pipex_session_close_req *req)
     934             : {
     935             :         struct pppx_if *pxi;
     936             : 
     937           0 :         pxi = pppx_if_find(pxd, req->pcr_session_id, req->pcr_protocol);
     938           0 :         if (pxi == NULL)
     939           0 :                 return (EINVAL);
     940             : 
     941           0 :         req->pcr_stat = pxi->pxi_session.stat;
     942             : 
     943           0 :         pppx_if_destroy(pxd, pxi);
     944           0 :         return (0);
     945           0 : }
     946             : 
     947             : int
     948           0 : pppx_set_session_descr(struct pppx_dev *pxd,
     949             :     struct pipex_session_descr_req *req)
     950             : {
     951             :         struct pppx_if *pxi;
     952             : 
     953           0 :         pxi = pppx_if_find(pxd, req->pdr_session_id, req->pdr_protocol);
     954           0 :         if (pxi == NULL)
     955           0 :                 return (EINVAL);
     956             : 
     957           0 :         (void)memset(pxi->pxi_if.if_description, 0, IFDESCRSIZE);
     958           0 :         strlcpy(pxi->pxi_if.if_description, req->pdr_descr, IFDESCRSIZE);
     959             : 
     960           0 :         return (0);
     961           0 : }
     962             : 
     963             : void
     964           0 : pppx_if_destroy(struct pppx_dev *pxd, struct pppx_if *pxi)
     965             : {
     966             :         struct ifnet *ifp;
     967             :         struct pipex_session *session;
     968             : 
     969           0 :         NET_ASSERT_LOCKED();
     970           0 :         session = &pxi->pxi_session;
     971           0 :         ifp = &pxi->pxi_if;
     972             : 
     973           0 :         LIST_REMOVE(session, id_chain);
     974           0 :         LIST_REMOVE(session, session_list);
     975           0 :         switch (session->protocol) {
     976             :         case PIPEX_PROTO_PPTP:
     977             :         case PIPEX_PROTO_L2TP:
     978           0 :                 LIST_REMOVE((struct pipex_session *)session,
     979             :                     peer_addr_chain);
     980           0 :                 break;
     981             :         }
     982             : 
     983             :         /* if final session is destroyed, stop timer */
     984           0 :         if (LIST_EMPTY(&pipex_session_list))
     985           0 :                 pipex_timer_stop();
     986             : 
     987             :         /* XXXSMP breaks atomicity */
     988           0 :         NET_UNLOCK();
     989           0 :         if_detach(ifp);
     990           0 :         NET_LOCK();
     991             : 
     992           0 :         rw_enter_write(&pppx_ifs_lk);
     993           0 :         if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
     994           0 :                 panic("%s: pppx_ifs modified while lock was held", __func__);
     995           0 :         LIST_REMOVE(pxi, pxi_list);
     996           0 :         rw_exit_write(&pppx_ifs_lk);
     997             : 
     998           0 :         pool_put(pppx_if_pl, pxi);
     999           0 : }
    1000             : 
    1001             : void
    1002           0 : pppx_if_start(struct ifnet *ifp)
    1003             : {
    1004           0 :         struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
    1005             :         struct mbuf *m;
    1006             :         int proto;
    1007             : 
    1008           0 :         if (!ISSET(ifp->if_flags, IFF_RUNNING))
    1009           0 :                 return;
    1010             : 
    1011           0 :         for (;;) {
    1012           0 :                 IFQ_DEQUEUE(&ifp->if_snd, m);
    1013             : 
    1014           0 :                 if (m == NULL)
    1015             :                         break;
    1016             : 
    1017           0 :                 proto = *mtod(m, int *);
    1018           0 :                 m_adj(m, sizeof(proto));
    1019             : 
    1020           0 :                 ifp->if_obytes += m->m_pkthdr.len;
    1021           0 :                 ifp->if_opackets++;
    1022             : 
    1023           0 :                 pipex_ppp_output(m, &pxi->pxi_session, proto);
    1024             :         }
    1025           0 : }
    1026             : 
    1027             : int
    1028           0 : pppx_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
    1029             :     struct rtentry *rt)
    1030             : {
    1031           0 :         struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
    1032             :         struct pppx_hdr *th;
    1033             :         int error = 0;
    1034             :         int proto;
    1035             : 
    1036           0 :         NET_ASSERT_LOCKED();
    1037             : 
    1038           0 :         if (!ISSET(ifp->if_flags, IFF_UP)) {
    1039           0 :                 m_freem(m);
    1040             :                 error = ENETDOWN;
    1041           0 :                 goto out;
    1042             :         }
    1043             : 
    1044             : #if NBPFILTER > 0
    1045           0 :         if (ifp->if_bpf)
    1046           0 :                 bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT);
    1047             : #endif
    1048           0 :         if (pipex_enable) {
    1049           0 :                 switch (dst->sa_family) {
    1050             :                 case AF_INET:
    1051             :                         proto = PPP_IP;
    1052             :                         break;
    1053             :                 default:
    1054           0 :                         m_freem(m);
    1055             :                         error = EPFNOSUPPORT;
    1056           0 :                         goto out;
    1057             :                 }
    1058           0 :         } else
    1059           0 :                 proto = htonl(dst->sa_family);
    1060             : 
    1061           0 :         M_PREPEND(m, sizeof(int), M_DONTWAIT);
    1062           0 :         if (m == NULL) {
    1063             :                 error = ENOBUFS;
    1064           0 :                 goto out;
    1065             :         }
    1066           0 :         *mtod(m, int *) = proto;
    1067             : 
    1068           0 :         if (pipex_enable)
    1069           0 :                 error = if_enqueue(ifp, m);
    1070             :         else {
    1071           0 :                 M_PREPEND(m, sizeof(struct pppx_hdr), M_DONTWAIT);
    1072           0 :                 if (m == NULL) {
    1073             :                         error = ENOBUFS;
    1074           0 :                         goto out;
    1075             :                 }
    1076           0 :                 th = mtod(m, struct pppx_hdr *);
    1077           0 :                 th->pppx_proto = 0;  /* not used */
    1078           0 :                 th->pppx_id = pxi->pxi_session.ppp_id;
    1079           0 :                 rw_enter_read(&pppx_devs_lk);
    1080           0 :                 error = mq_enqueue(&pxi->pxi_dev->pxd_svcq, m);
    1081           0 :                 if (error == 0) {
    1082           0 :                         if (pxi->pxi_dev->pxd_waiting) {
    1083           0 :                                 wakeup((caddr_t)pxi->pxi_dev);
    1084           0 :                                 pxi->pxi_dev->pxd_waiting = 0;
    1085           0 :                         }
    1086           0 :                         selwakeup(&pxi->pxi_dev->pxd_rsel);
    1087           0 :                 }
    1088           0 :                 rw_exit_read(&pppx_devs_lk);
    1089             :         }
    1090             : 
    1091             : out:
    1092           0 :         if (error)
    1093           0 :                 ifp->if_oerrors++;
    1094           0 :         return (error);
    1095             : }
    1096             : 
    1097             : int
    1098           0 : pppx_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
    1099             : {
    1100           0 :         struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
    1101           0 :         struct ifreq *ifr = (struct ifreq *)addr;
    1102             :         int error = 0;
    1103             : 
    1104           0 :         switch (cmd) {
    1105             :         case SIOCSIFADDR:
    1106             :                 break;
    1107             : 
    1108             :         case SIOCSIFFLAGS:
    1109             :                 break;
    1110             : 
    1111             :         case SIOCADDMULTI:
    1112             :         case SIOCDELMULTI:
    1113             :                 break;
    1114             : 
    1115             :         case SIOCSIFMTU:
    1116           0 :                 if (ifr->ifr_mtu < 512 ||
    1117           0 :                     ifr->ifr_mtu > pxi->pxi_session.peer_mru)
    1118           0 :                         error = EINVAL;
    1119             :                 else
    1120           0 :                         ifp->if_mtu = ifr->ifr_mtu;
    1121             :                 break;
    1122             : 
    1123             :         default:
    1124             :                 error = ENOTTY;
    1125           0 :                 break;
    1126             :         }
    1127             : 
    1128           0 :         return (error);
    1129             : }
    1130             : 
    1131           0 : RBT_GENERATE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);

Generated by: LCOV version 1.13