1 1.136 riastrad /* $NetBSD: if_sl.c,v 1.136 2022/10/26 23:42:42 riastradh Exp $ */ 2 1.29 cgd 3 1.1 cgd /* 4 1.28 mycroft * Copyright (c) 1987, 1989, 1992, 1993 5 1.28 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.84 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd * 31 1.47 fvdl * @(#)if_sl.c 8.9 (Berkeley) 1/9/95 32 1.1 cgd */ 33 1.1 cgd 34 1.1 cgd /* 35 1.1 cgd * Serial Line interface 36 1.1 cgd * 37 1.1 cgd * Rick Adams 38 1.1 cgd * Center for Seismic Studies 39 1.1 cgd * 1300 N 17th Street, Suite 1450 40 1.1 cgd * Arlington, Virginia 22209 41 1.1 cgd * (703)276-7900 42 1.1 cgd * rick (at) seismo.ARPA 43 1.1 cgd * seismo!rick 44 1.1 cgd * 45 1.1 cgd * Pounded on heavily by Chris Torek (chris (at) mimsy.umd.edu, umcp-cs!chris). 46 1.1 cgd * N.B.: this belongs in netinet, not net, the way it stands now. 47 1.1 cgd * Should have a link-layer type designation, but wouldn't be 48 1.1 cgd * backwards-compatible. 49 1.1 cgd * 50 1.1 cgd * Converted to 4.3BSD Beta by Chris Torek. 51 1.1 cgd * Other changes made at Berkeley, based in part on code by Kirk Smith. 52 1.1 cgd * W. Jolitz added slip abort. 53 1.1 cgd * 54 1.1 cgd * Hacked almost beyond recognition by Van Jacobson (van (at) helios.ee.lbl.gov). 55 1.1 cgd * Added priority queuing for "interactive" traffic; hooks for TCP 56 1.1 cgd * header compression; ICMP filtering (at 2400 baud, some cretin 57 1.1 cgd * pinging you can use up all your bandwidth). Made low clist behavior 58 1.1 cgd * more robust and slightly less likely to hang serial line. 59 1.1 cgd * Sped up a bunch of things. 60 1.1 cgd */ 61 1.78 lukem 62 1.78 lukem #include <sys/cdefs.h> 63 1.136 riastrad __KERNEL_RCSID(0, "$NetBSD: if_sl.c,v 1.136 2022/10/26 23:42:42 riastradh Exp $"); 64 1.1 cgd 65 1.121 pooka #ifdef _KERNEL_OPT 66 1.50 jonathan #include "opt_inet.h" 67 1.121 pooka #endif 68 1.22 cgd 69 1.20 mycroft #include <sys/param.h> 70 1.20 mycroft #include <sys/proc.h> 71 1.45 thorpej #include <sys/malloc.h> 72 1.20 mycroft #include <sys/mbuf.h> 73 1.20 mycroft #include <sys/buf.h> 74 1.20 mycroft #include <sys/dkstat.h> 75 1.20 mycroft #include <sys/socket.h> 76 1.20 mycroft #include <sys/ioctl.h> 77 1.20 mycroft #include <sys/file.h> 78 1.59 itohy #include <sys/conf.h> 79 1.20 mycroft #include <sys/tty.h> 80 1.20 mycroft #include <sys/kernel.h> 81 1.111 ad #include <sys/socketvar.h> 82 1.38 christos #if __NetBSD__ 83 1.38 christos #include <sys/systm.h> 84 1.97 elad #include <sys/kauth.h> 85 1.38 christos #endif 86 1.108 ad #include <sys/cpu.h> 87 1.108 ad #include <sys/intr.h> 88 1.125 christos #include <sys/device.h> 89 1.125 christos #include <sys/module.h> 90 1.22 cgd 91 1.20 mycroft #include <net/if.h> 92 1.20 mycroft #include <net/if_types.h> 93 1.20 mycroft #include <net/route.h> 94 1.1 cgd 95 1.51 jtk #ifdef INET 96 1.20 mycroft #include <netinet/in.h> 97 1.20 mycroft #include <netinet/in_systm.h> 98 1.20 mycroft #include <netinet/in_var.h> 99 1.20 mycroft #include <netinet/ip.h> 100 1.1 cgd #endif 101 1.1 cgd 102 1.20 mycroft #include <net/slcompress.h> 103 1.20 mycroft #include <net/if_slvar.h> 104 1.26 cgd #include <net/slip.h> 105 1.96 christos #include <net/ppp_defs.h> 106 1.96 christos #include <net/if_ppp.h> 107 1.3 cgd 108 1.3 cgd #include <sys/time.h> 109 1.3 cgd #include <net/bpf.h> 110 1.1 cgd 111 1.120 uebayasi #include "ioconf.h" 112 1.120 uebayasi 113 1.1 cgd /* 114 1.1 cgd * SLMAX is a hard limit on input packet size. To simplify the code 115 1.1 cgd * and improve performance, we require that packets fit in an mbuf 116 1.1 cgd * cluster, and if we get a compressed packet, there's enough extra 117 1.1 cgd * room to expand the header into a max length tcp/ip header (128 118 1.1 cgd * bytes). So, SLMAX can be at most 119 1.1 cgd * MCLBYTES - 128 120 1.1 cgd * 121 1.1 cgd * SLMTU is a hard limit on output packet size. To insure good 122 1.1 cgd * interactive response, SLMTU wants to be the smallest size that 123 1.1 cgd * amortizes the header cost. (Remember that even with 124 1.1 cgd * type-of-service queuing, we have to wait for any in-progress 125 1.1 cgd * packet to finish. I.e., we wait, on the average, 1/2 * mtu / 126 1.1 cgd * cps, where cps is the line speed in characters per second. 127 1.1 cgd * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The 128 1.1 cgd * average compressed header size is 6-8 bytes so any MTU > 90 129 1.1 cgd * bytes will give us 90% of the line bandwidth. A 100ms wait is 130 1.1 cgd * tolerable (500ms is not), so want an MTU around 296. (Since TCP 131 1.1 cgd * will send 256 byte segments (to allow for 40 byte headers), the 132 1.1 cgd * typical packet size on the wire will be around 260 bytes). In 133 1.1 cgd * 4.3tahoe+ systems, we can set an MTU in a route so we do that & 134 1.1 cgd * leave the interface MTU relatively high (so we don't IP fragment 135 1.1 cgd * when acting as a gateway to someone using a stupid MTU). 136 1.1 cgd * 137 1.1 cgd * Similar considerations apply to SLIP_HIWAT: It's the amount of 138 1.1 cgd * data that will be queued 'downstream' of us (i.e., in clists 139 1.1 cgd * waiting to be picked up by the tty output interrupt). If we 140 1.1 cgd * queue a lot of data downstream, it's immune to our t.o.s. queuing. 141 1.1 cgd * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed 142 1.1 cgd * telnet/ftp will see a 1 sec wait, independent of the mtu (the 143 1.1 cgd * wait is dependent on the ftp window size but that's typically 144 1.1 cgd * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize 145 1.1 cgd * the cost (in idle time on the wire) of the tty driver running 146 1.1 cgd * off the end of its clists & having to call back slstart for a 147 1.1 cgd * new packet. For a tty interface with any buffering at all, this 148 1.1 cgd * cost will be zero. Even with a totally brain dead interface (like 149 1.1 cgd * the one on a typical workstation), the cost will be <= 1 character 150 1.1 cgd * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose 151 1.1 cgd * at most 1% while maintaining good interactive response. 152 1.1 cgd */ 153 1.22 cgd #define BUFOFFSET (128+sizeof(struct ifnet **)+SLIP_HDRLEN) 154 1.1 cgd #define SLMAX (MCLBYTES - BUFOFFSET) 155 1.1 cgd #define SLBUFSIZE (SLMAX + BUFOFFSET) 156 1.27 cgd #ifndef SLMTU 157 1.22 cgd #define SLMTU 296 158 1.27 cgd #endif 159 1.27 cgd #if (SLMTU < 3) 160 1.53 kleink #error SLMTU way too small. 161 1.27 cgd #endif 162 1.118 christos #define SLIP_HIWAT roundup(50, TTROUND) 163 1.52 mrg #ifndef __NetBSD__ /* XXX - cgd */ 164 1.22 cgd #define CLISTRESERVE 1024 /* Can't let clists get too low */ 165 1.52 mrg #endif /* !__NetBSD__ */ 166 1.1 cgd 167 1.1 cgd /* 168 1.1 cgd * SLIP ABORT ESCAPE MECHANISM: 169 1.1 cgd * (inspired by HAYES modem escape arrangement) 170 1.1 cgd * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } 171 1.22 cgd * within window time signals a "soft" exit from slip mode by remote end 172 1.22 cgd * if the IFF_DEBUG flag is on. 173 1.1 cgd */ 174 1.1 cgd #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ 175 1.22 cgd #define ABT_IDLE 1 /* in seconds - idle before an escape */ 176 1.22 cgd #define ABT_COUNT 3 /* count of escapes for abort */ 177 1.22 cgd #define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */ 178 1.1 cgd 179 1.87 christos static int sl_clone_create(struct if_clone *, int); 180 1.87 christos static int sl_clone_destroy(struct ifnet *); 181 1.87 christos 182 1.87 christos static LIST_HEAD(, sl_softc) sl_softc_list; 183 1.87 christos 184 1.87 christos struct if_clone sl_cloner = 185 1.87 christos IF_CLONE_INITIALIZER("sl", sl_clone_create, sl_clone_destroy); 186 1.1 cgd 187 1.99 tsutsui #define FRAME_END 0xc0 /* Frame End */ 188 1.1 cgd #define FRAME_ESCAPE 0xdb /* Frame Esc */ 189 1.99 tsutsui #define TRANS_FRAME_END 0xdc /* transposed frame end */ 190 1.99 tsutsui #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ 191 1.1 cgd 192 1.95 thorpej static void slintr(void *); 193 1.71 thorpej 194 1.125 christos static int slcreate(struct sl_softc *); 195 1.95 thorpej static struct mbuf *sl_btom(struct sl_softc *, int); 196 1.95 thorpej 197 1.95 thorpej static int slclose(struct tty *, int); 198 1.95 thorpej static int slinput(int, struct tty *); 199 1.105 christos static int slioctl(struct ifnet *, u_long, void *); 200 1.95 thorpej static int slopen(dev_t, struct tty *); 201 1.104 dyoung static int sloutput(struct ifnet *, struct mbuf *, const struct sockaddr *, 202 1.123 ozaki const struct rtentry *); 203 1.95 thorpej static int slstart(struct tty *); 204 1.105 christos static int sltioctl(struct tty *, u_long, void *, int, struct lwp *); 205 1.1 cgd 206 1.93 thorpej static struct linesw slip_disc = { 207 1.93 thorpej .l_name = "slip", 208 1.93 thorpej .l_open = slopen, 209 1.93 thorpej .l_close = slclose, 210 1.93 thorpej .l_read = ttyerrio, 211 1.93 thorpej .l_write = ttyerrio, 212 1.93 thorpej .l_ioctl = sltioctl, 213 1.93 thorpej .l_rint = slinput, 214 1.93 thorpej .l_start = slstart, 215 1.93 thorpej .l_modem = nullmodem, 216 1.93 thorpej .l_poll = ttyerrpoll 217 1.93 thorpej }; 218 1.93 thorpej 219 1.22 cgd void 220 1.120 uebayasi slattach(int n __unused) 221 1.87 christos { 222 1.99 tsutsui 223 1.125 christos /* 224 1.125 christos * Nothing to do here, initialization is handled by the 225 1.125 christos * module initialization code in slinit() below). 226 1.125 christos */ 227 1.125 christos } 228 1.125 christos 229 1.125 christos static void 230 1.125 christos slinit(void) 231 1.125 christos { 232 1.125 christos 233 1.93 thorpej if (ttyldisc_attach(&slip_disc) != 0) 234 1.125 christos panic("%s", __func__); 235 1.89 peter LIST_INIT(&sl_softc_list); 236 1.89 peter if_clone_attach(&sl_cloner); 237 1.87 christos } 238 1.87 christos 239 1.89 peter static int 240 1.125 christos sldetach(void) 241 1.125 christos { 242 1.125 christos int error = 0; 243 1.125 christos 244 1.125 christos if (!LIST_EMPTY(&sl_softc_list)) 245 1.125 christos error = EBUSY; 246 1.125 christos 247 1.125 christos if (error == 0) 248 1.125 christos error = ttyldisc_detach(&slip_disc); 249 1.125 christos 250 1.126 christos if (error == 0) 251 1.126 christos if_clone_detach(&sl_cloner); 252 1.126 christos 253 1.125 christos return error; 254 1.125 christos } 255 1.125 christos 256 1.125 christos static int 257 1.87 christos sl_clone_create(struct if_clone *ifc, int unit) 258 1.1 cgd { 259 1.57 augustss struct sl_softc *sc; 260 1.1 cgd 261 1.114 cegger sc = malloc(sizeof(*sc), M_DEVBUF, M_WAIT|M_ZERO); 262 1.87 christos sc->sc_unit = unit; 263 1.112 christos if_initname(&sc->sc_if, ifc->ifc_name, unit); 264 1.87 christos sc->sc_if.if_softc = sc; 265 1.87 christos sc->sc_if.if_mtu = SLMTU; 266 1.89 peter sc->sc_if.if_flags = IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST; 267 1.87 christos sc->sc_if.if_type = IFT_SLIP; 268 1.87 christos sc->sc_if.if_ioctl = slioctl; 269 1.87 christos sc->sc_if.if_output = sloutput; 270 1.87 christos sc->sc_if.if_dlt = DLT_SLIP; 271 1.133 thorpej IFQ_SET_MAXLEN(&sc->sc_fastq, 32); 272 1.134 thorpej IFQ_LOCK_INIT(&sc->sc_fastq); 273 1.87 christos IFQ_SET_READY(&sc->sc_if.if_snd); 274 1.87 christos if_attach(&sc->sc_if); 275 1.87 christos if_alloc_sadl(&sc->sc_if); 276 1.117 joerg bpf_attach(&sc->sc_if, DLT_SLIP, SLIP_HDRLEN); 277 1.87 christos LIST_INSERT_HEAD(&sl_softc_list, sc, sc_iflist); 278 1.87 christos return 0; 279 1.87 christos } 280 1.87 christos 281 1.87 christos static int 282 1.87 christos sl_clone_destroy(struct ifnet *ifp) 283 1.87 christos { 284 1.89 peter struct sl_softc *sc = (struct sl_softc *)ifp->if_softc; 285 1.87 christos 286 1.89 peter if (sc->sc_ttyp != NULL) 287 1.89 peter return EBUSY; /* Not removing it */ 288 1.87 christos 289 1.89 peter LIST_REMOVE(sc, sc_iflist); 290 1.87 christos 291 1.117 joerg bpf_detach(ifp); 292 1.89 peter if_detach(ifp); 293 1.87 christos 294 1.134 thorpej IFQ_LOCK_DESTROY(&sc->sc_fastq); 295 1.134 thorpej 296 1.114 cegger free(sc, M_DEVBUF); 297 1.89 peter return 0; 298 1.1 cgd } 299 1.1 cgd 300 1.1 cgd static int 301 1.125 christos slcreate(struct sl_softc *sc) 302 1.1 cgd { 303 1.1 cgd 304 1.64 thorpej if (sc->sc_mbuf == NULL) { 305 1.82 matt sc->sc_mbuf = m_gethdr(M_WAIT, MT_DATA); 306 1.82 matt m_clget(sc->sc_mbuf, M_WAIT); 307 1.64 thorpej } 308 1.99 tsutsui sc->sc_ep = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 309 1.64 thorpej sc->sc_mbuf->m_ext.ext_size; 310 1.99 tsutsui sc->sc_mp = sc->sc_pktstart = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 311 1.64 thorpej BUFOFFSET; 312 1.64 thorpej 313 1.90 christos #ifdef INET 314 1.46 christos sl_compress_init(&sc->sc_comp); 315 1.90 christos #endif 316 1.64 thorpej 317 1.99 tsutsui return 1; 318 1.1 cgd } 319 1.1 cgd 320 1.1 cgd /* 321 1.1 cgd * Line specific open routine. 322 1.1 cgd * Attach the given tty to the first available sl unit. 323 1.1 cgd */ 324 1.1 cgd /* ARGSUSED */ 325 1.95 thorpej static int 326 1.102 christos slopen(dev_t dev, struct tty *tp) 327 1.1 cgd { 328 1.100 ad struct lwp *l = curlwp; /* XXX */ 329 1.57 augustss struct sl_softc *sc; 330 1.1 cgd int error; 331 1.1 cgd 332 1.115 elad error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE_SLIP, 333 1.115 elad KAUTH_REQ_NETWORK_INTERFACE_SLIP_ADD, NULL, NULL, NULL); 334 1.115 elad if (error) 335 1.99 tsutsui return error; 336 1.1 cgd 337 1.93 thorpej if (tp->t_linesw == &slip_disc) 338 1.99 tsutsui return 0; 339 1.1 cgd 340 1.87 christos LIST_FOREACH(sc, &sl_softc_list, sc_iflist) 341 1.1 cgd if (sc->sc_ttyp == NULL) { 342 1.108 ad sc->sc_si = softint_establish(SOFTINT_NET, 343 1.71 thorpej slintr, sc); 344 1.71 thorpej if (sc->sc_si == NULL) 345 1.99 tsutsui return ENOMEM; 346 1.125 christos if (slcreate(sc) == 0) { 347 1.108 ad softint_disestablish(sc->sc_si); 348 1.99 tsutsui return ENOBUFS; 349 1.71 thorpej } 350 1.105 christos tp->t_sc = (void *)sc; 351 1.1 cgd sc->sc_ttyp = tp; 352 1.1 cgd sc->sc_if.if_baudrate = tp->t_ospeed; 353 1.136 riastrad ttylock(tp); 354 1.47 fvdl tp->t_state |= TS_ISOPEN | TS_XCLUDE; 355 1.1 cgd ttyflush(tp, FREAD | FWRITE); 356 1.27 cgd /* 357 1.27 cgd * make sure tty output queue is large enough 358 1.27 cgd * to hold a full-sized packet (including frame 359 1.27 cgd * end, and a possible extra frame end). full-sized 360 1.54 tron * packet occupies a max of 2*SLMAX bytes (because 361 1.27 cgd * of possible escapes), and add two on for frame 362 1.27 cgd * ends. 363 1.27 cgd */ 364 1.99 tsutsui if (tp->t_outq.c_cn < 2 * SLMAX + 2) { 365 1.27 cgd sc->sc_oldbufsize = tp->t_outq.c_cn; 366 1.27 cgd sc->sc_oldbufquot = tp->t_outq.c_cq != 0; 367 1.27 cgd 368 1.27 cgd clfree(&tp->t_outq); 369 1.136 riastrad ttyunlock(tp); 370 1.99 tsutsui error = clalloc(&tp->t_outq, 2 * SLMAX + 2, 0); 371 1.27 cgd if (error) { 372 1.108 ad softint_disestablish(sc->sc_si); 373 1.80 atatat /* 374 1.80 atatat * clalloc() might return -1 which 375 1.80 atatat * is no good, so we need to return 376 1.80 atatat * something else. 377 1.80 atatat */ 378 1.99 tsutsui return ENOMEM; /* XXX ?! */ 379 1.27 cgd } 380 1.109 ad } else { 381 1.27 cgd sc->sc_oldbufsize = sc->sc_oldbufquot = 0; 382 1.136 riastrad ttyunlock(tp); 383 1.109 ad } 384 1.99 tsutsui return 0; 385 1.1 cgd } 386 1.99 tsutsui return ENXIO; 387 1.1 cgd } 388 1.1 cgd 389 1.1 cgd /* 390 1.1 cgd * Line specific close routine. 391 1.1 cgd * Detach the tty from the sl unit. 392 1.1 cgd */ 393 1.95 thorpej static int 394 1.102 christos slclose(struct tty *tp, int flag) 395 1.1 cgd { 396 1.57 augustss struct sl_softc *sc; 397 1.1 cgd int s; 398 1.1 cgd 399 1.1 cgd ttywflush(tp); 400 1.69 thorpej sc = tp->t_sc; 401 1.69 thorpej 402 1.1 cgd if (sc != NULL) { 403 1.108 ad softint_disestablish(sc->sc_si); 404 1.69 thorpej s = splnet(); 405 1.1 cgd if_down(&sc->sc_if); 406 1.69 thorpej IF_PURGE(&sc->sc_fastq); 407 1.69 thorpej splx(s); 408 1.69 thorpej 409 1.69 thorpej s = spltty(); 410 1.93 thorpej ttyldisc_release(tp->t_linesw); 411 1.93 thorpej tp->t_linesw = ttyldisc_default(); 412 1.69 thorpej tp->t_state = 0; 413 1.69 thorpej 414 1.1 cgd sc->sc_ttyp = NULL; 415 1.1 cgd tp->t_sc = NULL; 416 1.69 thorpej 417 1.64 thorpej m_freem(sc->sc_mbuf); 418 1.70 thorpej sc->sc_mbuf = NULL; 419 1.64 thorpej sc->sc_ep = sc->sc_mp = sc->sc_pktstart = NULL; 420 1.65 thorpej IF_PURGE(&sc->sc_inq); 421 1.69 thorpej 422 1.69 thorpej /* 423 1.69 thorpej * If necessary, install a new outq buffer of the 424 1.69 thorpej * appropriate size. 425 1.69 thorpej */ 426 1.69 thorpej if (sc->sc_oldbufsize != 0) { 427 1.69 thorpej clfree(&tp->t_outq); 428 1.69 thorpej clalloc(&tp->t_outq, sc->sc_oldbufsize, 429 1.69 thorpej sc->sc_oldbufquot); 430 1.69 thorpej } 431 1.69 thorpej splx(s); 432 1.1 cgd } 433 1.93 thorpej 434 1.99 tsutsui return 0; 435 1.1 cgd } 436 1.1 cgd 437 1.1 cgd /* 438 1.1 cgd * Line specific (tty) ioctl routine. 439 1.1 cgd * Provide a way to get the sl unit number. 440 1.1 cgd */ 441 1.1 cgd /* ARGSUSED */ 442 1.95 thorpej static int 443 1.105 christos sltioctl(struct tty *tp, u_long cmd, void *data, int flag, 444 1.102 christos struct lwp *l) 445 1.1 cgd { 446 1.1 cgd struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 447 1.1 cgd 448 1.131 knakahar /* 449 1.131 knakahar * XXX 450 1.131 knakahar * This function can be called without KERNEL_LOCK when caller's 451 1.131 knakahar * struct cdevsw is set D_MPSAFE. Is KERNEL_LOCK required? 452 1.131 knakahar */ 453 1.131 knakahar 454 1.1 cgd switch (cmd) { 455 1.1 cgd case SLIOCGUNIT: 456 1.39 thorpej *(int *)data = sc->sc_unit; /* XXX */ 457 1.1 cgd break; 458 1.1 cgd 459 1.1 cgd default: 460 1.99 tsutsui return EPASSTHROUGH; 461 1.1 cgd } 462 1.99 tsutsui return 0; 463 1.1 cgd } 464 1.1 cgd 465 1.1 cgd /* 466 1.1 cgd * Queue a packet. Start transmission if not active. 467 1.67 thorpej * Compression happens in slintr(); if we do it here, IP TOS 468 1.22 cgd * will cause us to not compress "background" packets, because 469 1.67 thorpej * ordering gets trashed. It can be done for all packets in slintr(). 470 1.1 cgd */ 471 1.95 thorpej static int 472 1.104 dyoung sloutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 473 1.123 ozaki const struct rtentry *rtp) 474 1.1 cgd { 475 1.57 augustss struct sl_softc *sc = ifp->if_softc; 476 1.57 augustss struct ip *ip; 477 1.91 christos struct ifqueue *ifq = NULL; 478 1.63 thorpej int s, error; 479 1.63 thorpej 480 1.122 knakahar IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); 481 1.1 cgd 482 1.1 cgd /* 483 1.1 cgd * `Cannot happen' (see slioctl). Someday we will extend 484 1.1 cgd * the line protocol to support other address families. 485 1.1 cgd */ 486 1.1 cgd if (dst->sa_family != AF_INET) { 487 1.44 christos printf("%s: af%d not supported\n", sc->sc_if.if_xname, 488 1.43 christos dst->sa_family); 489 1.1 cgd m_freem(m); 490 1.132 thorpej if_statinc(&sc->sc_if, if_noproto); 491 1.99 tsutsui return EAFNOSUPPORT; 492 1.1 cgd } 493 1.1 cgd 494 1.1 cgd if (sc->sc_ttyp == NULL) { 495 1.1 cgd m_freem(m); 496 1.99 tsutsui return ENETDOWN; /* sort of */ 497 1.1 cgd } 498 1.14 mycroft if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 && 499 1.14 mycroft (sc->sc_ttyp->t_cflag & CLOCAL) == 0) { 500 1.1 cgd m_freem(m); 501 1.49 enami printf("%s: no carrier and not local\n", sc->sc_if.if_xname); 502 1.99 tsutsui return EHOSTUNREACH; 503 1.1 cgd } 504 1.22 cgd ip = mtod(m, struct ip *); 505 1.90 christos #ifdef INET 506 1.22 cgd if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 507 1.1 cgd m_freem(m); 508 1.99 tsutsui return ENETRESET; /* XXX ? */ 509 1.1 cgd } 510 1.90 christos #endif 511 1.69 thorpej 512 1.69 thorpej s = spltty(); 513 1.27 cgd if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) { 514 1.98 kardel struct bintime bt; 515 1.27 cgd 516 1.27 cgd /* if output's been stalled for too long, and restart */ 517 1.98 kardel getbinuptime(&bt); 518 1.98 kardel bintime_sub(&bt, &sc->sc_lastpacket); 519 1.98 kardel if (bt.sec > 0) { 520 1.27 cgd sc->sc_otimeout++; 521 1.27 cgd slstart(sc->sc_ttyp); 522 1.27 cgd } 523 1.27 cgd } 524 1.69 thorpej splx(s); 525 1.69 thorpej 526 1.69 thorpej s = splnet(); 527 1.90 christos #ifdef INET 528 1.91 christos if ((ip->ip_tos & IPTOS_LOWDELAY) != 0) 529 1.91 christos ifq = &sc->sc_fastq; 530 1.90 christos #endif 531 1.122 knakahar if ((error = ifq_enqueue2(ifp, ifq, m)) != 0) { 532 1.1 cgd splx(s); 533 1.91 christos return error; 534 1.1 cgd } 535 1.98 kardel getbinuptime(&sc->sc_lastpacket); 536 1.69 thorpej splx(s); 537 1.69 thorpej 538 1.69 thorpej s = spltty(); 539 1.27 cgd if ((sc->sc_oqlen = sc->sc_ttyp->t_outq.c_cc) == 0) 540 1.1 cgd slstart(sc->sc_ttyp); 541 1.1 cgd splx(s); 542 1.69 thorpej 543 1.99 tsutsui return 0; 544 1.1 cgd } 545 1.1 cgd 546 1.1 cgd /* 547 1.1 cgd * Start output on interface. Get another datagram 548 1.1 cgd * to send from the interface queue and map it to 549 1.1 cgd * the interface before starting output. 550 1.1 cgd */ 551 1.95 thorpej static int 552 1.95 thorpej slstart(struct tty *tp) 553 1.1 cgd { 554 1.71 thorpej struct sl_softc *sc = tp->t_sc; 555 1.1 cgd 556 1.67 thorpej /* 557 1.67 thorpej * If there is more in the output queue, just send it now. 558 1.67 thorpej * We are being called in lieu of ttstart and must do what 559 1.67 thorpej * it would. 560 1.67 thorpej */ 561 1.67 thorpej if (tp->t_outq.c_cc != 0) { 562 1.67 thorpej (*tp->t_oproc)(tp); 563 1.67 thorpej if (tp->t_outq.c_cc > SLIP_HIWAT) 564 1.99 tsutsui return 0; 565 1.67 thorpej } 566 1.1 cgd 567 1.67 thorpej /* 568 1.67 thorpej * This happens briefly when the line shuts down. 569 1.67 thorpej */ 570 1.71 thorpej if (sc == NULL) 571 1.99 tsutsui return 0; 572 1.108 ad softint_schedule(sc->sc_si); 573 1.99 tsutsui return 0; 574 1.1 cgd } 575 1.1 cgd 576 1.1 cgd /* 577 1.1 cgd * Copy data buffer to mbuf chain; add ifnet pointer. 578 1.1 cgd */ 579 1.1 cgd static struct mbuf * 580 1.95 thorpej sl_btom(struct sl_softc *sc, int len) 581 1.1 cgd { 582 1.57 augustss struct mbuf *m; 583 1.1 cgd 584 1.1 cgd /* 585 1.66 thorpej * Allocate a new input buffer and swap. 586 1.1 cgd */ 587 1.66 thorpej m = sc->sc_mbuf; 588 1.66 thorpej MGETHDR(sc->sc_mbuf, M_DONTWAIT, MT_DATA); 589 1.66 thorpej if (sc->sc_mbuf == NULL) { 590 1.66 thorpej sc->sc_mbuf = m; 591 1.99 tsutsui return NULL; 592 1.66 thorpej } 593 1.66 thorpej MCLGET(sc->sc_mbuf, M_DONTWAIT); 594 1.66 thorpej if ((sc->sc_mbuf->m_flags & M_EXT) == 0) { 595 1.68 thorpej m_freem(sc->sc_mbuf); 596 1.66 thorpej sc->sc_mbuf = m; 597 1.99 tsutsui return NULL; 598 1.66 thorpej } 599 1.99 tsutsui sc->sc_ep = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 600 1.66 thorpej sc->sc_mbuf->m_ext.ext_size; 601 1.64 thorpej 602 1.66 thorpej m->m_data = sc->sc_pktstart; 603 1.1 cgd 604 1.64 thorpej m->m_pkthdr.len = m->m_len = len; 605 1.124 ozaki m_set_rcvif(m, &sc->sc_if); 606 1.99 tsutsui return m; 607 1.1 cgd } 608 1.1 cgd 609 1.1 cgd /* 610 1.1 cgd * tty interface receiver interrupt. 611 1.1 cgd */ 612 1.95 thorpej static int 613 1.95 thorpej slinput(int c, struct tty *tp) 614 1.1 cgd { 615 1.57 augustss struct sl_softc *sc; 616 1.57 augustss struct mbuf *m; 617 1.57 augustss int len; 618 1.22 cgd 619 1.1 cgd tk_nin++; 620 1.1 cgd sc = (struct sl_softc *)tp->t_sc; 621 1.1 cgd if (sc == NULL) 622 1.99 tsutsui return 0; 623 1.47 fvdl if ((c & TTY_ERRORMASK) || ((tp->t_state & TS_CARR_ON) == 0 && 624 1.22 cgd (tp->t_cflag & CLOCAL) == 0)) { 625 1.2 cgd sc->sc_flags |= SC_ERROR; 626 1.99 tsutsui return 0; 627 1.2 cgd } 628 1.22 cgd c &= TTY_CHARMASK; 629 1.1 cgd 630 1.132 thorpej if_statinc(&sc->sc_if, if_ibytes); 631 1.1 cgd 632 1.19 cgd if (sc->sc_if.if_flags & IFF_DEBUG) { 633 1.22 cgd if (c == ABT_ESC) { 634 1.22 cgd /* 635 1.22 cgd * If we have a previous abort, see whether 636 1.22 cgd * this one is within the time limit. 637 1.22 cgd */ 638 1.22 cgd if (sc->sc_abortcount && 639 1.98 kardel time_second >= sc->sc_starttime + ABT_WINDOW) 640 1.1 cgd sc->sc_abortcount = 0; 641 1.22 cgd /* 642 1.22 cgd * If we see an abort after "idle" time, count it; 643 1.22 cgd * record when the first abort escape arrived. 644 1.22 cgd */ 645 1.98 kardel if (time_second >= sc->sc_lasttime + ABT_IDLE) { 646 1.22 cgd if (++sc->sc_abortcount == 1) 647 1.98 kardel sc->sc_starttime = time_second; 648 1.22 cgd if (sc->sc_abortcount >= ABT_COUNT) { 649 1.93 thorpej slclose(tp, 0); 650 1.99 tsutsui return 0; 651 1.22 cgd } 652 1.1 cgd } 653 1.22 cgd } else 654 1.22 cgd sc->sc_abortcount = 0; 655 1.98 kardel sc->sc_lasttime = time_second; 656 1.1 cgd } 657 1.1 cgd 658 1.1 cgd switch (c) { 659 1.1 cgd 660 1.1 cgd case TRANS_FRAME_ESCAPE: 661 1.1 cgd if (sc->sc_escape) 662 1.1 cgd c = FRAME_ESCAPE; 663 1.1 cgd break; 664 1.1 cgd 665 1.1 cgd case TRANS_FRAME_END: 666 1.1 cgd if (sc->sc_escape) 667 1.1 cgd c = FRAME_END; 668 1.1 cgd break; 669 1.1 cgd 670 1.1 cgd case FRAME_ESCAPE: 671 1.1 cgd sc->sc_escape = 1; 672 1.99 tsutsui return 0; 673 1.1 cgd 674 1.1 cgd case FRAME_END: 675 1.99 tsutsui if (sc->sc_flags & SC_ERROR) { 676 1.2 cgd sc->sc_flags &= ~SC_ERROR; 677 1.2 cgd goto newpack; 678 1.2 cgd } 679 1.64 thorpej len = sc->sc_mp - sc->sc_pktstart; 680 1.1 cgd if (len < 3) 681 1.1 cgd /* less than min length packet - ignore */ 682 1.1 cgd goto newpack; 683 1.1 cgd 684 1.64 thorpej m = sl_btom(sc, len); 685 1.64 thorpej if (m == NULL) 686 1.64 thorpej goto error; 687 1.64 thorpej 688 1.65 thorpej IF_ENQUEUE(&sc->sc_inq, m); 689 1.108 ad softint_schedule(sc->sc_si); 690 1.1 cgd goto newpack; 691 1.1 cgd } 692 1.1 cgd if (sc->sc_mp < sc->sc_ep) { 693 1.1 cgd *sc->sc_mp++ = c; 694 1.1 cgd sc->sc_escape = 0; 695 1.99 tsutsui return 0; 696 1.1 cgd } 697 1.22 cgd 698 1.22 cgd /* can't put lower; would miss an extra frame */ 699 1.3 cgd sc->sc_flags |= SC_ERROR; 700 1.22 cgd 701 1.1 cgd error: 702 1.132 thorpej if_statinc(&sc->sc_if, if_ierrors); 703 1.1 cgd newpack: 704 1.99 tsutsui sc->sc_mp = sc->sc_pktstart = (u_char *)sc->sc_mbuf->m_ext.ext_buf + 705 1.64 thorpej BUFOFFSET; 706 1.1 cgd sc->sc_escape = 0; 707 1.93 thorpej 708 1.99 tsutsui return 0; 709 1.65 thorpej } 710 1.65 thorpej 711 1.95 thorpej static void 712 1.71 thorpej slintr(void *arg) 713 1.71 thorpej { 714 1.71 thorpej struct sl_softc *sc = arg; 715 1.71 thorpej struct tty *tp = sc->sc_ttyp; 716 1.128 maya struct mbuf *m, *n; 717 1.71 thorpej int s, len; 718 1.90 christos u_char *pktstart; 719 1.66 thorpej u_char chdr[CHDR_LEN]; 720 1.65 thorpej 721 1.71 thorpej KASSERT(tp != NULL); 722 1.67 thorpej 723 1.71 thorpej /* 724 1.71 thorpej * Output processing loop. 725 1.71 thorpej */ 726 1.111 ad mutex_enter(softnet_lock); 727 1.71 thorpej for (;;) { 728 1.71 thorpej struct mbuf *m2; 729 1.71 thorpej struct mbuf *bpf_m; 730 1.67 thorpej 731 1.67 thorpej /* 732 1.71 thorpej * Do not remove the packet from the queue if it 733 1.71 thorpej * doesn't look like it will fit into the current 734 1.71 thorpej * serial output queue. With a packet full of 735 1.71 thorpej * escapes, this could be as bad as MTU*2+2. 736 1.67 thorpej */ 737 1.71 thorpej s = spltty(); 738 1.71 thorpej if (tp->t_outq.c_cn - tp->t_outq.c_cc < 739 1.99 tsutsui 2 * sc->sc_if.if_mtu + 2) { 740 1.67 thorpej splx(s); 741 1.71 thorpej break; 742 1.71 thorpej } 743 1.71 thorpej splx(s); 744 1.67 thorpej 745 1.71 thorpej /* 746 1.71 thorpej * Get a packet and send it to the interface. 747 1.71 thorpej */ 748 1.71 thorpej s = splnet(); 749 1.71 thorpej IF_DEQUEUE(&sc->sc_fastq, m); 750 1.71 thorpej if (m) 751 1.132 thorpej if_statinc(&sc->sc_if, if_omcasts); /* XXX */ 752 1.71 thorpej else 753 1.71 thorpej IFQ_DEQUEUE(&sc->sc_if.if_snd, m); 754 1.71 thorpej splx(s); 755 1.67 thorpej 756 1.71 thorpej if (m == NULL) 757 1.71 thorpej break; 758 1.67 thorpej 759 1.71 thorpej /* 760 1.71 thorpej * We do the header compression here rather than in 761 1.71 thorpej * sloutput() because the packets will be out of order 762 1.71 thorpej * if we are using TOS queueing, and the connection 763 1.71 thorpej * ID compression will get munged when this happens. 764 1.71 thorpej */ 765 1.71 thorpej if (sc->sc_if.if_bpf) { 766 1.67 thorpej /* 767 1.71 thorpej * We need to save the TCP/IP header before 768 1.71 thorpej * it's compressed. To avoid complicated 769 1.71 thorpej * code, we just make a deep copy of the 770 1.71 thorpej * entire packet (since this is a serial 771 1.71 thorpej * line, packets should be short and/or the 772 1.71 thorpej * copy should be negligible cost compared 773 1.71 thorpej * to the packet transmission time). 774 1.67 thorpej */ 775 1.71 thorpej bpf_m = m_dup(m, 0, M_COPYALL, M_DONTWAIT); 776 1.71 thorpej } else 777 1.71 thorpej bpf_m = NULL; 778 1.90 christos #ifdef INET 779 1.128 maya struct ip *ip; 780 1.71 thorpej if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { 781 1.71 thorpej if (sc->sc_if.if_flags & SC_COMPRESS) 782 1.71 thorpej *mtod(m, u_char *) |= 783 1.99 tsutsui sl_compress_tcp(m, ip, &sc->sc_comp, 1); 784 1.71 thorpej } 785 1.90 christos #endif 786 1.117 joerg if (bpf_m) 787 1.117 joerg bpf_mtap_sl_out(&sc->sc_if, mtod(m, u_char *), bpf_m); 788 1.98 kardel getbinuptime(&sc->sc_lastpacket); 789 1.67 thorpej 790 1.71 thorpej s = spltty(); 791 1.67 thorpej 792 1.71 thorpej /* 793 1.71 thorpej * The extra FRAME_END will start up a new packet, 794 1.71 thorpej * and thus will flush any accumulated garbage. We 795 1.71 thorpej * do this whenever the line may have been idle for 796 1.71 thorpej * some time. 797 1.71 thorpej */ 798 1.71 thorpej if (tp->t_outq.c_cc == 0) { 799 1.132 thorpej if_statinc(&sc->sc_if, if_obytes); 800 1.99 tsutsui (void)putc(FRAME_END, &tp->t_outq); 801 1.71 thorpej } 802 1.67 thorpej 803 1.71 thorpej while (m) { 804 1.71 thorpej u_char *bp, *cp, *ep; 805 1.67 thorpej 806 1.71 thorpej bp = cp = mtod(m, u_char *); 807 1.71 thorpej ep = cp + m->m_len; 808 1.71 thorpej while (cp < ep) { 809 1.71 thorpej /* 810 1.71 thorpej * Find out how many bytes in the 811 1.71 thorpej * string we can handle without 812 1.71 thorpej * doing something special. 813 1.71 thorpej */ 814 1.67 thorpej while (cp < ep) { 815 1.71 thorpej switch (*cp++) { 816 1.71 thorpej case FRAME_ESCAPE: 817 1.71 thorpej case FRAME_END: 818 1.71 thorpej cp--; 819 1.71 thorpej goto out; 820 1.67 thorpej } 821 1.71 thorpej } 822 1.71 thorpej out: 823 1.71 thorpej if (cp > bp) { 824 1.67 thorpej /* 825 1.71 thorpej * Put N characters at once 826 1.71 thorpej * into the tty output queue. 827 1.67 thorpej */ 828 1.99 tsutsui if (b_to_q(bp, cp - bp, &tp->t_outq)) 829 1.71 thorpej break; 830 1.132 thorpej if_statadd(&sc->sc_if, if_obytes, 831 1.132 thorpej cp - bp); 832 1.67 thorpej } 833 1.67 thorpej /* 834 1.71 thorpej * If there are characters left in 835 1.71 thorpej * the mbuf, the first one must be 836 1.71 thorpej * special.. Put it out in a different 837 1.71 thorpej * form. 838 1.67 thorpej */ 839 1.71 thorpej if (cp < ep) { 840 1.99 tsutsui if (putc(FRAME_ESCAPE, &tp->t_outq)) 841 1.71 thorpej break; 842 1.71 thorpej if (putc(*cp++ == FRAME_ESCAPE ? 843 1.71 thorpej TRANS_FRAME_ESCAPE : 844 1.71 thorpej TRANS_FRAME_END, 845 1.71 thorpej &tp->t_outq)) { 846 1.99 tsutsui (void)unputc(&tp->t_outq); 847 1.71 thorpej break; 848 1.71 thorpej } 849 1.132 thorpej if_statadd(&sc->sc_if, if_obytes, 2); 850 1.71 thorpej } 851 1.77 martin bp = cp; 852 1.67 thorpej } 853 1.127 christos m = m2 = m_free(m); 854 1.71 thorpej } 855 1.67 thorpej 856 1.71 thorpej if (putc(FRAME_END, &tp->t_outq)) { 857 1.67 thorpej /* 858 1.71 thorpej * Not enough room. Remove a char to make 859 1.71 thorpej * room and end the packet normally. If 860 1.71 thorpej * you get many collisions (more than one 861 1.71 thorpej * or two a day), you probably do not have 862 1.71 thorpej * enough clists and you should increase 863 1.71 thorpej * "nclist" in param.c 864 1.67 thorpej */ 865 1.99 tsutsui (void)unputc(&tp->t_outq); 866 1.99 tsutsui (void)putc(FRAME_END, &tp->t_outq); 867 1.132 thorpej if_statinc(&sc->sc_if, if_collisions); 868 1.71 thorpej } else { 869 1.132 thorpej if_statadd2(&sc->sc_if, if_obytes, 1, if_opackets, 1); 870 1.67 thorpej } 871 1.67 thorpej 872 1.67 thorpej /* 873 1.71 thorpej * We now have characters in the output queue, 874 1.71 thorpej * kick the serial port. 875 1.67 thorpej */ 876 1.71 thorpej (*tp->t_oproc)(tp); 877 1.71 thorpej splx(s); 878 1.71 thorpej } 879 1.71 thorpej 880 1.71 thorpej /* 881 1.71 thorpej * Input processing loop. 882 1.71 thorpej */ 883 1.71 thorpej for (;;) { 884 1.71 thorpej s = spltty(); 885 1.71 thorpej IF_DEQUEUE(&sc->sc_inq, m); 886 1.71 thorpej splx(s); 887 1.71 thorpej if (m == NULL) 888 1.71 thorpej break; 889 1.71 thorpej pktstart = mtod(m, u_char *); 890 1.71 thorpej len = m->m_pkthdr.len; 891 1.71 thorpej if (sc->sc_if.if_bpf) { 892 1.71 thorpej /* 893 1.71 thorpej * Save the compressed header, so we 894 1.71 thorpej * can tack it on later. Note that we 895 1.71 thorpej * will end up copying garbage in some 896 1.71 thorpej * cases but this is okay. We remember 897 1.71 thorpej * where the buffer started so we can 898 1.71 thorpej * compute the new header length. 899 1.71 thorpej */ 900 1.71 thorpej memcpy(chdr, pktstart, CHDR_LEN); 901 1.71 thorpej } 902 1.90 christos #ifdef INET 903 1.128 maya u_char c; 904 1.71 thorpej if ((c = (*pktstart & 0xf0)) != (IPVERSION << 4)) { 905 1.71 thorpej if (c & 0x80) 906 1.71 thorpej c = TYPE_COMPRESSED_TCP; 907 1.71 thorpej else if (c == TYPE_UNCOMPRESSED_TCP) 908 1.71 thorpej *pktstart &= 0x4f; /* XXX */ 909 1.71 thorpej /* 910 1.71 thorpej * We've got something that's not an IP 911 1.71 thorpej * packet. If compression is enabled, 912 1.71 thorpej * try to decompress it. Otherwise, if 913 1.71 thorpej * `auto-enable' compression is on and 914 1.71 thorpej * it's a reasonable packet, decompress 915 1.71 thorpej * it and then enable compression. 916 1.71 thorpej * Otherwise, drop it. 917 1.71 thorpej */ 918 1.71 thorpej if (sc->sc_if.if_flags & SC_COMPRESS) { 919 1.71 thorpej len = sl_uncompress_tcp(&pktstart, len, 920 1.71 thorpej (u_int)c, &sc->sc_comp); 921 1.71 thorpej if (len <= 0) { 922 1.71 thorpej m_freem(m); 923 1.71 thorpej continue; 924 1.71 thorpej } 925 1.71 thorpej } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) && 926 1.71 thorpej c == TYPE_UNCOMPRESSED_TCP && len >= 40) { 927 1.71 thorpej len = sl_uncompress_tcp(&pktstart, len, 928 1.71 thorpej (u_int)c, &sc->sc_comp); 929 1.71 thorpej if (len <= 0) { 930 1.66 thorpej m_freem(m); 931 1.66 thorpej continue; 932 1.66 thorpej } 933 1.71 thorpej sc->sc_if.if_flags |= SC_COMPRESS; 934 1.71 thorpej } else { 935 1.71 thorpej m_freem(m); 936 1.71 thorpej continue; 937 1.66 thorpej } 938 1.71 thorpej } 939 1.90 christos #endif 940 1.105 christos m->m_data = (void *) pktstart; 941 1.71 thorpej m->m_pkthdr.len = m->m_len = len; 942 1.71 thorpej if (sc->sc_if.if_bpf) { 943 1.117 joerg bpf_mtap_sl_in(&sc->sc_if, chdr, &m); 944 1.71 thorpej if (m == NULL) 945 1.71 thorpej continue; 946 1.71 thorpej } 947 1.71 thorpej /* 948 1.71 thorpej * If the packet will fit into a single 949 1.128 maya * header mbuf, try to copy it into one, 950 1.128 maya * to save memory. 951 1.71 thorpej */ 952 1.128 maya if ((m->m_pkthdr.len < MHLEN) && 953 1.128 maya (n = m_gethdr(M_DONTWAIT, MT_DATA))) { 954 1.92 yamt int pktlen; 955 1.66 thorpej 956 1.92 yamt pktlen = m->m_pkthdr.len; 957 1.130 maxv m_move_pkthdr(n, m); 958 1.105 christos memcpy(mtod(n, void *), mtod(m, void *), pktlen); 959 1.71 thorpej n->m_len = m->m_len; 960 1.71 thorpej m_freem(m); 961 1.71 thorpej m = n; 962 1.71 thorpej } 963 1.66 thorpej 964 1.132 thorpej if_statinc(&sc->sc_if, if_ipackets); 965 1.98 kardel getbinuptime(&sc->sc_lastpacket); 966 1.66 thorpej 967 1.90 christos #ifdef INET 968 1.74 thorpej s = splnet(); 969 1.119 rmind if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) { 970 1.132 thorpej if_statadd2(&sc->sc_if, if_ierrors, 1, if_iqdrops, 1); 971 1.71 thorpej m_freem(m); 972 1.65 thorpej } 973 1.71 thorpej splx(s); 974 1.90 christos #endif 975 1.65 thorpej } 976 1.111 ad mutex_exit(softnet_lock); 977 1.1 cgd } 978 1.1 cgd 979 1.1 cgd /* 980 1.1 cgd * Process an ioctl request. 981 1.1 cgd */ 982 1.95 thorpej static int 983 1.105 christos slioctl(struct ifnet *ifp, u_long cmd, void *data) 984 1.1 cgd { 985 1.57 augustss struct ifaddr *ifa = (struct ifaddr *)data; 986 1.57 augustss struct ifreq *ifr = (struct ifreq *)data; 987 1.69 thorpej int s = splnet(), error = 0; 988 1.57 augustss struct sl_softc *sc = ifp->if_softc; 989 1.96 christos struct ppp_stats *psp; 990 1.96 christos struct ppp_comp_stats *pcp; 991 1.1 cgd 992 1.1 cgd switch (cmd) { 993 1.1 cgd 994 1.113 dyoung case SIOCINITIFADDR: 995 1.1 cgd if (ifa->ifa_addr->sa_family == AF_INET) 996 1.1 cgd ifp->if_flags |= IFF_UP; 997 1.1 cgd else 998 1.1 cgd error = EAFNOSUPPORT; 999 1.1 cgd break; 1000 1.1 cgd 1001 1.1 cgd case SIOCSIFDSTADDR: 1002 1.129 knakahar if (ifreq_getaddr(cmd, ifr)->sa_family != AF_INET) 1003 1.1 cgd error = EAFNOSUPPORT; 1004 1.1 cgd break; 1005 1.22 cgd 1006 1.54 tron case SIOCSIFMTU: 1007 1.54 tron if ((ifr->ifr_mtu < 3) || (ifr->ifr_mtu > SLMAX)) { 1008 1.54 tron error = EINVAL; 1009 1.54 tron break; 1010 1.54 tron } 1011 1.110 dyoung /*FALLTHROUGH*/ 1012 1.54 tron case SIOCGIFMTU: 1013 1.110 dyoung if ((error = ifioctl_common(&sc->sc_if, cmd, data)) == ENETRESET) 1014 1.110 dyoung error = 0; 1015 1.54 tron break; 1016 1.54 tron 1017 1.18 hpeyerl case SIOCADDMULTI: 1018 1.18 hpeyerl case SIOCDELMULTI: 1019 1.18 hpeyerl if (ifr == 0) { 1020 1.18 hpeyerl error = EAFNOSUPPORT; /* XXX */ 1021 1.18 hpeyerl break; 1022 1.18 hpeyerl } 1023 1.107 dyoung switch (ifreq_getaddr(cmd, ifr)->sa_family) { 1024 1.18 hpeyerl 1025 1.18 hpeyerl #ifdef INET 1026 1.18 hpeyerl case AF_INET: 1027 1.18 hpeyerl break; 1028 1.18 hpeyerl #endif 1029 1.22 cgd 1030 1.18 hpeyerl default: 1031 1.18 hpeyerl error = EAFNOSUPPORT; 1032 1.18 hpeyerl break; 1033 1.18 hpeyerl } 1034 1.18 hpeyerl break; 1035 1.22 cgd 1036 1.132 thorpej case SIOCGPPPSTATS: { 1037 1.132 thorpej struct if_data ifi; 1038 1.132 thorpej 1039 1.132 thorpej if_export_if_data(&sc->sc_if, &ifi, false); 1040 1.96 christos psp = &((struct ifpppstatsreq *) data)->stats; 1041 1.96 christos (void)memset(psp, 0, sizeof(*psp)); 1042 1.132 thorpej psp->p.ppp_ibytes = ifi.ifi_ibytes; 1043 1.132 thorpej psp->p.ppp_ipackets = ifi.ifi_ipackets; 1044 1.132 thorpej psp->p.ppp_ierrors = ifi.ifi_ierrors; 1045 1.132 thorpej psp->p.ppp_obytes = ifi.ifi_obytes; 1046 1.132 thorpej psp->p.ppp_opackets = ifi.ifi_opackets; 1047 1.132 thorpej psp->p.ppp_oerrors = ifi.ifi_oerrors; 1048 1.96 christos #ifdef INET 1049 1.96 christos psp->vj.vjs_packets = sc->sc_comp.sls_packets; 1050 1.96 christos psp->vj.vjs_compressed = sc->sc_comp.sls_compressed; 1051 1.96 christos psp->vj.vjs_searches = sc->sc_comp.sls_searches; 1052 1.96 christos psp->vj.vjs_misses = sc->sc_comp.sls_misses; 1053 1.96 christos psp->vj.vjs_uncompressedin = sc->sc_comp.sls_uncompressedin; 1054 1.96 christos psp->vj.vjs_compressedin = sc->sc_comp.sls_compressedin; 1055 1.96 christos psp->vj.vjs_errorin = sc->sc_comp.sls_errorin; 1056 1.96 christos psp->vj.vjs_tossed = sc->sc_comp.sls_tossed; 1057 1.96 christos #endif 1058 1.132 thorpej } 1059 1.96 christos break; 1060 1.96 christos 1061 1.96 christos case SIOCGPPPCSTATS: 1062 1.96 christos pcp = &((struct ifpppcstatsreq *) data)->stats; 1063 1.96 christos (void)memset(pcp, 0, sizeof(*pcp)); 1064 1.96 christos break; 1065 1.96 christos 1066 1.1 cgd default: 1067 1.113 dyoung error = ifioctl_common(ifp, cmd, data); 1068 1.113 dyoung break; 1069 1.1 cgd } 1070 1.1 cgd splx(s); 1071 1.99 tsutsui return error; 1072 1.1 cgd } 1073 1.125 christos 1074 1.125 christos 1075 1.125 christos /* 1076 1.125 christos * Module infrastructure 1077 1.125 christos */ 1078 1.125 christos 1079 1.126 christos #include "if_module.h" 1080 1.125 christos 1081 1.126 christos IF_MODULE(MODULE_CLASS_DRIVER, sl, "slcompress"); 1082