2010-04-05 11:19:28 +04:00
|
|
|
/* $NetBSD: if_strip.c,v 1.95 2010/04/05 07:22:24 joerg Exp $ */
|
1996-05-19 20:34:36 +04:00
|
|
|
/* from: NetBSD: if_sl.c,v 1.38 1996/02/13 22:00:23 christos Exp $ */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright 1996 The Board of Trustees of The Leland Stanford
|
|
|
|
* Junior University. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this
|
|
|
|
* software and its documentation for any purpose and without
|
|
|
|
* fee is hereby granted, provided that the above copyright
|
|
|
|
* notice appear in all copies. Stanford University
|
|
|
|
* makes no representations about the suitability of this
|
|
|
|
* software for any purpose. It is provided "as is" without
|
|
|
|
* express or implied warranty.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* This driver was contributed by Jonathan Stone.
|
|
|
|
*
|
|
|
|
* Starmode Radio IP interface (STRIP) for Metricom wireless radio.
|
|
|
|
* This STRIP driver assumes address resolution of IP addresses to
|
|
|
|
* Metricom MAC addresses is done via local link-level routes.
|
|
|
|
* The link-level addresses are entered as an 8-digit packed BCD number.
|
|
|
|
* To add a route for a radio at IP address 10.1.2.3, with radio
|
2005-02-27 01:45:09 +03:00
|
|
|
* address '1234-5678', reachable via interface strip0, use the command
|
1996-05-19 20:34:36 +04:00
|
|
|
*
|
1997-11-18 02:35:28 +03:00
|
|
|
* route add -host 10.1.2.3 -link strip0:12:34:56:78
|
1996-05-19 20:34:36 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 1987, 1989, 1992, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2003-08-07 20:26:28 +04:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1996-05-19 20:34:36 +04:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* @(#)if_sl.c 8.6 (Berkeley) 2/1/94
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Derived from: Serial Line interface written by Rick Adams (rick@seismo.gov)
|
|
|
|
*
|
|
|
|
* Rick Adams
|
|
|
|
* Center for Seismic Studies
|
|
|
|
* 1300 N 17th Street, Suite 1450
|
|
|
|
* Arlington, Virginia 22209
|
|
|
|
* (703)276-7900
|
|
|
|
* rick@seismo.ARPA
|
|
|
|
* seismo!rick
|
|
|
|
*
|
|
|
|
* Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
|
|
|
|
* N.B.: this belongs in netinet, not net, the way it stands now.
|
|
|
|
* Should have a link-layer type designation, but wouldn't be
|
|
|
|
* backwards-compatible.
|
|
|
|
*
|
|
|
|
* Converted to 4.3BSD Beta by Chris Torek.
|
|
|
|
* Other changes made at Berkeley, based in part on code by Kirk Smith.
|
|
|
|
* W. Jolitz added slip abort.
|
|
|
|
*
|
|
|
|
* Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov).
|
|
|
|
* Added priority queuing for "interactive" traffic; hooks for TCP
|
|
|
|
* header compression; ICMP filtering (at 2400 baud, some cretin
|
|
|
|
* pinging you can use up all your bandwidth). Made low clist behavior
|
|
|
|
* more robust and slightly less likely to hang serial line.
|
|
|
|
* Sped up a bunch of things.
|
|
|
|
*/
|
|
|
|
|
2001-11-13 02:49:33 +03:00
|
|
|
#include <sys/cdefs.h>
|
2010-04-05 11:19:28 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: if_strip.c,v 1.95 2010/04/05 07:22:24 joerg Exp $");
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1998-07-05 04:51:04 +04:00
|
|
|
#include "opt_inet.h"
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/buf.h>
|
|
|
|
#include <sys/dkstat.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/file.h>
|
2000-11-02 14:00:53 +03:00
|
|
|
#include <sys/conf.h>
|
1996-05-19 20:34:36 +04:00
|
|
|
#include <sys/tty.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#if __NetBSD__
|
|
|
|
#include <sys/systm.h>
|
2000-03-23 10:01:25 +03:00
|
|
|
#include <sys/callout.h>
|
2006-05-15 01:19:33 +04:00
|
|
|
#include <sys/kauth.h>
|
1996-05-19 20:34:36 +04:00
|
|
|
#endif
|
|
|
|
#include <sys/syslog.h>
|
2007-10-08 20:18:02 +04:00
|
|
|
#include <sys/cpu.h>
|
|
|
|
#include <sys/intr.h>
|
2008-04-24 15:38:36 +04:00
|
|
|
#include <sys/socketvar.h>
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/if_dl.h>
|
|
|
|
#include <net/if_types.h>
|
|
|
|
#include <net/netisr.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
|
1998-07-07 07:22:03 +04:00
|
|
|
#ifdef INET
|
1996-05-19 20:34:36 +04:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/in_var.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <net/slcompress.h>
|
|
|
|
#include <net/if_stripvar.h>
|
|
|
|
#include <net/slip.h>
|
|
|
|
|
|
|
|
#ifdef __NetBSD__ /* XXX -- jrs */
|
|
|
|
typedef u_char ttychar_t;
|
|
|
|
#else
|
|
|
|
typedef char ttychar_t;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <net/bpf.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SLMAX is a hard limit on input packet size. To simplify the code
|
|
|
|
* and improve performance, we require that packets fit in an mbuf
|
|
|
|
* cluster, and if we get a compressed packet, there's enough extra
|
|
|
|
* room to expand the header into a max length tcp/ip header (128
|
|
|
|
* bytes). So, SLMAX can be at most
|
|
|
|
* MCLBYTES - 128
|
|
|
|
*
|
|
|
|
* SLMTU is a hard limit on output packet size. To insure good
|
|
|
|
* interactive response, SLMTU wants to be the smallest size that
|
1996-08-02 06:53:39 +04:00
|
|
|
* amortizes the header cost. Remember that even with
|
1996-05-19 20:34:36 +04:00
|
|
|
* type-of-service queuing, we have to wait for any in-progress
|
|
|
|
* packet to finish. I.e., we wait, on the average, 1/2 * mtu /
|
|
|
|
* cps, where cps is the line speed in characters per second.
|
|
|
|
* E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The
|
|
|
|
* average compressed header size is 6-8 bytes so any MTU > 90
|
|
|
|
* bytes will give us 90% of the line bandwidth. A 100ms wait is
|
|
|
|
* tolerable (500ms is not), so want an MTU around 296. (Since TCP
|
|
|
|
* will send 256 byte segments (to allow for 40 byte headers), the
|
|
|
|
* typical packet size on the wire will be around 260 bytes). In
|
|
|
|
* 4.3tahoe+ systems, we can set an MTU in a route so we do that &
|
|
|
|
* leave the interface MTU relatively high (so we don't IP fragment
|
|
|
|
* when acting as a gateway to someone using a stupid MTU).
|
|
|
|
*
|
|
|
|
* Similar considerations apply to SLIP_HIWAT: It's the amount of
|
|
|
|
* data that will be queued 'downstream' of us (i.e., in clists
|
|
|
|
* waiting to be picked up by the tty output interrupt). If we
|
|
|
|
* queue a lot of data downstream, it's immune to our t.o.s. queuing.
|
|
|
|
* E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed
|
|
|
|
* telnet/ftp will see a 1 sec wait, independent of the mtu (the
|
|
|
|
* wait is dependent on the ftp window size but that's typically
|
|
|
|
* 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize
|
|
|
|
* the cost (in idle time on the wire) of the tty driver running
|
|
|
|
* off the end of its clists & having to call back slstart for a
|
|
|
|
* new packet. For a tty interface with any buffering at all, this
|
|
|
|
* cost will be zero. Even with a totally brain dead interface (like
|
|
|
|
* the one on a typical workstation), the cost will be <= 1 character
|
|
|
|
* time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose
|
|
|
|
* at most 1% while maintaining good interactive response.
|
|
|
|
*/
|
|
|
|
#define BUFOFFSET (128+sizeof(struct ifnet **)+SLIP_HDRLEN)
|
|
|
|
#define SLMAX (MCLBYTES - BUFOFFSET)
|
|
|
|
#define SLBUFSIZE (SLMAX + BUFOFFSET)
|
1996-08-02 06:53:39 +04:00
|
|
|
#define SLMTU 1100 /* XXX -- appromaximated. 1024 may be safer. */
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-06-26 10:04:20 +04:00
|
|
|
#define STRIP_MTU_ONWIRE (SLMTU + 20 + STRIP_HDRLEN) /* (2*SLMTU+2 in sl.c */
|
1996-08-02 06:53:39 +04:00
|
|
|
|
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
#define SLIP_HIWAT roundup(50,CBSIZE)
|
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/* This is a NetBSD-1.0 or later kernel. */
|
|
|
|
#define CCOUNT(q) ((q)->c_cc)
|
|
|
|
|
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
#ifndef __NetBSD__ /* XXX - cgd */
|
|
|
|
#define CLISTRESERVE 1024 /* Can't let clists get too low */
|
|
|
|
#endif /* !__NetBSD__ */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SLIP ABORT ESCAPE MECHANISM:
|
|
|
|
* (inspired by HAYES modem escape arrangement)
|
|
|
|
* 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape }
|
|
|
|
* within window time signals a "soft" exit from slip mode by remote end
|
|
|
|
* if the IFF_DEBUG flag is on.
|
|
|
|
*/
|
|
|
|
#define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/
|
|
|
|
#define ABT_IDLE 1 /* in seconds - idle before an escape */
|
|
|
|
#define ABT_COUNT 3 /* count of escapes for abort */
|
|
|
|
#define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */
|
|
|
|
|
2004-12-05 08:43:04 +03:00
|
|
|
static int strip_clone_create(struct if_clone *, int);
|
|
|
|
static int strip_clone_destroy(struct ifnet *);
|
|
|
|
|
|
|
|
static LIST_HEAD(, strip_softc) strip_softc_list;
|
|
|
|
|
|
|
|
struct if_clone strip_cloner =
|
|
|
|
IF_CLONE_INITIALIZER("strip", strip_clone_create, strip_clone_destroy);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
#define STRIP_FRAME_END 0x0D /* carriage return */
|
|
|
|
|
2005-12-12 02:05:24 +03:00
|
|
|
static void stripintr(void *);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
2005-12-12 02:05:24 +03:00
|
|
|
static int stripinit(struct strip_softc *);
|
|
|
|
static struct mbuf *strip_btom(struct strip_softc *, int);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* STRIP header: '*' + modem address (dddd-dddd) + '*' + mactype ('SIP0')
|
|
|
|
* A Metricom packet looks like this: *<address>*<key><payload><CR>
|
|
|
|
* eg. *0000-1164*SIP0<payload><CR>
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define STRIP_ENCAP_SIZE(X) ((36) + (X)*65/64 + 2)
|
|
|
|
#define STRIP_HDRLEN 15
|
|
|
|
#define STRIP_MAC_ADDR_LEN 9
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Star mode packet header.
|
|
|
|
* (may be used for encapsulations other than STRIP.)
|
|
|
|
*/
|
|
|
|
#define STARMODE_ADDR_LEN 11
|
|
|
|
struct st_header {
|
|
|
|
u_char starmode_addr[STARMODE_ADDR_LEN];
|
|
|
|
u_char starmode_type[4];
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Forward declarations for Metricom-specific functions.
|
|
|
|
* Ideally, these would be in a library and shared across
|
|
|
|
* different STRIP implementations: *BSD, Linux, etc.
|
|
|
|
*
|
|
|
|
*/
|
2005-12-12 02:05:24 +03:00
|
|
|
static u_char* UnStuffData(u_char *src, u_char *end, u_char
|
|
|
|
*dest, u_long dest_length);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
2005-12-12 02:05:24 +03:00
|
|
|
static u_char* StuffData(u_char *src, u_long length, u_char *dest,
|
|
|
|
u_char **code_ptr_ptr);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
2005-12-12 02:05:24 +03:00
|
|
|
static void RecvErr(const char *msg, struct strip_softc *sc);
|
|
|
|
static void RecvErr_Message(struct strip_softc *strip_info,
|
|
|
|
u_char *sendername, const u_char *msg);
|
|
|
|
void strip_resetradio(struct strip_softc *sc, struct tty *tp);
|
|
|
|
void strip_proberadio(struct strip_softc *sc, struct tty *tp);
|
|
|
|
void strip_watchdog(struct ifnet *ifp);
|
|
|
|
void strip_sendbody(struct strip_softc *sc, struct mbuf *m);
|
|
|
|
int strip_newpacket(struct strip_softc *sc, u_char *ptr, u_char *end);
|
|
|
|
void strip_send(struct strip_softc *sc, struct mbuf *m0);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
2005-12-12 02:05:24 +03:00
|
|
|
void strip_timeout(void *x);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
1996-10-13 06:10:01 +04:00
|
|
|
#define DPRINTF(x) printf x
|
1996-05-19 20:34:36 +04:00
|
|
|
#else
|
|
|
|
#define DPRINTF(x)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Radio reset macros.
|
|
|
|
* The Metricom radios are not particularly well-designed for
|
|
|
|
* use in packet mode (starmode). There's no easy way to tell
|
|
|
|
* when the radio is in starmode. Worse, when the radios are reset
|
|
|
|
* or power-cycled, they come back up in Hayes AT-emulation mode,
|
|
|
|
* and there's no good way for this driver to tell.
|
|
|
|
* We deal with this by peridically tickling the radio
|
|
|
|
* with an invalid starmode command. If the radio doesn't
|
|
|
|
* respond with an error, the driver knows to reset the radio.
|
|
|
|
*/
|
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/* Radio-reset finite state machine (if_watchdog) callback rate, in seconds */
|
|
|
|
#define STRIP_WATCHDOG_INTERVAL 5
|
|
|
|
|
|
|
|
/* Period between intrusive radio probes, in seconds */
|
|
|
|
#define ST_PROBE_INTERVAL 10
|
|
|
|
|
|
|
|
/* Grace period for radio to answer probe, in seconds */
|
|
|
|
#define ST_PROBERESPONSE_INTERVAL 2
|
|
|
|
|
|
|
|
/* Be less agressive about repeated resetting. */
|
|
|
|
#define STRIP_RESET_INTERVAL 5
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/*
|
|
|
|
* We received a response from the radio that indicates it's in
|
|
|
|
* star mode. Clear any pending probe or reset timer.
|
|
|
|
* Don't probe radio again for standard polling interval.
|
|
|
|
*/
|
1996-05-19 20:34:36 +04:00
|
|
|
#define CLEAR_RESET_TIMER(sc) \
|
|
|
|
do {\
|
1996-08-02 06:53:39 +04:00
|
|
|
(sc)->sc_state = ST_ALIVE; \
|
2006-06-08 02:33:33 +04:00
|
|
|
(sc)->sc_statetimo = time_second + ST_PROBE_INTERVAL; \
|
2002-11-02 10:20:42 +03:00
|
|
|
} while (/*CONSTCOND*/ 0)
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/*
|
|
|
|
* we received a response from the radio that indicates it's crashed
|
|
|
|
* out of starmode into Hayse mode. Reset it ASAP.
|
|
|
|
*/
|
|
|
|
#define FORCE_RESET(sc) \
|
|
|
|
do {\
|
2006-06-08 02:33:33 +04:00
|
|
|
(sc)->sc_statetimo = time_second - 1; \
|
1996-08-02 06:53:39 +04:00
|
|
|
(sc)->sc_state = ST_DEAD; \
|
|
|
|
/*(sc)->sc_if.if_timer = 0;*/ \
|
2002-11-02 10:20:42 +03:00
|
|
|
} while (/*CONSTCOND*/ 0)
|
1996-08-02 06:53:39 +04:00
|
|
|
|
|
|
|
#define RADIO_PROBE_TIMEOUT(sc) \
|
2006-06-08 02:33:33 +04:00
|
|
|
((sc)-> sc_statetimo > time_second)
|
1996-08-02 06:53:39 +04:00
|
|
|
|
2005-12-12 02:05:24 +03:00
|
|
|
static int stripclose(struct tty *, int);
|
|
|
|
static int stripinput(int, struct tty *);
|
2007-03-04 08:59:00 +03:00
|
|
|
static int stripioctl(struct ifnet *, u_long, void *);
|
2005-12-12 02:05:24 +03:00
|
|
|
static int stripopen(dev_t, struct tty *);
|
|
|
|
static int stripoutput(struct ifnet *,
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
struct mbuf *, const struct sockaddr *, struct rtentry *);
|
2005-12-12 02:05:24 +03:00
|
|
|
static int stripstart(struct tty *);
|
2007-03-04 08:59:00 +03:00
|
|
|
static int striptioctl(struct tty *, u_long, void *, int, struct lwp *);
|
2005-12-12 02:05:24 +03:00
|
|
|
|
2005-11-27 08:35:52 +03:00
|
|
|
static struct linesw strip_disc = {
|
|
|
|
.l_name = "strip",
|
|
|
|
.l_open = stripopen,
|
|
|
|
.l_close = stripclose,
|
|
|
|
.l_read = ttyerrio,
|
|
|
|
.l_write = ttyerrio,
|
|
|
|
.l_ioctl = striptioctl,
|
|
|
|
.l_rint = stripinput,
|
|
|
|
.l_start = stripstart,
|
|
|
|
.l_modem = nullmodem,
|
|
|
|
.l_poll = ttyerrpoll
|
|
|
|
};
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
void
|
2004-12-05 08:43:04 +03:00
|
|
|
stripattach(void)
|
|
|
|
{
|
2005-11-27 08:35:52 +03:00
|
|
|
if (ttyldisc_attach(&strip_disc) != 0)
|
|
|
|
panic("stripattach");
|
2004-12-05 18:00:47 +03:00
|
|
|
LIST_INIT(&strip_softc_list);
|
|
|
|
if_clone_attach(&strip_cloner);
|
2004-12-05 08:43:04 +03:00
|
|
|
}
|
|
|
|
|
2004-12-05 18:00:47 +03:00
|
|
|
static int
|
2004-12-05 08:43:04 +03:00
|
|
|
strip_clone_create(struct if_clone *ifc, int unit)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct strip_softc *sc;
|
2004-12-05 08:43:04 +03:00
|
|
|
|
2008-12-17 23:51:31 +03:00
|
|
|
sc = malloc(sizeof(*sc), M_DEVBUF, M_WAIT|M_ZERO);
|
2004-12-05 08:43:04 +03:00
|
|
|
sc->sc_unit = unit;
|
2008-06-15 20:37:21 +04:00
|
|
|
if_initname(&sc->sc_if, ifc->ifc_name, unit);
|
2007-07-10 00:51:58 +04:00
|
|
|
callout_init(&sc->sc_timo_ch, 0);
|
2004-12-05 08:43:04 +03:00
|
|
|
sc->sc_if.if_softc = sc;
|
|
|
|
sc->sc_if.if_mtu = SLMTU;
|
|
|
|
sc->sc_if.if_flags = 0;
|
|
|
|
sc->sc_if.if_type = IFT_OTHER;
|
1996-05-19 20:34:36 +04:00
|
|
|
#if 0
|
2004-12-05 08:43:04 +03:00
|
|
|
sc->sc_if.if_flags |= SC_AUTOCOMP /* | IFF_POINTOPOINT | IFF_MULTICAST*/;
|
1996-05-19 20:34:36 +04:00
|
|
|
#endif
|
2004-12-05 08:43:04 +03:00
|
|
|
sc->sc_if.if_type = IFT_SLIP;
|
|
|
|
sc->sc_if.if_ioctl = stripioctl;
|
|
|
|
sc->sc_if.if_output = stripoutput;
|
|
|
|
sc->sc_if.if_dlt = DLT_SLIP;
|
|
|
|
sc->sc_fastq.ifq_maxlen = 32;
|
|
|
|
IFQ_SET_READY(&sc->sc_if.if_snd);
|
|
|
|
|
|
|
|
sc->sc_if.if_watchdog = strip_watchdog;
|
|
|
|
if_attach(&sc->sc_if);
|
|
|
|
if_alloc_sadl(&sc->sc_if);
|
2010-04-05 11:19:28 +04:00
|
|
|
bpf_attach(&sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
|
2004-12-05 08:43:04 +03:00
|
|
|
LIST_INSERT_HEAD(&strip_softc_list, sc, sc_iflist);
|
2004-12-05 09:53:33 +03:00
|
|
|
return 0;
|
2004-12-05 08:43:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
strip_clone_destroy(struct ifnet *ifp)
|
|
|
|
{
|
2004-12-05 18:00:47 +03:00
|
|
|
struct strip_softc *sc = (struct strip_softc *)ifp->if_softc;
|
2004-12-05 08:43:04 +03:00
|
|
|
|
2004-12-05 18:00:47 +03:00
|
|
|
if (sc->sc_ttyp != NULL)
|
|
|
|
return EBUSY; /* Not removing it */
|
2004-12-05 08:43:04 +03:00
|
|
|
|
2004-12-05 18:00:47 +03:00
|
|
|
LIST_REMOVE(sc, sc_iflist);
|
2004-12-05 08:43:04 +03:00
|
|
|
|
2010-04-05 11:19:28 +04:00
|
|
|
bpf_detach(ifp);
|
2004-12-05 18:00:47 +03:00
|
|
|
if_detach(ifp);
|
2004-12-05 08:43:04 +03:00
|
|
|
|
2008-12-17 23:51:31 +03:00
|
|
|
free(sc, M_DEVBUF);
|
2004-12-05 18:00:47 +03:00
|
|
|
return 0;
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2005-12-12 02:05:24 +03:00
|
|
|
stripinit(struct strip_softc *sc)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
u_char *p;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
2001-01-12 01:23:11 +03:00
|
|
|
if (sc->sc_mbuf == NULL) {
|
2003-02-26 09:31:08 +03:00
|
|
|
sc->sc_mbuf = m_get(M_WAIT, MT_DATA);
|
|
|
|
m_clget(sc->sc_mbuf, M_WAIT);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
2001-01-12 01:23:11 +03:00
|
|
|
sc->sc_ep = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
|
|
|
|
sc->sc_mbuf->m_ext.ext_size;
|
|
|
|
sc->sc_mp = sc->sc_pktstart = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
|
|
|
|
BUFOFFSET;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/* Get contiguous buffer in which to de-bytestuff/rll-decode input */
|
1997-03-27 23:36:14 +03:00
|
|
|
if (sc->sc_rxbuf == NULL) {
|
|
|
|
p = (u_char *)malloc(MCLBYTES, M_DEVBUF, M_WAITOK);
|
1996-05-19 20:34:36 +04:00
|
|
|
if (p)
|
1997-03-27 23:36:14 +03:00
|
|
|
sc->sc_rxbuf = p + SLBUFSIZE - SLMAX;
|
1996-05-19 20:34:36 +04:00
|
|
|
else {
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("%s: can't allocate input buffer\n",
|
1996-10-11 02:59:41 +04:00
|
|
|
sc->sc_if.if_xname);
|
1996-05-19 20:34:36 +04:00
|
|
|
sc->sc_if.if_flags &= ~IFF_UP;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/* Get contiguous buffer in which to bytestuff/rll-encode output */
|
1997-03-27 23:36:14 +03:00
|
|
|
if (sc->sc_txbuf == NULL) {
|
|
|
|
p = (u_char *)malloc(MCLBYTES, M_DEVBUF, M_WAITOK);
|
1996-05-19 20:34:36 +04:00
|
|
|
if (p)
|
|
|
|
sc->sc_txbuf = (u_char *)p + SLBUFSIZE - SLMAX;
|
|
|
|
else {
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("%s: can't allocate buffer\n",
|
1996-10-11 02:59:41 +04:00
|
|
|
sc->sc_if.if_xname);
|
2005-02-27 01:45:09 +03:00
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
sc->sc_if.if_flags &= ~IFF_UP;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
1997-05-24 18:39:44 +04:00
|
|
|
sl_compress_init(&sc->sc_comp);
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/* Initialize radio probe/reset state machine */
|
|
|
|
sc->sc_state = ST_DEAD; /* assumet the worst. */
|
2006-06-08 02:33:33 +04:00
|
|
|
sc->sc_statetimo = time_second; /* do reset immediately */
|
1996-08-02 06:53:39 +04:00
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Line specific open routine.
|
|
|
|
* Attach the given tty to the first available sl unit.
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
stripopen(dev_t dev, struct tty *tp)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2006-07-24 02:06:03 +04:00
|
|
|
struct lwp *l = curlwp; /* XXX */
|
2000-03-30 13:45:33 +04:00
|
|
|
struct strip_softc *sc;
|
1996-05-19 20:34:36 +04:00
|
|
|
int error;
|
|
|
|
|
2009-05-07 22:01:56 +04:00
|
|
|
error = kauth_authorize_network(l->l_cred,
|
|
|
|
KAUTH_NETWORK_INTERFACE_STRIP,
|
|
|
|
KAUTH_REQ_NETWORK_INTERFACE_STRIP_ADD, NULL, NULL, NULL);
|
|
|
|
if (error)
|
1996-05-19 20:34:36 +04:00
|
|
|
return (error);
|
|
|
|
|
2005-11-27 08:35:52 +03:00
|
|
|
if (tp->t_linesw == &strip_disc)
|
1996-05-19 20:34:36 +04:00
|
|
|
return (0);
|
|
|
|
|
2004-12-05 08:43:04 +03:00
|
|
|
LIST_FOREACH(sc, &strip_softc_list, sc_iflist) {
|
1996-05-19 20:34:36 +04:00
|
|
|
if (sc->sc_ttyp == NULL) {
|
2007-10-08 20:18:02 +04:00
|
|
|
sc->sc_si = softint_establish(SOFTINT_NET,
|
2001-01-15 19:33:30 +03:00
|
|
|
stripintr, sc);
|
|
|
|
if (stripinit(sc) == 0) {
|
2007-10-08 20:18:02 +04:00
|
|
|
softint_disestablish(sc->sc_si);
|
1996-05-19 20:34:36 +04:00
|
|
|
return (ENOBUFS);
|
2001-01-15 19:33:30 +03:00
|
|
|
}
|
2007-11-10 21:29:36 +03:00
|
|
|
mutex_spin_enter(&tty_lock);
|
2007-03-04 08:59:00 +03:00
|
|
|
tp->t_sc = (void *)sc;
|
1996-05-19 20:34:36 +04:00
|
|
|
sc->sc_ttyp = tp;
|
|
|
|
sc->sc_if.if_baudrate = tp->t_ospeed;
|
|
|
|
ttyflush(tp, FREAD | FWRITE);
|
|
|
|
/*
|
1996-06-26 10:04:20 +04:00
|
|
|
* Make sure tty output queue is large enough
|
1996-05-19 20:34:36 +04:00
|
|
|
* to hold a full-sized packet (including frame
|
1996-06-26 10:04:20 +04:00
|
|
|
* end, and a possible extra frame end).
|
|
|
|
* A full-sized of 65/64) *SLMTU bytes (because
|
|
|
|
* of escapes and clever RLL bytestuffing),
|
|
|
|
* plus frame header, and add two on for frame ends.
|
1996-05-19 20:34:36 +04:00
|
|
|
*/
|
1996-06-26 10:04:20 +04:00
|
|
|
if (tp->t_outq.c_cn < STRIP_MTU_ONWIRE) {
|
1996-05-19 20:34:36 +04:00
|
|
|
sc->sc_oldbufsize = tp->t_outq.c_cn;
|
|
|
|
sc->sc_oldbufquot = tp->t_outq.c_cq != 0;
|
|
|
|
|
2007-11-10 21:29:36 +03:00
|
|
|
mutex_spin_exit(&tty_lock);
|
1996-05-19 20:34:36 +04:00
|
|
|
clfree(&tp->t_outq);
|
|
|
|
error = clalloc(&tp->t_outq, 3*SLMTU, 0);
|
|
|
|
if (error) {
|
2007-10-08 20:18:02 +04:00
|
|
|
softint_disestablish(sc->sc_si);
|
2002-03-17 22:40:26 +03:00
|
|
|
/*
|
|
|
|
* clalloc() might return -1 which
|
|
|
|
* is no good, so we need to return
|
|
|
|
* something else.
|
|
|
|
*/
|
2002-09-11 09:36:26 +04:00
|
|
|
return (ENOMEM);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
2007-11-10 21:29:36 +03:00
|
|
|
mutex_spin_enter(&tty_lock);
|
|
|
|
} else
|
1996-05-19 20:34:36 +04:00
|
|
|
sc->sc_oldbufsize = sc->sc_oldbufquot = 0;
|
1996-06-26 10:04:20 +04:00
|
|
|
strip_resetradio(sc, tp);
|
2007-11-10 21:29:36 +03:00
|
|
|
mutex_spin_exit(&tty_lock);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1997-11-20 11:03:06 +03:00
|
|
|
/*
|
|
|
|
* Start the watchdog timer to get the radio
|
|
|
|
* "probe-for-death"/reset machine going.
|
|
|
|
*/
|
|
|
|
sc->sc_if.if_timer = STRIP_WATCHDOG_INTERVAL;
|
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
return (0);
|
|
|
|
}
|
1997-11-20 11:03:06 +03:00
|
|
|
}
|
1996-05-19 20:34:36 +04:00
|
|
|
return (ENXIO);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Line specific close routine.
|
1996-08-02 06:53:39 +04:00
|
|
|
* Detach the tty from the strip unit.
|
1996-05-19 20:34:36 +04:00
|
|
|
*/
|
2005-12-12 02:05:24 +03:00
|
|
|
static int
|
2006-11-16 04:32:37 +03:00
|
|
|
stripclose(struct tty *tp, int flag)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct strip_softc *sc;
|
1996-05-19 20:34:36 +04:00
|
|
|
int s;
|
|
|
|
|
|
|
|
ttywflush(tp);
|
2001-01-12 22:26:48 +03:00
|
|
|
sc = tp->t_sc;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
if (sc != NULL) {
|
2007-10-08 20:18:02 +04:00
|
|
|
softint_disestablish(sc->sc_si);
|
2001-01-12 22:26:48 +03:00
|
|
|
s = splnet();
|
1997-11-20 11:03:06 +03:00
|
|
|
/*
|
|
|
|
* Cancel watchdog timer, which stops the "probe-for-death"/
|
|
|
|
* reset machine.
|
|
|
|
*/
|
|
|
|
sc->sc_if.if_timer = 0;
|
1996-05-19 20:34:36 +04:00
|
|
|
if_down(&sc->sc_if);
|
2001-01-12 22:26:48 +03:00
|
|
|
IF_PURGE(&sc->sc_fastq);
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
s = spltty();
|
2005-11-27 08:35:52 +03:00
|
|
|
ttyldisc_release(tp->t_linesw);
|
|
|
|
tp->t_linesw = ttyldisc_default();
|
2001-01-12 22:26:48 +03:00
|
|
|
tp->t_state = 0;
|
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
sc->sc_ttyp = NULL;
|
|
|
|
tp->t_sc = NULL;
|
2001-01-12 22:26:48 +03:00
|
|
|
|
2001-01-12 01:23:11 +03:00
|
|
|
m_freem(sc->sc_mbuf);
|
|
|
|
sc->sc_mbuf = NULL;
|
|
|
|
sc->sc_ep = sc->sc_mp = sc->sc_pktstart = NULL;
|
2001-01-12 01:31:49 +03:00
|
|
|
IF_PURGE(&sc->sc_inq);
|
2001-01-12 01:23:11 +03:00
|
|
|
|
1997-03-27 23:36:14 +03:00
|
|
|
/* XXX */
|
2007-03-04 08:59:00 +03:00
|
|
|
free((void *)(sc->sc_rxbuf - SLBUFSIZE + SLMAX), M_DEVBUF);
|
2001-01-12 01:23:11 +03:00
|
|
|
sc->sc_rxbuf = NULL;
|
|
|
|
|
1997-03-27 23:36:14 +03:00
|
|
|
/* XXX */
|
2007-03-04 08:59:00 +03:00
|
|
|
free((void *)(sc->sc_txbuf - SLBUFSIZE + SLMAX), M_DEVBUF);
|
2001-01-12 01:23:11 +03:00
|
|
|
sc->sc_txbuf = NULL;
|
1996-08-02 06:53:39 +04:00
|
|
|
|
|
|
|
if (sc->sc_flags & SC_TIMEOUT) {
|
2000-03-23 10:01:25 +03:00
|
|
|
callout_stop(&sc->sc_timo_ch);
|
1996-08-02 06:53:39 +04:00
|
|
|
sc->sc_flags &= ~SC_TIMEOUT;
|
|
|
|
}
|
2001-01-12 22:26:48 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If necessary, install a new outq buffer of the
|
|
|
|
* appropriate size.
|
|
|
|
*/
|
|
|
|
if (sc->sc_oldbufsize != 0) {
|
|
|
|
clfree(&tp->t_outq);
|
|
|
|
clalloc(&tp->t_outq, sc->sc_oldbufsize,
|
|
|
|
sc->sc_oldbufquot);
|
|
|
|
}
|
|
|
|
splx(s);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
2005-11-27 08:35:52 +03:00
|
|
|
|
|
|
|
return (0);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Line specific (tty) ioctl routine.
|
|
|
|
* Provide a way to get the sl unit number.
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
2007-03-04 08:59:00 +03:00
|
|
|
striptioctl(struct tty *tp, u_long cmd, void *data, int flag,
|
2006-11-16 04:32:37 +03:00
|
|
|
struct lwp *l)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
1997-11-18 02:35:28 +03:00
|
|
|
struct strip_softc *sc = (struct strip_softc *)tp->t_sc;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SLIOCGUNIT:
|
1996-05-20 02:09:36 +04:00
|
|
|
*(int *)data = sc->sc_unit;
|
1996-05-19 20:34:36 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2002-03-17 22:40:26 +03:00
|
|
|
return (EPASSTHROUGH);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1996-06-26 10:04:20 +04:00
|
|
|
* Take an mbuf chain containing a STRIP packet (no link-level header),
|
|
|
|
* byte-stuff (escape) it, and enqueue it on the tty send queue.
|
1996-05-19 20:34:36 +04:00
|
|
|
*/
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
strip_sendbody(struct strip_softc *sc, struct mbuf *m)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct tty *tp = sc->sc_ttyp;
|
|
|
|
u_char *dp = sc->sc_txbuf;
|
1996-05-19 20:34:36 +04:00
|
|
|
struct mbuf *m2;
|
2000-03-30 13:45:33 +04:00
|
|
|
int len;
|
2001-01-12 22:03:24 +03:00
|
|
|
u_char *rllstate_ptr = NULL;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
while (m) {
|
2001-01-12 22:03:24 +03:00
|
|
|
if (m->m_len != 0) {
|
|
|
|
/*
|
|
|
|
* Byte-stuff/run-length encode this mbuf's data
|
|
|
|
* into the output buffer.
|
|
|
|
* XXX Note that chained calls to stuffdata()
|
|
|
|
* require that the stuffed data be left in the
|
|
|
|
* output buffer until the entire packet is encoded.
|
|
|
|
*/
|
|
|
|
dp = StuffData(mtod(m, u_char *), m->m_len, dp,
|
|
|
|
&rllstate_ptr);
|
|
|
|
}
|
1996-05-19 20:34:36 +04:00
|
|
|
MFREE(m, m2);
|
|
|
|
m = m2;
|
|
|
|
}
|
1996-06-26 10:04:20 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Put the entire stuffed packet into the tty output queue.
|
|
|
|
*/
|
|
|
|
len = dp - sc->sc_txbuf;
|
2001-01-12 22:03:24 +03:00
|
|
|
if (b_to_q((ttychar_t *)sc->sc_txbuf, len, &tp->t_outq)) {
|
|
|
|
if (sc->sc_if.if_flags & IFF_DEBUG)
|
|
|
|
addlog("%s: tty output overflow\n",
|
|
|
|
sc->sc_if.if_xname);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sc->sc_if.if_obytes += len;
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
|
2005-02-27 01:45:09 +03:00
|
|
|
/*
|
2001-01-12 22:03:24 +03:00
|
|
|
* Send a STRIP packet. Must be called at spltty().
|
1996-05-19 20:34:36 +04:00
|
|
|
*/
|
2001-01-12 22:03:24 +03:00
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
strip_send(struct strip_softc *sc, struct mbuf *m0)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct tty *tp = sc->sc_ttyp;
|
1996-05-19 20:34:36 +04:00
|
|
|
struct st_header *hdr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send starmode header (unstuffed).
|
|
|
|
*/
|
|
|
|
hdr = mtod(m0, struct st_header *);
|
|
|
|
if (b_to_q((ttychar_t *)hdr, STRIP_HDRLEN, &tp->t_outq)) {
|
1996-08-02 06:53:39 +04:00
|
|
|
if (sc->sc_if.if_flags & IFF_DEBUG)
|
|
|
|
addlog("%s: outq overflow writing header\n",
|
|
|
|
sc->sc_if.if_xname);
|
1996-05-19 20:34:36 +04:00
|
|
|
m_freem(m0);
|
2001-01-12 22:03:24 +03:00
|
|
|
return;
|
1996-06-26 10:04:20 +04:00
|
|
|
}
|
|
|
|
|
2001-01-12 22:03:24 +03:00
|
|
|
m_adj(m0, sizeof(struct st_header));
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-06-26 10:04:20 +04:00
|
|
|
/* Byte-stuff and run-length encode the remainder of the packet. */
|
1996-08-02 06:53:39 +04:00
|
|
|
strip_sendbody(sc, m0);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
if (putc(STRIP_FRAME_END, &tp->t_outq)) {
|
|
|
|
/*
|
|
|
|
* Not enough room. Remove a char to make room
|
|
|
|
* and end the packet normally.
|
|
|
|
* If you get many collisions (more than one or two
|
|
|
|
* a day) you probably do not have enough clists
|
|
|
|
* and you should increase "nclist" in param.c.
|
|
|
|
*/
|
|
|
|
(void) unputc(&tp->t_outq);
|
|
|
|
(void) putc(STRIP_FRAME_END, &tp->t_outq);
|
|
|
|
sc->sc_if.if_collisions++;
|
|
|
|
} else {
|
|
|
|
++sc->sc_if.if_obytes;
|
|
|
|
sc->sc_if.if_opackets++;
|
|
|
|
}
|
1996-08-02 06:53:39 +04:00
|
|
|
|
|
|
|
/*
|
2001-01-12 22:03:24 +03:00
|
|
|
* If a radio probe is due now, append it to this packet rather
|
|
|
|
* than waiting until the watchdog routine next runs.
|
1996-08-02 06:53:39 +04:00
|
|
|
*/
|
2006-06-08 02:33:33 +04:00
|
|
|
if (time_second >= sc->sc_statetimo && sc->sc_state == ST_ALIVE)
|
1996-08-02 06:53:39 +04:00
|
|
|
strip_proberadio(sc, tp);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Queue a packet. Start transmission if not active.
|
2001-01-12 22:03:24 +03:00
|
|
|
* Compression happens in stripintr(); if we do it here, IP TOS
|
1996-05-19 20:34:36 +04:00
|
|
|
* will cause us to not compress "background" packets, because
|
2001-01-12 22:03:24 +03:00
|
|
|
* ordering gets trashed. It can be done for all packets in stripintr().
|
1996-05-19 20:34:36 +04:00
|
|
|
*/
|
|
|
|
int
|
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
|
|
|
stripoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
2005-12-12 02:05:24 +03:00
|
|
|
struct rtentry *rt)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct strip_softc *sc = ifp->if_softc;
|
|
|
|
struct ip *ip;
|
|
|
|
struct st_header *shp;
|
|
|
|
const u_char *dldst; /* link-level next-hop */
|
2000-12-18 23:47:10 +03:00
|
|
|
struct ifqueue *ifq;
|
|
|
|
int s, error;
|
1996-05-19 20:34:36 +04:00
|
|
|
u_char dl_addrbuf[STARMODE_ADDR_LEN+1];
|
2001-01-09 02:43:34 +03:00
|
|
|
ALTQ_DECL(struct altq_pktattr pktattr;)
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Verify tty line is up and alive.
|
|
|
|
*/
|
|
|
|
if (sc->sc_ttyp == NULL) {
|
|
|
|
m_freem(m);
|
|
|
|
return (ENETDOWN); /* sort of */
|
|
|
|
}
|
|
|
|
if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 &&
|
|
|
|
(sc->sc_ttyp->t_cflag & CLOCAL) == 0) {
|
|
|
|
m_freem(m);
|
|
|
|
return (EHOSTUNREACH);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2000-10-02 07:51:18 +04:00
|
|
|
if (rt) {
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("stripout, rt: dst af%d gw af%d",
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
rt_getkey(rt)->sa_family, rt->rt_gateway->sa_family);
|
|
|
|
if (rt_getkey(rt)->sa_family == AF_INET)
|
1996-10-13 06:10:01 +04:00
|
|
|
printf(" dst %x",
|
Take steps to hide the radix_node implementation of the forwarding table
from the forwarding table's users:
Introduce rt_walktree() for walking the routing table and
applying a function to each rtentry. Replace most
rn_walktree() calls with it.
Use rt_getkey()/rt_setkey() to get/set a route's destination.
Keep a pointer to the sockaddr key in the rtentry, so that
rtentry users do not have to grovel in the radix_node for
the key.
Add a RTM_GET method to rtrequest. Use that instead of
radix_node lookups in, e.g., carp(4).
Add sys/net/link_proto.c, which supplies sockaddr routines for
link-layer socket addresses (sockaddr_dl).
Cosmetic:
Constify. KNF. Stop open-coding LIST_FOREACH, TAILQ_FOREACH,
et cetera. Use NULL instead of 0 for null pointers. Use
__arraycount(). Reduce gratuitous parenthesization.
Stop using variadic arguments for rip6_output(), it is
unnecessary.
Remove the unnecessary rtentry member rt_genmask and the
code to maintain it, since nothing actually used it.
Make rt_maskedcopy() easier to read by using meaningful variable
names.
Extract a subroutine intern_netmask() for looking up a netmask in
the masks table.
Start converting backslash-ridden IPv6 macros in
sys/netinet6/in6_var.h into inline subroutines that one
can read without special eyeglasses.
One functional change: when the kernel serves an RTM_GET, RTM_LOCK,
or RTM_CHANGE request, it applies the netmask (if supplied) to a
destination before searching for it in the forwarding table.
I have changed sys/netinet/ip_carp.c, carp_setroute(), to remove
the unlawful radix_node knowledge.
Apart from the changes to carp(4), netiso, ATM, and strip(4), I
have run the changes on three nodes in my wireless routing testbed,
which involves IPv4 + IPv6 dynamic routing acrobatics, and it's
working beautifully so far.
2007-07-20 00:48:52 +04:00
|
|
|
satocsin(rt_getkey(rt))->sin_addr.s_addr);
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("\n");
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
switch (dst->sa_family) {
|
2000-10-02 07:51:18 +04:00
|
|
|
case AF_INET:
|
1996-05-19 20:34:36 +04:00
|
|
|
if (rt != NULL && rt->rt_gwroute != NULL)
|
|
|
|
rt = rt->rt_gwroute;
|
|
|
|
|
|
|
|
/* assume rt is never NULL */
|
|
|
|
if (rt == NULL || rt->rt_gateway->sa_family != AF_LINK
|
2007-08-07 08:41:15 +04:00
|
|
|
|| satocsdl(rt->rt_gateway)->sdl_alen != ifp->if_addrlen) {
|
1996-05-19 20:34:36 +04:00
|
|
|
DPRINTF(("strip: could not arp starmode addr %x\n",
|
2007-02-18 10:17:48 +03:00
|
|
|
satocsin(dst)->sin_addr.s_addr));
|
1996-05-19 20:34:36 +04:00
|
|
|
m_freem(m);
|
2002-09-11 09:36:26 +04:00
|
|
|
return (EHOSTUNREACH);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
2007-08-07 08:41:15 +04:00
|
|
|
dldst = CLLADDR(satocsdl(rt->rt_gateway));
|
1996-05-19 20:34:36 +04:00
|
|
|
break;
|
|
|
|
|
2000-10-02 07:51:18 +04:00
|
|
|
case AF_LINK:
|
2007-08-07 08:41:15 +04:00
|
|
|
dldst = CLLADDR(satocsdl(dst));
|
1996-05-19 20:34:36 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* `Cannot happen' (see stripioctl). Someday we will extend
|
|
|
|
* the line protocol to support other address families.
|
|
|
|
*/
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("%s: af %d not supported\n", sc->sc_if.if_xname,
|
1996-10-11 02:59:41 +04:00
|
|
|
dst->sa_family);
|
1996-05-19 20:34:36 +04:00
|
|
|
m_freem(m);
|
|
|
|
sc->sc_if.if_noproto++;
|
|
|
|
return (EAFNOSUPPORT);
|
|
|
|
}
|
2005-02-27 01:45:09 +03:00
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
ip = mtod(m, struct ip *);
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
1996-05-19 20:34:36 +04:00
|
|
|
if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
|
|
|
|
m_freem(m);
|
|
|
|
return (ENETRESET); /* XXX ? */
|
|
|
|
}
|
2000-12-18 23:47:10 +03:00
|
|
|
if ((ip->ip_tos & IPTOS_LOWDELAY) != 0
|
|
|
|
#ifdef ALTQ
|
|
|
|
&& ALTQ_IS_ENABLED(&ifp->if_snd) == 0
|
|
|
|
#endif
|
|
|
|
)
|
1996-05-19 20:34:36 +04:00
|
|
|
ifq = &sc->sc_fastq;
|
2000-12-18 23:47:10 +03:00
|
|
|
else
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
2000-12-18 23:47:10 +03:00
|
|
|
ifq = NULL;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add local net header. If no space in first mbuf,
|
|
|
|
* add another.
|
|
|
|
*/
|
|
|
|
M_PREPEND(m, sizeof(struct st_header), M_DONTWAIT);
|
|
|
|
if (m == 0) {
|
|
|
|
DPRINTF(("strip: could not prepend starmode header\n"));
|
2002-09-11 09:36:26 +04:00
|
|
|
return (ENOBUFS);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unpack BCD route entry into an ASCII starmode address.
|
|
|
|
*/
|
|
|
|
dl_addrbuf[0] = '*';
|
|
|
|
|
|
|
|
dl_addrbuf[1] = ((dldst[0] >> 4) & 0x0f) + '0';
|
|
|
|
dl_addrbuf[2] = ((dldst[0] ) & 0x0f) + '0';
|
|
|
|
|
|
|
|
dl_addrbuf[3] = ((dldst[1] >> 4) & 0x0f) + '0';
|
|
|
|
dl_addrbuf[4] = ((dldst[1] ) & 0x0f) + '0';
|
|
|
|
|
|
|
|
dl_addrbuf[5] = '-';
|
|
|
|
|
|
|
|
dl_addrbuf[6] = ((dldst[2] >> 4) & 0x0f) + '0';
|
|
|
|
dl_addrbuf[7] = ((dldst[2] ) & 0x0f) + '0';
|
|
|
|
|
|
|
|
dl_addrbuf[8] = ((dldst[3] >> 4) & 0x0f) + '0';
|
|
|
|
dl_addrbuf[9] = ((dldst[3] ) & 0x0f) + '0';
|
|
|
|
|
|
|
|
dl_addrbuf[10] = '*';
|
|
|
|
dl_addrbuf[11] = 0;
|
|
|
|
dldst = dl_addrbuf;
|
|
|
|
|
|
|
|
shp = mtod(m, struct st_header *);
|
2005-05-30 01:22:52 +04:00
|
|
|
memcpy(&shp->starmode_type, "SIP0", sizeof(shp->starmode_type));
|
1996-05-19 20:34:36 +04:00
|
|
|
|
2005-05-30 01:22:52 +04:00
|
|
|
memcpy(shp->starmode_addr, dldst, sizeof(shp->starmode_addr));
|
1996-05-19 20:34:36 +04:00
|
|
|
|
2001-01-12 22:26:48 +03:00
|
|
|
s = spltty();
|
1996-05-19 20:34:36 +04:00
|
|
|
if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) {
|
2006-06-08 02:33:33 +04:00
|
|
|
struct bintime bt;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
/* if output's been stalled for too long, and restart */
|
2006-06-08 02:33:33 +04:00
|
|
|
getbinuptime(&bt);
|
|
|
|
bintime_sub(&bt, &sc->sc_lastpacket);
|
|
|
|
if (bt.sec > 0) {
|
1996-08-02 06:53:39 +04:00
|
|
|
DPRINTF(("stripoutput: stalled, resetting\n"));
|
1996-05-19 20:34:36 +04:00
|
|
|
sc->sc_otimeout++;
|
|
|
|
stripstart(sc->sc_ttyp);
|
|
|
|
}
|
|
|
|
}
|
2001-01-12 22:26:48 +03:00
|
|
|
splx(s);
|
|
|
|
|
|
|
|
s = splnet();
|
2005-03-31 19:48:13 +04:00
|
|
|
if ((error = ifq_enqueue2(ifp, ifq, m ALTQ_COMMA
|
|
|
|
ALTQ_DECL(&pktattr))) != 0) {
|
1996-05-19 20:34:36 +04:00
|
|
|
splx(s);
|
2005-03-31 19:48:13 +04:00
|
|
|
return error;
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
2006-06-08 02:33:33 +04:00
|
|
|
getbinuptime(&sc->sc_lastpacket);
|
2001-01-12 22:26:48 +03:00
|
|
|
splx(s);
|
1996-08-02 06:53:39 +04:00
|
|
|
|
2001-01-12 22:26:48 +03:00
|
|
|
s = spltty();
|
2000-12-18 23:47:10 +03:00
|
|
|
stripstart(sc->sc_ttyp);
|
1996-05-19 20:34:36 +04:00
|
|
|
splx(s);
|
2001-01-12 22:26:48 +03:00
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1996-06-26 10:04:20 +04:00
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
/*
|
|
|
|
* Start output on interface. Get another datagram
|
|
|
|
* to send from the interface queue and map it to
|
|
|
|
* the interface before starting output.
|
1996-06-26 10:04:20 +04:00
|
|
|
*
|
1996-05-19 20:34:36 +04:00
|
|
|
*/
|
2005-11-27 08:35:52 +03:00
|
|
|
int
|
2005-12-12 02:05:24 +03:00
|
|
|
stripstart(struct tty *tp)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2001-01-15 19:33:30 +03:00
|
|
|
struct strip_softc *sc = tp->t_sc;
|
1996-08-02 06:53:39 +04:00
|
|
|
|
|
|
|
/*
|
2001-01-12 22:03:24 +03:00
|
|
|
* If there is more in the output queue, just send it now.
|
|
|
|
* We are being called in lieu of ttstart and must do what
|
|
|
|
* it would.
|
1996-08-02 06:53:39 +04:00
|
|
|
*/
|
2001-01-12 22:03:24 +03:00
|
|
|
if (tp->t_outq.c_cc != 0) {
|
1996-08-02 06:53:39 +04:00
|
|
|
(*tp->t_oproc)(tp);
|
2001-01-12 22:03:24 +03:00
|
|
|
if (tp->t_outq.c_cc > SLIP_HIWAT)
|
2005-11-27 08:35:52 +03:00
|
|
|
return (0);
|
1996-08-02 06:53:39 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2001-01-12 22:03:24 +03:00
|
|
|
* This happens briefly when the line shuts down.
|
1996-08-02 06:53:39 +04:00
|
|
|
*/
|
2001-01-15 19:33:30 +03:00
|
|
|
if (sc == NULL)
|
2005-11-27 08:35:52 +03:00
|
|
|
return (0);
|
2007-10-08 20:18:02 +04:00
|
|
|
softint_schedule(sc->sc_si);
|
2005-11-27 08:35:52 +03:00
|
|
|
return (0);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy data buffer to mbuf chain; add ifnet pointer.
|
|
|
|
*/
|
|
|
|
static struct mbuf *
|
2005-12-12 02:05:24 +03:00
|
|
|
strip_btom(struct strip_softc *sc, int len)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct mbuf *m;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
2001-01-12 01:23:11 +03:00
|
|
|
/*
|
2001-01-12 01:56:51 +03:00
|
|
|
* Allocate a new input buffer and swap.
|
1996-05-19 20:34:36 +04:00
|
|
|
*/
|
2001-01-12 01:56:51 +03:00
|
|
|
m = sc->sc_mbuf;
|
|
|
|
MGETHDR(sc->sc_mbuf, M_DONTWAIT, MT_DATA);
|
|
|
|
if (sc->sc_mbuf == NULL) {
|
|
|
|
sc->sc_mbuf = m;
|
|
|
|
return (NULL);
|
2001-01-12 01:23:11 +03:00
|
|
|
}
|
2001-01-12 01:56:51 +03:00
|
|
|
MCLGET(sc->sc_mbuf, M_DONTWAIT);
|
|
|
|
if ((sc->sc_mbuf->m_flags & M_EXT) == 0) {
|
|
|
|
m_freem(sc->sc_mbuf);
|
|
|
|
sc->sc_mbuf = m;
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
sc->sc_ep = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
|
|
|
|
sc->sc_mbuf->m_ext.ext_size;
|
|
|
|
|
|
|
|
m->m_data = sc->sc_pktstart;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
2001-01-12 01:23:11 +03:00
|
|
|
m->m_pkthdr.len = m->m_len = len;
|
1996-05-19 20:34:36 +04:00
|
|
|
m->m_pkthdr.rcvif = &sc->sc_if;
|
|
|
|
return (m);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* tty interface receiver interrupt.
|
|
|
|
*
|
|
|
|
* Called with a single char from the tty receiver interrupt; put
|
|
|
|
* the char into the buffer containing a partial packet. If the
|
|
|
|
* char is a packet delimiter, decapsulate the packet, wrap it in
|
|
|
|
* an mbuf, and put it on the protocol input queue.
|
|
|
|
*/
|
2005-11-27 08:35:52 +03:00
|
|
|
int
|
2005-12-12 02:05:24 +03:00
|
|
|
stripinput(int c, struct tty *tp)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct strip_softc *sc;
|
|
|
|
struct mbuf *m;
|
|
|
|
int len;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
tk_nin++;
|
1997-11-18 02:35:28 +03:00
|
|
|
sc = (struct strip_softc *)tp->t_sc;
|
1996-05-19 20:34:36 +04:00
|
|
|
if (sc == NULL)
|
2005-11-27 08:35:52 +03:00
|
|
|
return (0);
|
1996-05-19 20:34:36 +04:00
|
|
|
if (c & TTY_ERRORMASK || ((tp->t_state & TS_CARR_ON) == 0 &&
|
|
|
|
(tp->t_cflag & CLOCAL) == 0)) {
|
|
|
|
sc->sc_flags |= SC_ERROR;
|
|
|
|
DPRINTF(("strip: input, error %x\n", c)); /* XXX */
|
2005-11-27 08:35:52 +03:00
|
|
|
return (0);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
c &= TTY_CHARMASK;
|
|
|
|
|
|
|
|
++sc->sc_if.if_ibytes;
|
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/*
|
|
|
|
* Accumulate characters until we see a frame terminator (\r).
|
|
|
|
*/
|
1996-05-19 20:34:36 +04:00
|
|
|
switch (c) {
|
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
case '\n':
|
|
|
|
/*
|
|
|
|
* Error message strings from the modem are terminated with
|
|
|
|
* \r\n. This driver interprets the \r as a packet terminator.
|
|
|
|
* If the first character in a packet is a \n, drop it.
|
|
|
|
* (it can never be the first char of a vaild frame).
|
|
|
|
*/
|
2001-01-12 01:23:11 +03:00
|
|
|
if (sc->sc_mp - sc->sc_pktstart == 0)
|
1996-08-02 06:53:39 +04:00
|
|
|
break;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/* Fall through to */
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (sc->sc_mp < sc->sc_ep) {
|
|
|
|
*sc->sc_mp++ = c;
|
|
|
|
} else {
|
|
|
|
sc->sc_flags |= SC_ERROR;
|
|
|
|
goto error;
|
|
|
|
}
|
2005-11-27 08:35:52 +03:00
|
|
|
return (0);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
case STRIP_FRAME_END:
|
1996-08-02 06:53:39 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We only reach here if we see a CR delimiting a packet.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2001-01-12 01:23:11 +03:00
|
|
|
len = sc->sc_mp - sc->sc_pktstart;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
#ifdef XDEBUG
|
1996-08-02 06:53:39 +04:00
|
|
|
if (len < 15 || sc->sc_flags & SC_ERROR)
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("stripinput: end of pkt, len %d, err %d\n",
|
1996-10-11 02:59:41 +04:00
|
|
|
len, sc->sc_flags & SC_ERROR); /*XXX*/
|
1996-05-19 20:34:36 +04:00
|
|
|
#endif
|
1996-08-02 06:53:39 +04:00
|
|
|
if(sc->sc_flags & SC_ERROR) {
|
|
|
|
sc->sc_flags &= ~SC_ERROR;
|
|
|
|
addlog("%s: sc error flag set. terminating packet\n",
|
|
|
|
sc->sc_if.if_xname);
|
|
|
|
goto newpack;
|
|
|
|
}
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/*
|
|
|
|
* We have a frame.
|
|
|
|
* Process an IP packet, ARP packet, AppleTalk packet,
|
|
|
|
* AT command resposne, or Starmode error.
|
|
|
|
*/
|
2001-01-12 01:23:11 +03:00
|
|
|
len = strip_newpacket(sc, sc->sc_pktstart, sc->sc_mp);
|
1996-08-02 06:53:39 +04:00
|
|
|
if (len <= 1)
|
|
|
|
/* less than min length packet - ignore */
|
|
|
|
goto newpack;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
2001-01-12 01:23:11 +03:00
|
|
|
m = strip_btom(sc, len);
|
|
|
|
if (m == NULL)
|
|
|
|
goto error;
|
|
|
|
|
2001-01-12 01:31:49 +03:00
|
|
|
IF_ENQUEUE(&sc->sc_inq, m);
|
2007-10-08 20:18:02 +04:00
|
|
|
softint_schedule(sc->sc_si);
|
1996-08-02 06:53:39 +04:00
|
|
|
goto newpack;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
error:
|
|
|
|
sc->sc_if.if_ierrors++;
|
|
|
|
|
|
|
|
newpack:
|
2001-01-12 01:23:11 +03:00
|
|
|
sc->sc_mp = sc->sc_pktstart = (u_char *) sc->sc_mbuf->m_ext.ext_buf +
|
|
|
|
BUFOFFSET;
|
2005-11-27 08:35:52 +03:00
|
|
|
|
|
|
|
return (0);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
|
2005-12-12 02:05:24 +03:00
|
|
|
static void
|
2001-01-15 19:33:30 +03:00
|
|
|
stripintr(void *arg)
|
|
|
|
{
|
|
|
|
struct strip_softc *sc = arg;
|
|
|
|
struct tty *tp = sc->sc_ttyp;
|
2001-01-12 01:31:49 +03:00
|
|
|
struct mbuf *m;
|
2001-01-15 19:33:30 +03:00
|
|
|
int s, len;
|
2004-12-06 05:59:23 +03:00
|
|
|
u_char *pktstart;
|
|
|
|
#ifdef INET
|
|
|
|
u_char c;
|
|
|
|
#endif
|
2001-01-12 01:56:51 +03:00
|
|
|
u_char chdr[CHDR_LEN];
|
2001-01-12 01:31:49 +03:00
|
|
|
|
2001-01-15 19:33:30 +03:00
|
|
|
KASSERT(tp != NULL);
|
2001-01-12 22:03:24 +03:00
|
|
|
|
2001-01-15 19:33:30 +03:00
|
|
|
/*
|
|
|
|
* Output processing loop.
|
|
|
|
*/
|
2008-04-24 15:38:36 +04:00
|
|
|
mutex_enter(softnet_lock);
|
2001-01-15 19:33:30 +03:00
|
|
|
for (;;) {
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
2001-01-15 19:33:30 +03:00
|
|
|
struct ip *ip;
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
2001-01-15 19:33:30 +03:00
|
|
|
struct mbuf *bpf_m;
|
2001-01-12 22:03:24 +03:00
|
|
|
|
2001-01-15 19:33:30 +03:00
|
|
|
/*
|
|
|
|
* Do not remove the packet from the queue if it
|
|
|
|
* doesn't look like it will fit into the current
|
|
|
|
* serial output queue (STRIP_MTU_ONWIRE, or
|
|
|
|
* Starmode header + 20 bytes + 4 bytes in case we
|
|
|
|
* have to probe the radio).
|
|
|
|
*/
|
|
|
|
s = spltty();
|
|
|
|
if (tp->t_outq.c_cn - tp->t_outq.c_cc <
|
|
|
|
STRIP_MTU_ONWIRE + 4) {
|
2001-01-12 22:03:24 +03:00
|
|
|
splx(s);
|
2001-01-15 19:33:30 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
splx(s);
|
2001-01-12 22:03:24 +03:00
|
|
|
|
2001-01-15 19:33:30 +03:00
|
|
|
/*
|
|
|
|
* Get a packet and send it to the radio.
|
|
|
|
*/
|
|
|
|
s = splnet();
|
|
|
|
IF_DEQUEUE(&sc->sc_fastq, m);
|
|
|
|
if (m)
|
|
|
|
sc->sc_if.if_omcasts++; /* XXX */
|
|
|
|
else
|
|
|
|
IFQ_DEQUEUE(&sc->sc_if.if_snd, m);
|
|
|
|
splx(s);
|
2001-01-12 22:03:24 +03:00
|
|
|
|
2001-01-15 19:33:30 +03:00
|
|
|
if (m == NULL)
|
|
|
|
break;
|
2001-01-12 22:03:24 +03:00
|
|
|
|
2001-01-15 19:33:30 +03:00
|
|
|
/*
|
|
|
|
* We do the header compression here rather than in
|
|
|
|
* stripoutput() because the packets will be out of
|
|
|
|
* order if we are using TOS queueing, and the
|
|
|
|
* connection ID compression will get munged when
|
|
|
|
* this happens.
|
|
|
|
*/
|
|
|
|
if (sc->sc_if.if_bpf) {
|
2001-01-12 22:03:24 +03:00
|
|
|
/*
|
2001-01-15 19:33:30 +03:00
|
|
|
* We need to save the TCP/IP header before
|
|
|
|
* it's compressed. To avoid complicated
|
|
|
|
* code, we just make a deep copy of the
|
|
|
|
* entire packet (since this is a serial
|
|
|
|
* line, packets should be short and/or the
|
|
|
|
* copy should be negligible cost compared
|
|
|
|
* to the packet transmission time).
|
2001-01-12 22:03:24 +03:00
|
|
|
*/
|
2001-01-15 19:33:30 +03:00
|
|
|
bpf_m = m_dup(m, 0, M_COPYALL, M_DONTWAIT);
|
|
|
|
} else
|
|
|
|
bpf_m = NULL;
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
2001-01-15 19:33:30 +03:00
|
|
|
if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
|
|
|
|
if (sc->sc_if.if_flags & SC_COMPRESS)
|
|
|
|
*mtod(m, u_char *) |=
|
|
|
|
sl_compress_tcp(m, ip,
|
|
|
|
&sc->sc_comp, 1);
|
|
|
|
}
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
2010-04-05 11:19:28 +04:00
|
|
|
if (bpf_m != NULL)
|
|
|
|
bpf_mtap_sl_out(&sc->sc_if, mtod(m, u_char *), bpf_m);
|
2006-06-08 02:33:33 +04:00
|
|
|
getbinuptime(&sc->sc_lastpacket);
|
2001-01-15 19:33:30 +03:00
|
|
|
|
|
|
|
s = spltty();
|
|
|
|
strip_send(sc, m);
|
2001-01-12 22:03:24 +03:00
|
|
|
|
|
|
|
/*
|
2001-01-15 19:33:30 +03:00
|
|
|
* We now have characters in the output queue,
|
|
|
|
* kick the serial port.
|
2001-01-12 22:03:24 +03:00
|
|
|
*/
|
2001-01-15 19:33:30 +03:00
|
|
|
if (tp->t_outq.c_cc != 0)
|
|
|
|
(*tp->t_oproc)(tp);
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Input processing loop.
|
|
|
|
*/
|
|
|
|
for (;;) {
|
|
|
|
s = spltty();
|
|
|
|
IF_DEQUEUE(&sc->sc_inq, m);
|
|
|
|
splx(s);
|
|
|
|
if (m == NULL)
|
|
|
|
break;
|
|
|
|
pktstart = mtod(m, u_char *);
|
|
|
|
len = m->m_pkthdr.len;
|
|
|
|
if (sc->sc_if.if_bpf) {
|
|
|
|
/*
|
|
|
|
* Save the compressed header, so we
|
|
|
|
* can tack it on later. Note that we
|
|
|
|
* will end up copying garbage in come
|
|
|
|
* cases but this is okay. We remember
|
|
|
|
* where the buffer started so we can
|
|
|
|
* compute the new header length.
|
|
|
|
*/
|
|
|
|
memcpy(chdr, pktstart, CHDR_LEN);
|
|
|
|
}
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
2001-01-15 19:33:30 +03:00
|
|
|
if ((c = (*pktstart & 0xf0)) != (IPVERSION << 4)) {
|
|
|
|
if (c & 0x80)
|
|
|
|
c = TYPE_COMPRESSED_TCP;
|
|
|
|
else if (c == TYPE_UNCOMPRESSED_TCP)
|
|
|
|
*pktstart &= 0x4f; /* XXX */
|
|
|
|
/*
|
|
|
|
* We've got something that's not an IP
|
|
|
|
* packet. If compression is enabled,
|
|
|
|
* try to decompress it. Otherwise, if
|
|
|
|
* `auto-enable' compression is on and
|
|
|
|
* it's a reasonable packet, decompress
|
|
|
|
* it and then enable compression.
|
|
|
|
* Otherwise, drop it.
|
|
|
|
*/
|
|
|
|
if (sc->sc_if.if_flags & SC_COMPRESS) {
|
|
|
|
len = sl_uncompress_tcp(&pktstart, len,
|
|
|
|
(u_int)c, &sc->sc_comp);
|
|
|
|
if (len <= 0) {
|
|
|
|
m_freem(m);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if ((sc->sc_if.if_flags & SC_AUTOCOMP) &&
|
|
|
|
c == TYPE_UNCOMPRESSED_TCP && len >= 40) {
|
|
|
|
len = sl_uncompress_tcp(&pktstart, len,
|
|
|
|
(u_int)c, &sc->sc_comp);
|
|
|
|
if (len <= 0) {
|
2001-01-12 01:56:51 +03:00
|
|
|
m_freem(m);
|
|
|
|
continue;
|
|
|
|
}
|
2001-01-15 19:33:30 +03:00
|
|
|
sc->sc_if.if_flags |= SC_COMPRESS;
|
|
|
|
} else {
|
|
|
|
m_freem(m);
|
|
|
|
continue;
|
2001-01-12 01:56:51 +03:00
|
|
|
}
|
2001-01-15 19:33:30 +03:00
|
|
|
}
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
2007-03-04 08:59:00 +03:00
|
|
|
m->m_data = (void *) pktstart;
|
2001-01-15 19:33:30 +03:00
|
|
|
m->m_pkthdr.len = m->m_len = len;
|
|
|
|
if (sc->sc_if.if_bpf) {
|
2010-04-05 11:19:28 +04:00
|
|
|
bpf_mtap_sl_in(&sc->sc_if, chdr, &m);
|
2001-01-15 19:33:30 +03:00
|
|
|
if (m == NULL)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If the packet will fit into a single
|
|
|
|
* header mbuf, copy it into one, to save
|
|
|
|
* memory.
|
|
|
|
*/
|
|
|
|
if (m->m_pkthdr.len < MHLEN) {
|
|
|
|
struct mbuf *n;
|
2005-08-18 04:30:58 +04:00
|
|
|
int pktlen;
|
2001-01-15 19:33:30 +03:00
|
|
|
|
|
|
|
MGETHDR(n, M_DONTWAIT, MT_DATA);
|
2005-08-18 04:30:58 +04:00
|
|
|
pktlen = m->m_pkthdr.len;
|
|
|
|
M_MOVE_PKTHDR(n, m);
|
2007-03-04 08:59:00 +03:00
|
|
|
memcpy(mtod(n, void *), mtod(m, void *), pktlen);
|
2001-01-15 19:33:30 +03:00
|
|
|
n->m_len = m->m_len;
|
|
|
|
m_freem(m);
|
|
|
|
m = n;
|
|
|
|
}
|
2001-01-12 01:56:51 +03:00
|
|
|
|
2001-01-15 19:33:30 +03:00
|
|
|
sc->sc_if.if_ipackets++;
|
2006-06-08 02:33:33 +04:00
|
|
|
getbinuptime(&sc->sc_lastpacket);
|
2001-01-12 01:56:51 +03:00
|
|
|
|
2004-12-06 05:59:23 +03:00
|
|
|
#ifdef INET
|
2001-04-14 03:29:55 +04:00
|
|
|
s = splnet();
|
2001-01-15 19:33:30 +03:00
|
|
|
if (IF_QFULL(&ipintrq)) {
|
|
|
|
IF_DROP(&ipintrq);
|
|
|
|
sc->sc_if.if_ierrors++;
|
|
|
|
sc->sc_if.if_iqdrops++;
|
|
|
|
m_freem(m);
|
|
|
|
} else {
|
|
|
|
IF_ENQUEUE(&ipintrq, m);
|
|
|
|
schednetisr(NETISR_IP);
|
2001-01-12 01:31:49 +03:00
|
|
|
}
|
2001-01-15 19:33:30 +03:00
|
|
|
splx(s);
|
2004-12-06 05:59:23 +03:00
|
|
|
#endif
|
2001-01-12 01:31:49 +03:00
|
|
|
}
|
2008-04-24 15:38:36 +04:00
|
|
|
mutex_exit(softnet_lock);
|
2001-01-12 01:31:49 +03:00
|
|
|
}
|
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
/*
|
|
|
|
* Process an ioctl request.
|
|
|
|
*/
|
|
|
|
int
|
2007-03-04 08:59:00 +03:00
|
|
|
stripioctl(struct ifnet *ifp, u_long cmd, void *data)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct ifaddr *ifa = (struct ifaddr *)data;
|
|
|
|
struct ifreq *ifr;
|
|
|
|
int s, error = 0;
|
1997-11-20 11:03:06 +03:00
|
|
|
|
2001-01-12 22:26:48 +03:00
|
|
|
s = splnet();
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
case SIOCINITIFADDR:
|
1996-05-19 20:34:36 +04:00
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET)
|
|
|
|
ifp->if_flags |= IFF_UP;
|
|
|
|
else
|
|
|
|
error = EAFNOSUPPORT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCSIFDSTADDR:
|
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET)
|
|
|
|
error = EAFNOSUPPORT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SIOCADDMULTI:
|
|
|
|
case SIOCDELMULTI:
|
|
|
|
ifr = (struct ifreq *)data;
|
|
|
|
if (ifr == 0) {
|
|
|
|
error = EAFNOSUPPORT; /* XXX */
|
|
|
|
break;
|
|
|
|
}
|
2007-09-01 08:32:50 +04:00
|
|
|
switch (ifreq_getaddr(cmd, ifr)->sa_family) {
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
#ifdef INET
|
|
|
|
case AF_INET:
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
|
|
error = EAFNOSUPPORT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
|
|
|
error = ifioctl_common(ifp, cmd, data);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
return (error);
|
|
|
|
}
|
1996-08-02 06:53:39 +04:00
|
|
|
|
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
/*
|
|
|
|
* Strip subroutines
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set a radio into starmode.
|
2001-01-12 22:38:46 +03:00
|
|
|
* Must be called at spltty().
|
1996-05-19 20:34:36 +04:00
|
|
|
*/
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
strip_resetradio(struct strip_softc *sc, struct tty *tp)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
static ttychar_t InitString[] =
|
|
|
|
"\r\n\r\n\r\nat\r\n\r\n\r\nate0dt**starmode\r\n**\r\n";
|
|
|
|
#else
|
|
|
|
static ttychar_t InitString[] =
|
1996-08-02 06:53:39 +04:00
|
|
|
"\r\rat\r\r\rate0q1dt**starmode\r**\r";
|
1996-05-19 20:34:36 +04:00
|
|
|
#endif
|
2000-03-30 13:45:33 +04:00
|
|
|
int i;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-06-26 10:04:20 +04:00
|
|
|
/*
|
|
|
|
* XXX Perhaps flush tty output queue?
|
|
|
|
*/
|
1996-08-02 06:53:39 +04:00
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
if ((i = b_to_q(InitString, sizeof(InitString) - 1, &tp->t_outq))) {
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("resetradio: %d chars didn't fit in tty queue\n", i);
|
1996-05-19 20:34:36 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
sc->sc_if.if_obytes += sizeof(InitString) - 1;
|
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/*
|
|
|
|
* Assume the radio is still dead, so we can detect repeated
|
|
|
|
* resets (perhaps the radio is disconnected, powered off, or
|
|
|
|
* is so badlyhung it needs powercycling.
|
|
|
|
*/
|
|
|
|
sc->sc_state = ST_DEAD;
|
2006-06-08 02:33:33 +04:00
|
|
|
getbinuptime(&sc->sc_lastpacket);
|
|
|
|
sc->sc_statetimo = time_second + STRIP_RESET_INTERVAL;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-06-26 10:04:20 +04:00
|
|
|
/*
|
|
|
|
* XXX Does calling the tty output routine now help resets?
|
|
|
|
*/
|
1996-05-19 20:34:36 +04:00
|
|
|
(*sc->sc_ttyp->t_oproc)(tp);
|
|
|
|
}
|
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Send an invalid starmode packet to the radio, to induce an error message
|
|
|
|
* indicating the radio is in starmode.
|
|
|
|
* Update the state machine to indicate a response is expected.
|
|
|
|
* Either the radio answers, which will be caught by the parser,
|
|
|
|
* or the watchdog will start resetting.
|
|
|
|
*
|
|
|
|
* NOTE: drops chars directly on the tty output queue.
|
|
|
|
* should be caled at spl >= spltty.
|
|
|
|
*/
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
strip_proberadio(struct strip_softc *sc, struct tty *tp)
|
1996-08-02 06:53:39 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
int overflow;
|
|
|
|
const char *strip_probestr = "**";
|
|
|
|
|
|
|
|
if (sc->sc_if.if_flags & IFF_DEBUG)
|
|
|
|
addlog("%s: attempting to probe radio\n", sc->sc_if.if_xname);
|
|
|
|
|
1996-10-26 02:15:54 +04:00
|
|
|
overflow = b_to_q((const ttychar_t *)strip_probestr, 2, &tp->t_outq);
|
1996-08-02 06:53:39 +04:00
|
|
|
if (overflow == 0) {
|
|
|
|
if (sc->sc_if.if_flags & IFF_DEBUG)
|
|
|
|
addlog("%s:: sent probe to radio\n",
|
|
|
|
sc->sc_if.if_xname);
|
|
|
|
/* Go to probe-sent state, set timeout accordingly. */
|
|
|
|
sc->sc_state = ST_PROBE_SENT;
|
2006-06-08 02:33:33 +04:00
|
|
|
sc->sc_statetimo = time_second + ST_PROBERESPONSE_INTERVAL;
|
1996-08-02 06:53:39 +04:00
|
|
|
} else {
|
|
|
|
addlog("%s: incomplete probe, tty queue %d bytes overfull\n",
|
|
|
|
sc->sc_if.if_xname, overflow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2005-05-30 01:22:52 +04:00
|
|
|
static const char *strip_statenames[] = {
|
1996-08-02 06:53:39 +04:00
|
|
|
"Alive",
|
|
|
|
"Probe sent, awaiting answer",
|
|
|
|
"Probe not answered, resetting"
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Timeout routine -- try to start more output.
|
|
|
|
* Will be needed to make strip work on ptys.
|
|
|
|
*/
|
2000-03-23 10:01:25 +03:00
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
strip_timeout(void *x)
|
1996-08-02 06:53:39 +04:00
|
|
|
{
|
1997-11-18 02:35:28 +03:00
|
|
|
struct strip_softc *sc = (struct strip_softc *) x;
|
1996-08-02 06:53:39 +04:00
|
|
|
struct tty *tp = sc->sc_ttyp;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
s = spltty();
|
|
|
|
sc->sc_flags &= ~SC_TIMEOUT;
|
|
|
|
stripstart(tp);
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
2005-02-27 01:45:09 +03:00
|
|
|
|
1996-06-26 10:04:20 +04:00
|
|
|
/*
|
|
|
|
* Strip watchdog routine.
|
1996-08-02 06:53:39 +04:00
|
|
|
* The radio hardware is balky. When sent long packets or bursts of small
|
|
|
|
* packets, the radios crash and reboots into Hayes-emulation mode.
|
|
|
|
* The transmit-side machinery, the error parser, and strip_watchdog()
|
|
|
|
* implement a simple finite state machine.
|
|
|
|
*
|
|
|
|
* We attempt to send a probe to the radio every ST_PROBE seconds. There
|
|
|
|
* is no direct way to tell if the radio is in starmode, so we send it a
|
|
|
|
* malformed starmode packet -- a frame with no destination address --
|
|
|
|
* and expect to an "name missing" error response from the radio within
|
|
|
|
* 1 second. If we hear such a response, we assume the radio is alive
|
|
|
|
* for the next ST_PROBE seconds.
|
|
|
|
* If we don't hear a starmode-error response from the radio, we reset it.
|
|
|
|
*
|
|
|
|
* Probes, and parsing of error responses, are normally done inside the send
|
|
|
|
* and receive side respectively. This watchdog routine examines the
|
|
|
|
* state-machine variables. If there are no packets to send to the radio
|
|
|
|
* during an entire probe interval, strip_output will not be called,
|
|
|
|
* so we send a probe on its behalf.
|
1996-06-26 10:04:20 +04:00
|
|
|
*/
|
|
|
|
void
|
2005-12-12 02:05:24 +03:00
|
|
|
strip_watchdog(struct ifnet *ifp)
|
1996-06-26 10:04:20 +04:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
struct strip_softc *sc = ifp->if_softc;
|
1996-08-02 06:53:39 +04:00
|
|
|
struct tty *tp = sc->sc_ttyp;
|
|
|
|
|
1997-11-20 11:03:06 +03:00
|
|
|
/*
|
|
|
|
* Just punt if the line has been closed.
|
|
|
|
*/
|
|
|
|
if (tp == NULL)
|
|
|
|
return;
|
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (ifp->if_flags & IFF_DEBUG)
|
2009-01-11 05:45:45 +03:00
|
|
|
addlog("\n%s: in watchdog, state %s timeout %lld\n",
|
1996-08-02 06:53:39 +04:00
|
|
|
ifp->if_xname,
|
|
|
|
((unsigned) sc->sc_state < 3) ?
|
|
|
|
strip_statenames[sc->sc_state] : "<<illegal state>>",
|
2009-01-11 05:45:45 +03:00
|
|
|
(long long)(sc->sc_statetimo - time_second));
|
1996-08-02 06:53:39 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If time in this state hasn't yet expired, return.
|
|
|
|
*/
|
2006-06-08 02:33:33 +04:00
|
|
|
if ((ifp->if_flags & IFF_UP) == 0 || sc->sc_statetimo > time_second) {
|
1996-08-02 06:53:39 +04:00
|
|
|
goto done;
|
|
|
|
}
|
1996-06-26 10:04:20 +04:00
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/*
|
|
|
|
* The time in the current state has expired.
|
|
|
|
* Take appropriate action and advance FSA to the next state.
|
|
|
|
*/
|
|
|
|
switch (sc->sc_state) {
|
|
|
|
case ST_ALIVE:
|
|
|
|
/*
|
|
|
|
* A probe is due but we haven't piggybacked one on a packet.
|
|
|
|
* Send a probe now.
|
|
|
|
*/
|
|
|
|
strip_proberadio(sc, sc->sc_ttyp);
|
|
|
|
(*tp->t_oproc)(tp);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ST_PROBE_SENT:
|
|
|
|
/*
|
|
|
|
* Probe sent but no response within timeout. Reset.
|
|
|
|
*/
|
|
|
|
addlog("%s: no answer to probe, resetting radio\n",
|
|
|
|
ifp->if_xname);
|
|
|
|
strip_resetradio(sc, sc->sc_ttyp);
|
|
|
|
ifp->if_oerrors++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ST_DEAD:
|
|
|
|
/*
|
|
|
|
* The radio has been sent a reset but didn't respond.
|
|
|
|
* XXX warn user to remove AC adaptor and battery,
|
|
|
|
* wait 5 secs, and replace.
|
|
|
|
*/
|
|
|
|
addlog("%s: radio reset but not responding, Trying again\n",
|
|
|
|
ifp->if_xname);
|
|
|
|
strip_resetradio(sc, sc->sc_ttyp);
|
|
|
|
ifp->if_oerrors++;
|
|
|
|
break;
|
1996-06-26 10:04:20 +04:00
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
default:
|
|
|
|
/* Cannot happen. To be safe, do a reset. */
|
|
|
|
addlog("%s: %s %d, resetting\n",
|
|
|
|
sc->sc_if.if_xname,
|
|
|
|
"radio-reset finite-state machine in invalid state",
|
|
|
|
sc->sc_state);
|
1996-06-26 10:04:20 +04:00
|
|
|
strip_resetradio(sc, sc->sc_ttyp);
|
1996-08-02 06:53:39 +04:00
|
|
|
sc->sc_state = ST_DEAD;
|
|
|
|
break;
|
1996-06-26 10:04:20 +04:00
|
|
|
}
|
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
done:
|
|
|
|
ifp->if_timer = STRIP_WATCHDOG_INTERVAL;
|
1996-06-26 10:04:20 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
/*
|
1996-08-02 06:53:39 +04:00
|
|
|
* The following bytestuffing and run-length encoding/decoding
|
2002-02-26 17:54:50 +03:00
|
|
|
* functions are taken, with permission from Stuart Cheshire,
|
|
|
|
* from the MosquitonNet strip driver for Linux.
|
1996-08-02 06:53:39 +04:00
|
|
|
* XXX Linux style left intact, to ease folding in updates from
|
|
|
|
* the Mosquitonet group.
|
1996-05-19 20:34:36 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process a received packet.
|
|
|
|
*/
|
|
|
|
int
|
2005-12-12 02:05:24 +03:00
|
|
|
strip_newpacket(struct strip_softc *sc, u_char *ptr, u_char *end)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2000-03-30 13:45:33 +04:00
|
|
|
int len = ptr - end;
|
|
|
|
u_char *name, *name_end;
|
1996-05-19 20:34:36 +04:00
|
|
|
u_int packetlen;
|
|
|
|
|
|
|
|
/* Ignore empty lines */
|
|
|
|
if (len == 0) return 0;
|
|
|
|
|
|
|
|
/* Catch 'OK' responses which show radio has fallen out of starmode */
|
|
|
|
if (len >= 2 && ptr[0] == 'O' && ptr[1] == 'K') {
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("%s: Radio is back in AT command mode: will reset\n",
|
1996-10-11 02:59:41 +04:00
|
|
|
sc->sc_if.if_xname);
|
1996-05-19 20:34:36 +04:00
|
|
|
FORCE_RESET(sc); /* Do reset ASAP */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for start of address marker, and then skip over it */
|
|
|
|
if (*ptr != '*') {
|
|
|
|
/* Catch other error messages */
|
|
|
|
if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' && ptr[3] == '_')
|
1996-08-02 06:53:39 +04:00
|
|
|
RecvErr_Message(sc, NULL, ptr+4);
|
1996-06-26 10:04:20 +04:00
|
|
|
/* XXX what should the message above be? */
|
1996-05-19 20:34:36 +04:00
|
|
|
else {
|
1996-06-26 10:04:20 +04:00
|
|
|
RecvErr("No initial *", sc);
|
1996-08-02 06:53:39 +04:00
|
|
|
addlog("(len = %d)\n", len);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* skip the '*' */
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
/* Skip the return address */
|
|
|
|
name = ptr;
|
|
|
|
while (ptr < end && *ptr != '*')
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
/* Check for end of address marker, and skip over it */
|
|
|
|
if (ptr == end) {
|
1996-06-26 10:04:20 +04:00
|
|
|
RecvErr("No second *", sc);
|
1996-05-19 20:34:36 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
name_end = ptr++;
|
|
|
|
|
|
|
|
/* Check for SRIP key, and skip over it */
|
|
|
|
if (ptr[0] != 'S' || ptr[1] != 'I' || ptr[2] != 'P' || ptr[3] != '0') {
|
|
|
|
if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' &&
|
2005-02-27 01:45:09 +03:00
|
|
|
ptr[3] == '_') {
|
1996-05-19 20:34:36 +04:00
|
|
|
*name_end = 0;
|
1996-08-02 06:53:39 +04:00
|
|
|
RecvErr_Message(sc, name, ptr+4);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
1996-06-26 10:04:20 +04:00
|
|
|
else RecvErr("No SRIP key", sc);
|
1996-05-19 20:34:36 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ptr += 4;
|
|
|
|
|
|
|
|
/* Decode start of the IP packet header */
|
|
|
|
ptr = UnStuffData(ptr, end, sc->sc_rxbuf, 4);
|
1996-08-02 06:53:39 +04:00
|
|
|
if (ptr == 0) {
|
1996-06-26 10:04:20 +04:00
|
|
|
RecvErr("Runt packet (hdr)", sc);
|
1996-05-19 20:34:36 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/*
|
|
|
|
* The STRIP bytestuff/RLL encoding has no explicit length
|
|
|
|
* of the decoded packet. Decode start of IP header, get the
|
|
|
|
* IP header length and decode that many bytes in total.
|
|
|
|
*/
|
2008-02-20 20:05:52 +03:00
|
|
|
packetlen = ((uint16_t)sc->sc_rxbuf[2] << 8) | sc->sc_rxbuf[3];
|
1996-06-26 10:04:20 +04:00
|
|
|
|
|
|
|
#ifdef DIAGNOSTIC
|
1996-10-11 02:59:41 +04:00
|
|
|
#if 0
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("Packet %02x.%02x.%02x.%02x\n",
|
1996-05-19 20:34:36 +04:00
|
|
|
sc->sc_rxbuf[0], sc->sc_rxbuf[1],
|
|
|
|
sc->sc_rxbuf[2], sc->sc_rxbuf[3]);
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("Got %d byte packet\n", packetlen);
|
1996-10-11 02:59:41 +04:00
|
|
|
#endif
|
1996-06-26 10:04:20 +04:00
|
|
|
#endif
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
/* Decode remainder of the IP packer */
|
|
|
|
ptr = UnStuffData(ptr, end, sc->sc_rxbuf+4, packetlen-4);
|
1996-08-02 06:53:39 +04:00
|
|
|
if (ptr == 0) {
|
1996-06-26 10:04:20 +04:00
|
|
|
RecvErr("Short packet", sc);
|
1996-05-19 20:34:36 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1996-06-26 10:04:20 +04:00
|
|
|
/* XXX redundant copy */
|
2009-04-18 18:58:02 +04:00
|
|
|
memcpy(sc->sc_pktstart, sc->sc_rxbuf, packetlen );
|
2002-09-11 09:36:26 +04:00
|
|
|
return (packetlen);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stuffing scheme:
|
|
|
|
* 00 Unused (reserved character)
|
|
|
|
* 01-3F Run of 2-64 different characters
|
|
|
|
* 40-7F Run of 1-64 different characters plus a single zero at the end
|
|
|
|
* 80-BF Run of 1-64 of the same character
|
|
|
|
* C0-FF Run of 1-64 zeroes (ASCII 0)
|
|
|
|
*/
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
Stuff_Diff = 0x00,
|
|
|
|
Stuff_DiffZero = 0x40,
|
|
|
|
Stuff_Same = 0x80,
|
|
|
|
Stuff_Zero = 0xC0,
|
|
|
|
Stuff_NoCode = 0xFF, /* Special code, meaning no code selected */
|
2005-02-27 01:45:09 +03:00
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
Stuff_CodeMask = 0xC0,
|
|
|
|
Stuff_CountMask = 0x3F,
|
|
|
|
Stuff_MaxCount = 0x3F,
|
|
|
|
Stuff_Magic = 0x0D /* The value we are eliminating */
|
|
|
|
} StuffingCode;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* StuffData encodes the data starting at "src" for "length" bytes.
|
|
|
|
* It writes it to the buffer pointed to by "dest" (which must be at least
|
|
|
|
* as long as 1 + 65/64 of the input length). The output may be up to 1.6%
|
|
|
|
* larger than the input for pathological input, but will usually be smaller.
|
|
|
|
* StuffData returns the new value of the dest pointer as its result.
|
|
|
|
*
|
|
|
|
* "code_ptr_ptr" points to a "u_char *" which is used to hold
|
|
|
|
* encoding state between calls, allowing an encoded packet to be
|
|
|
|
* incrementally built up from small parts.
|
|
|
|
* On the first call, the "u_char *" pointed to should be initialized
|
|
|
|
* to NULL; between subsequent calls the calling routine should leave
|
|
|
|
* the value alone and simply pass it back unchanged so that the
|
|
|
|
* encoder can recover its current state.
|
2005-02-27 01:45:09 +03:00
|
|
|
*/
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
#define StuffData_FinishBlock(X) \
|
|
|
|
(*code_ptr = (X) ^ Stuff_Magic, code = Stuff_NoCode)
|
|
|
|
|
|
|
|
static u_char*
|
|
|
|
StuffData(u_char *src, u_long length, u_char *dest, u_char **code_ptr_ptr)
|
|
|
|
{
|
|
|
|
u_char *end = src + length;
|
|
|
|
u_char *code_ptr = *code_ptr_ptr;
|
|
|
|
u_char code = Stuff_NoCode, count = 0;
|
2005-02-27 01:45:09 +03:00
|
|
|
|
2002-09-11 09:36:26 +04:00
|
|
|
if (!length) return (dest);
|
2005-02-27 01:45:09 +03:00
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
if (code_ptr) { /* Recover state from last call, if applicable */
|
1996-06-26 10:04:20 +04:00
|
|
|
code = (*code_ptr ^ Stuff_Magic) & Stuff_CodeMask;
|
|
|
|
count = (*code_ptr ^ Stuff_Magic) & Stuff_CountMask;
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
while (src < end) {
|
|
|
|
switch (code) {
|
|
|
|
/*
|
|
|
|
* Stuff_NoCode: If no current code, select one
|
|
|
|
*/
|
|
|
|
case Stuff_NoCode:
|
|
|
|
code_ptr = dest++; /* Record where we're going to put this code */
|
|
|
|
count = 0; /* Reset the count (zero means one instance) */
|
|
|
|
/* Tentatively start a new block */
|
|
|
|
if (*src == 0) {
|
|
|
|
code = Stuff_Zero;
|
|
|
|
src++;
|
|
|
|
} else {
|
|
|
|
code = Stuff_Same;
|
|
|
|
*dest++ = *src++ ^ Stuff_Magic;
|
|
|
|
}
|
|
|
|
/* Note: We optimistically assume run of same -- which will be */
|
|
|
|
/* fixed later in Stuff_Same if it turns out not to be true. */
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stuff_Zero: We already have at least one zero encoded
|
|
|
|
*/
|
|
|
|
case Stuff_Zero:
|
2005-02-27 01:45:09 +03:00
|
|
|
|
1996-05-19 20:34:36 +04:00
|
|
|
/* If another zero, count it, else finish this code block */
|
|
|
|
if (*src == 0) {
|
|
|
|
count++;
|
|
|
|
src++;
|
|
|
|
} else
|
|
|
|
StuffData_FinishBlock(Stuff_Zero + count);
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stuff_Same: We already have at least one byte encoded
|
|
|
|
*/
|
|
|
|
case Stuff_Same:
|
|
|
|
/* If another one the same, count it */
|
|
|
|
if ((*src ^ Stuff_Magic) == code_ptr[1]) {
|
|
|
|
count++;
|
|
|
|
src++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* else, this byte does not match this block. */
|
|
|
|
/* If we already have two or more bytes encoded, finish this code block */
|
|
|
|
if (count) {
|
|
|
|
StuffData_FinishBlock(Stuff_Same + count);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* else, we only have one so far, so switch to Stuff_Diff code */
|
|
|
|
code = Stuff_Diff; /* and fall through to Stuff_Diff case below */
|
|
|
|
|
|
|
|
case Stuff_Diff: /* Stuff_Diff: We have at least two *different* bytes encoded */
|
|
|
|
/* If this is a zero, must encode a Stuff_DiffZero, and begin a new block */
|
|
|
|
if (*src == 0)
|
|
|
|
StuffData_FinishBlock(Stuff_DiffZero + count);
|
|
|
|
/* else, if we have three in a row, it is worth starting a Stuff_Same block */
|
|
|
|
else if ((*src ^ Stuff_Magic) == dest[-1] && dest[-1] == dest[-2])
|
|
|
|
{
|
|
|
|
code += count-2;
|
|
|
|
if (code == Stuff_Diff)
|
|
|
|
code = Stuff_Same;
|
|
|
|
StuffData_FinishBlock(code);
|
|
|
|
code_ptr = dest-2;
|
|
|
|
/* dest[-1] already holds the correct value */
|
|
|
|
count = 2; /* 2 means three bytes encoded */
|
|
|
|
code = Stuff_Same;
|
|
|
|
}
|
|
|
|
/* else, another different byte, so add it to the block */
|
|
|
|
else {
|
|
|
|
*dest++ = *src ^ Stuff_Magic;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
src++; /* Consume the byte */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count == Stuff_MaxCount)
|
|
|
|
StuffData_FinishBlock(code + count);
|
|
|
|
}
|
|
|
|
if (code == Stuff_NoCode)
|
|
|
|
*code_ptr_ptr = NULL;
|
|
|
|
else {
|
|
|
|
*code_ptr_ptr = code_ptr;
|
|
|
|
StuffData_FinishBlock(code + count);
|
|
|
|
}
|
|
|
|
|
2002-09-11 09:36:26 +04:00
|
|
|
return (dest);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* UnStuffData decodes the data at "src", up to (but not including)
|
|
|
|
* "end". It writes the decoded data into the buffer pointed to by
|
1996-08-02 06:53:39 +04:00
|
|
|
* "dst", up to a maximum of "dst_length", and returns the new
|
1996-05-19 20:34:36 +04:00
|
|
|
* value of "src" so that a follow-on call can read more data,
|
2005-02-27 01:45:09 +03:00
|
|
|
* continuing from where the first left off.
|
1996-05-19 20:34:36 +04:00
|
|
|
*
|
|
|
|
* There are three types of results:
|
1996-08-02 06:53:39 +04:00
|
|
|
* 1. The source data runs out before extracting "dst_length" bytes:
|
1996-05-19 20:34:36 +04:00
|
|
|
* UnStuffData returns NULL to indicate failure.
|
1996-08-02 06:53:39 +04:00
|
|
|
* 2. The source data produces exactly "dst_length" bytes:
|
1996-05-19 20:34:36 +04:00
|
|
|
* UnStuffData returns new_src = end to indicate that all bytes
|
2005-02-27 01:45:09 +03:00
|
|
|
* were consumed.
|
1996-08-02 06:53:39 +04:00
|
|
|
* 3. "dst_length" bytes are extracted, with more
|
1996-05-19 20:34:36 +04:00
|
|
|
* remaining. UnStuffData returns new_src < end to indicate that
|
|
|
|
* there are more bytes to be read.
|
|
|
|
*
|
1996-08-02 06:53:39 +04:00
|
|
|
* Note: The decoding may be dstructive, in that it may alter the
|
1996-05-19 20:34:36 +04:00
|
|
|
* source data in the process of decoding it (this is necessary to
|
|
|
|
* allow a follow-on call to resume correctly).
|
|
|
|
*/
|
|
|
|
|
|
|
|
static u_char*
|
1996-08-02 06:53:39 +04:00
|
|
|
UnStuffData(u_char *src, u_char *end, u_char *dst, u_long dst_length)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
1996-08-02 06:53:39 +04:00
|
|
|
u_char *dst_end = dst + dst_length;
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-06-26 10:04:20 +04:00
|
|
|
/* Sanity check */
|
1996-08-02 06:53:39 +04:00
|
|
|
if (!src || !end || !dst || !dst_length)
|
2002-09-11 09:36:26 +04:00
|
|
|
return (NULL);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
while (src < end && dst < dst_end)
|
|
|
|
{
|
1996-05-19 20:34:36 +04:00
|
|
|
int count = (*src ^ Stuff_Magic) & Stuff_CountMask;
|
|
|
|
switch ((*src ^ Stuff_Magic) & Stuff_CodeMask)
|
|
|
|
{
|
|
|
|
case Stuff_Diff:
|
|
|
|
if (src+1+count >= end)
|
2002-09-11 09:36:26 +04:00
|
|
|
return (NULL);
|
1996-05-19 20:34:36 +04:00
|
|
|
do
|
1996-08-02 06:53:39 +04:00
|
|
|
{
|
|
|
|
*dst++ = *++src ^ Stuff_Magic;
|
|
|
|
}
|
|
|
|
while(--count >= 0 && dst < dst_end);
|
1996-05-19 20:34:36 +04:00
|
|
|
if (count < 0)
|
|
|
|
src += 1;
|
1996-08-02 06:53:39 +04:00
|
|
|
else
|
|
|
|
if (count == 0)
|
1996-05-19 20:34:36 +04:00
|
|
|
*src = Stuff_Same ^ Stuff_Magic;
|
|
|
|
else
|
|
|
|
*src = (Stuff_Diff + count) ^ Stuff_Magic;
|
|
|
|
break;
|
|
|
|
case Stuff_DiffZero:
|
|
|
|
if (src+1+count >= end)
|
2002-09-11 09:36:26 +04:00
|
|
|
return (NULL);
|
1996-05-19 20:34:36 +04:00
|
|
|
do
|
1996-08-02 06:53:39 +04:00
|
|
|
{
|
|
|
|
*dst++ = *++src ^ Stuff_Magic;
|
|
|
|
}
|
|
|
|
while(--count >= 0 && dst < dst_end);
|
1996-05-19 20:34:36 +04:00
|
|
|
if (count < 0)
|
|
|
|
*src = Stuff_Zero ^ Stuff_Magic;
|
|
|
|
else
|
|
|
|
*src = (Stuff_DiffZero + count) ^ Stuff_Magic;
|
|
|
|
break;
|
|
|
|
case Stuff_Same:
|
|
|
|
if (src+1 >= end)
|
2002-09-11 09:36:26 +04:00
|
|
|
return (NULL);
|
1996-05-19 20:34:36 +04:00
|
|
|
do
|
1996-08-02 06:53:39 +04:00
|
|
|
{
|
|
|
|
*dst++ = src[1] ^ Stuff_Magic;
|
|
|
|
}
|
|
|
|
while(--count >= 0 && dst < dst_end);
|
1996-05-19 20:34:36 +04:00
|
|
|
if (count < 0)
|
|
|
|
src += 2;
|
|
|
|
else
|
|
|
|
*src = (Stuff_Same + count) ^ Stuff_Magic;
|
|
|
|
break;
|
|
|
|
case Stuff_Zero:
|
|
|
|
do
|
1996-08-02 06:53:39 +04:00
|
|
|
{
|
|
|
|
*dst++ = 0;
|
|
|
|
}
|
|
|
|
while(--count >= 0 && dst < dst_end);
|
1996-05-19 20:34:36 +04:00
|
|
|
if (count < 0)
|
|
|
|
src += 1;
|
|
|
|
else
|
|
|
|
*src = (Stuff_Zero + count) ^ Stuff_Magic;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
if (dst < dst_end)
|
2002-09-11 09:36:26 +04:00
|
|
|
return (NULL);
|
1996-05-19 20:34:36 +04:00
|
|
|
else
|
2002-09-11 09:36:26 +04:00
|
|
|
return (src);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Log an error mesesage (for a packet received with errors?)
|
1996-06-26 10:04:20 +04:00
|
|
|
* from the STRIP driver.
|
1996-05-19 20:34:36 +04:00
|
|
|
*/
|
|
|
|
static void
|
2005-12-12 02:05:24 +03:00
|
|
|
RecvErr(const char *msg, struct strip_softc *sc)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
2001-05-07 14:15:46 +04:00
|
|
|
#define MAX_RecErr 80
|
2001-01-12 01:23:11 +03:00
|
|
|
u_char *ptr = sc->sc_pktstart;
|
1996-05-19 20:34:36 +04:00
|
|
|
u_char *end = sc->sc_mp;
|
|
|
|
u_char pkt_text[MAX_RecErr], *p = pkt_text;
|
|
|
|
*p++ = '\"';
|
|
|
|
while (ptr < end && p < &pkt_text[MAX_RecErr-4]) {
|
|
|
|
if (*ptr == '\\') {
|
|
|
|
*p++ = '\\';
|
|
|
|
*p++ = '\\';
|
|
|
|
} else if (*ptr >= 32 && *ptr <= 126)
|
|
|
|
*p++ = *ptr;
|
|
|
|
else {
|
2004-04-21 22:40:37 +04:00
|
|
|
snprintf(p, sizeof(pkt_text) - (p - pkt_text),
|
|
|
|
"\\%02x", *ptr);
|
|
|
|
p += 3;
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr == end) *p++ = '\"';
|
|
|
|
*p++ = 0;
|
1996-08-02 06:53:39 +04:00
|
|
|
addlog("%s: %13s : %s\n", sc->sc_if.if_xname, msg, pkt_text);
|
1996-05-19 20:34:36 +04:00
|
|
|
|
|
|
|
sc->sc_if.if_ierrors++;
|
|
|
|
}
|
|
|
|
|
1996-06-26 10:04:20 +04:00
|
|
|
|
1996-08-02 06:53:39 +04:00
|
|
|
/*
|
|
|
|
* Parse an error message from the radio.
|
|
|
|
*/
|
1996-05-19 20:34:36 +04:00
|
|
|
static void
|
2005-12-12 02:05:24 +03:00
|
|
|
RecvErr_Message(struct strip_softc *strip_info, u_char *sendername,
|
|
|
|
const u_char *msg)
|
1996-05-19 20:34:36 +04:00
|
|
|
{
|
1996-06-26 10:04:20 +04:00
|
|
|
static const char ERR_001[] = "001"; /* Not in StarMode! */
|
|
|
|
static const char ERR_002[] = "002"; /* Remap handle */
|
|
|
|
static const char ERR_003[] = "003"; /* Can't resolve name */
|
|
|
|
static const char ERR_004[] = "004"; /* Name too small or missing */
|
|
|
|
static const char ERR_005[] = "005"; /* Bad count specification */
|
|
|
|
static const char ERR_006[] = "006"; /* Header too big */
|
|
|
|
static const char ERR_007[] = "007"; /* Body too big */
|
|
|
|
static const char ERR_008[] = "008"; /* Bad character in name */
|
|
|
|
static const char ERR_009[] = "009"; /* No count or line terminator */
|
|
|
|
|
|
|
|
char * if_name;
|
|
|
|
|
|
|
|
if_name = strip_info->sc_if.if_xname;
|
|
|
|
|
|
|
|
if (!strncmp(msg, ERR_001, sizeof(ERR_001)-1))
|
|
|
|
{
|
1996-08-02 06:53:39 +04:00
|
|
|
RecvErr("radio error message:", strip_info);
|
1996-06-26 10:04:20 +04:00
|
|
|
addlog("%s: Radio %s is not in StarMode\n",
|
|
|
|
if_name, sendername);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
1996-06-26 10:04:20 +04:00
|
|
|
else if (!strncmp(msg, ERR_002, sizeof(ERR_002)-1))
|
|
|
|
{
|
1996-08-02 06:53:39 +04:00
|
|
|
RecvErr("radio error message:", strip_info);
|
1996-05-19 20:34:36 +04:00
|
|
|
#ifdef notyet /*Kernel doesn't have scanf!*/
|
|
|
|
int handle;
|
|
|
|
u_char newname[64];
|
|
|
|
sscanf(msg, "ERR_002 Remap handle &%d to name %s", &handle, newname);
|
1996-06-26 10:04:20 +04:00
|
|
|
addlog("%s: Radio name %s is handle %d\n",
|
|
|
|
if_name, newname, handle);
|
1996-05-19 20:34:36 +04:00
|
|
|
#endif
|
|
|
|
}
|
1996-06-26 10:04:20 +04:00
|
|
|
else if (!strncmp(msg, ERR_003, sizeof(ERR_003)-1))
|
|
|
|
{
|
1996-08-02 06:53:39 +04:00
|
|
|
RecvErr("radio error message:", strip_info);
|
1996-06-26 10:04:20 +04:00
|
|
|
addlog("%s: Destination radio name is unknown\n", if_name);
|
|
|
|
}
|
1996-08-02 06:53:39 +04:00
|
|
|
else if (!strncmp(msg, ERR_004, sizeof(ERR_004)-1)) {
|
|
|
|
/*
|
|
|
|
* The radio reports it got a badly-framed starmode packet
|
|
|
|
* from us; so it must me in starmode.
|
|
|
|
*/
|
|
|
|
if (strip_info->sc_if.if_flags & IFF_DEBUG)
|
|
|
|
addlog("%s: radio responded to probe\n", if_name);
|
|
|
|
if (strip_info->sc_state == ST_DEAD) {
|
|
|
|
/* A successful reset... */
|
|
|
|
addlog("%s: Radio back in starmode\n", if_name);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
1996-08-02 06:53:39 +04:00
|
|
|
CLEAR_RESET_TIMER(strip_info);
|
1996-06-26 10:04:20 +04:00
|
|
|
}
|
|
|
|
else if (!strncmp(msg, ERR_005, sizeof(ERR_005)-1))
|
1996-08-02 06:53:39 +04:00
|
|
|
RecvErr("radio error message:", strip_info);
|
1996-06-26 10:04:20 +04:00
|
|
|
else if (!strncmp(msg, ERR_006, sizeof(ERR_006)-1))
|
1996-08-02 06:53:39 +04:00
|
|
|
RecvErr("radio error message:", strip_info);
|
1996-06-26 10:04:20 +04:00
|
|
|
else if (!strncmp(msg, ERR_007, sizeof(ERR_007)-1))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Note: This error knocks the radio back into
|
|
|
|
* command mode.
|
|
|
|
*/
|
1996-08-02 06:53:39 +04:00
|
|
|
RecvErr("radio error message:", strip_info);
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("%s: Error! Packet size too big for radio.",
|
1996-10-11 02:59:41 +04:00
|
|
|
if_name);
|
1996-08-02 06:53:39 +04:00
|
|
|
FORCE_RESET(strip_info);
|
1996-06-26 10:04:20 +04:00
|
|
|
}
|
|
|
|
else if (!strncmp(msg, ERR_008, sizeof(ERR_008)-1))
|
|
|
|
{
|
1996-08-02 06:53:39 +04:00
|
|
|
RecvErr("radio error message:", strip_info);
|
1996-10-13 06:10:01 +04:00
|
|
|
printf("%s: Radio name contains illegal character\n",
|
1996-10-11 02:59:41 +04:00
|
|
|
if_name);
|
1996-06-26 10:04:20 +04:00
|
|
|
}
|
|
|
|
else if (!strncmp(msg, ERR_009, sizeof(ERR_009)-1))
|
1996-08-02 06:53:39 +04:00
|
|
|
RecvErr("radio error message:", strip_info);
|
|
|
|
else {
|
|
|
|
addlog("failed to parse ]%3s[\n", msg);
|
|
|
|
RecvErr("unparsed radio error message:", strip_info);
|
1996-05-19 20:34:36 +04:00
|
|
|
}
|
|
|
|
}
|