pmap_kernel() -> kernel_pmap; from Pace Willison
[unix-history] / usr / src / sys / i386 / isa / if_apx.c
CommitLineData
b852041a
KS
1/*
2 * Copyright (c) 1982, 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
5d5451ff 7 * @(#)if_apx.c 7.9 (Berkeley) %G%
b852041a
KS
8 */
9
10/*
11 * Driver for SGS-THOMSON MK5025 based Link level controller.
12 * The chip will do LAPB in hardware, although this driver only
13 * attempts to use it for HDLC framing.
14 *
15 * Driver written by Keith Sklower, based on lance AMD7990
16 * driver by Van Jacobsen, and information graciously supplied
17 * by the ADAX corporation of Berkeley, CA.
18 */
19
20#include "apx.h"
21#if NAPX > 0
22
23#include "param.h"
24#include "mbuf.h"
25#include "socket.h"
26#include "ioctl.h"
27#include "errno.h"
28#include "syslog.h"
29
30#include "net/if.h"
31#include "net/netisr.h"
90e5f293 32#include "net/if_types.h"
673c2aae 33#ifdef CCITT
b852041a 34#include "netccitt/x25.h"
673c2aae
KS
35int x25_rtrequest(), x25_ifoutput();
36#endif
b852041a 37
90e5f293 38#include "if_apxreg.h"
b852041a
KS
39
40int apxprobe(), apxattach(), apxstart(), apx_uprim(), apx_meminit();
7726cddb 41int apxinit(), apxoutput(), apxioctl(), apxreset(), apxdebug = 0;
673c2aae 42void apx_ifattach(), apxtest(), apxinput(), apxintr(), apxtint(), apxrint();
b852041a
KS
43
44struct apx_softc {
45 struct ifnet apx_if;
673c2aae 46 caddr_t apx_device; /* e.g. isa_device, vme_device, etc. */
b852041a
KS
47 struct apc_reg *apx_reg; /* control regs for both subunits */
48 struct apc_mem *apx_hmem; /* Host addr for shared memory */
49 struct apc_mem *apx_dmem; /* Device (chip) addr for shared mem */
50 struct sgcp *apx_sgcp; /* IO control port for this subunit */
673c2aae
KS
51 int apx_flags; /* Flags specific to this driver */
52#define APXF_CHIPHERE 0x01 /* mk5025 present */
b852041a
KS
53 int apx_rxnum; /* Last receiver dx we looked at */
54 int apx_txnum; /* Last tranmistter dx we stomped on */
55 int apx_txcnt; /* Number of packets queued for tx*/
4234d067 56 u_int apx_msize;
01af915f 57 struct sgae apx_csr23; /* 24 bit init addr, as seen by chip */
673c2aae
KS
58 u_short apx_csr4; /* byte gender, set in mach dep code */
59 struct apc_modes apx_modes; /* Parameters, as amended by ioctls */
60} apx_softc[2 * NAPX];
b852041a
KS
61
62struct apxstat {
01af915f
KS
63 int rxnull; /* no rx bufs ready this interrupt */
64 int rxnrdy; /* expected rx buf not ready */
65 int rx2big; /* expected rx buf not ready */
66 int txnull;
67 int pint; /* new primitive available interrupt */
68 int rint; /* receive interrupts */
69 int tint; /* transmit interrupts */
70 int anyint; /* note all interrupts */
71 int queued; /* got through apxinput */
72 int nxpctd; /* received while if was down */
4234d067 73 int rstfld; /* reset didn't work */
90e5f293 74} apxstat;
b852041a
KS
75
76/* default operating paramters for devices */
77struct apc_modes apx_default_modes = {
78 { 1, /* apm_sgob.lsaddr; */
79 3, /* apm_sgob.rsaddr; */
80 -SGMTU, /* apm_sgob.n1; */
81 ((-10)<<8), /* apm_sgob.n2_scale; */
82 -1250, /* apm_sgob.t1; */
83 -10000, /* apm_sgob.t3; */
84 -80, /* apm_sgob.tp; */
85 },
86 2, /* apm_txwin; */
01af915f
KS
87 1, /* apm_apxmode: RS_232 connector and modem clock; */
88 0, /* apm_apxaltmode: enable dtr, disable X.21 connector; */
b852041a
KS
89 IFT_X25, /* apm_iftype; */
90};
91
92/* Begin bus & endian dependence */
93
90e5f293 94#include "isa_device.h"
b852041a
KS
95
96struct isa_driver apxdriver = {
97 apxprobe, apxattach, "apx",
98};
99
100#define SG_RCSR(apx, csrnum) \
90e5f293
KS
101 (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \
102 inw(&(apx->apx_sgcp->sgcp_rdp)))
b852041a
KS
103
104#define SG_WCSR(apx, csrnum, data) \
90e5f293 105 (outw(&(apx->apx_sgcp->sgcp_rap), csrnum << 1), \
b852041a
KS
106 outw(&(apx->apx_sgcp->sgcp_rdp), data))
107
108#define APX_RCSR(apx, csrname) inb(&(apx->apx_reg->csrname))
109#define APX_WCSR(apx, csrname, data) outb(&(apx->apx_reg->csrname), data)
110
111#define TIMO 10000 /* used in apx_uprim */
112
113apxprobe(id)
114 register struct isa_device *id;
115{
4234d067 116 int moffset = 0, subunit, unit = id->id_unit << 1;
90e5f293 117 struct apc_reg *reg = (struct apc_reg *)id->id_iobase;
b852041a
KS
118 register struct apx_softc *apx = apx_softc + unit;
119
04edb38b 120 for (subunit = 0; subunit < 2; subunit++) {
4234d067 121 apx->apx_msize = id->id_msize >> 1;
b852041a 122 apx->apx_hmem = (struct apc_mem *) (id->id_maddr + moffset);
4234d067 123 apx->apx_dmem = (struct apc_mem *) moffset;
7726cddb 124 apx->apx_device = (caddr_t) id;
b852041a 125 apx->apx_reg = reg;
673c2aae
KS
126 apx->apx_sgcp = reg->axr_sgcp + subunit;
127 apx->apx_csr4 = 0x0210; /* no byte swapping for PC-AT */
128 apx->apx_modes = apx_default_modes;
129 apx->apx_if.if_unit = unit++;
4234d067 130 moffset = apx->apx_msize;
5d5451ff 131 apxtest(apx++);
b852041a
KS
132 }
133 return 1;
134}
135
136apxattach(id)
04edb38b 137 struct isa_device *id;
b852041a 138{
04edb38b 139 register struct apx_softc *apx = apx_softc + (id->id_unit << 1);
b852041a 140
04edb38b
KS
141 apx_ifattach(&((apx++)->apx_if));
142 apx_ifattach(&(apx->apx_if));
673c2aae 143 return 0;
b852041a 144}
b852041a
KS
145/* End bus & endian dependence */
146
147/*
148 * Interface exists: make available by filling in network interface
149 * record. System will initialize the interface when it is ready
150 * to accept packets.
151 */
90e5f293 152void
04edb38b
KS
153apx_ifattach(ifp)
154 register struct ifnet *ifp;
b852041a 155{
b852041a
KS
156 /*
157 * Initialize ifnet structure
158 */
673c2aae
KS
159 ifp->if_name = "apc";
160 ifp->if_mtu = SGMTU;
161 ifp->if_init = apxinit;
162 ifp->if_output = apxoutput;
163 ifp->if_start = apxstart;
164 ifp->if_ioctl = apxioctl;
165 ifp->if_reset = apxreset;
166 ifp->if_type = apx_default_modes.apm_iftype;
167 ifp->if_hdrlen = 5;
168 ifp->if_addrlen = 8;
b852041a
KS
169 if_attach(ifp);
170}
171/*
172 * Initialization of interface
173 */
174apxinit(unit)
175 int unit;
176{
177 struct ifnet *ifp = &apx_softc[unit].apx_if;
178 int s = splimp();
179
180 ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
181 if (apxreset(unit) && (ifp->if_flags & IFF_UP)) {
182 ifp->if_flags |= IFF_RUNNING;
183 (void)apxstart(ifp);
184 }
185 splx(s);
186 return 0;
187}
188
fdbd99c6
KS
189apxctr(apx)
190 register struct apx_softc *apx;
191{
673c2aae 192 APX_WCSR(apx, axr_ccr, 0xB0); /* select ctr 2, write lsb+msb, mode 0 */
fdbd99c6
KS
193 APX_WCSR(apx, axr_cnt2, 0x1);
194 APX_WCSR(apx, axr_cnt2, 0x0);
195 DELAY(50);
673c2aae
KS
196 APX_WCSR(apx, axr_ccr, 0xE8); /* latch status, ctr 2; */
197 return (APX_RCSR(apx, axr_cnt2));
198}
199
200void
201apxtest(apx)
202 register struct apx_softc *apx;
203{
204 int i = 0;
205
206 if ((apx->apx_if.if_unit & 1) == 0 && (i = apxctr(apx)) == 0)
207 apxerror(apx, "no response from timer chip", 0);
208 if (SG_RCSR(apx, 1) & 0x8000)
209 SG_WCSR(apx, 1, 0x8040);
210 SG_WCSR(apx, 4, apx->apx_csr4);
673c2aae
KS
211 SG_WCSR(apx, 5, 0x08); /* Set DTR mode in SGS thompson chip */
212 if (((i = SG_RCSR(apx, 5)) & 0xff08) != 0x08)
213 apxerror(apx, "no mk5025, csr5 high bits are", i);
214 else
215 apx->apx_flags |= APXF_CHIPHERE;
01af915f 216 (void) apx_uprim(apx, SG_STOP, "stop after probing");
fdbd99c6
KS
217}
218
b852041a
KS
219apxreset(unit)
220 int unit;
221{
222 register struct apx_softc *apx = &apx_softc[unit ^ 1];
223 u_char apm_apxmode = 0, apm_apxaltmode = 0;
224#define MODE(m) (m |= apx->apx_modes.m << ((apx->apx_if.if_unit & 1) ? 1 : 0))
225
226 MODE(apm_apxmode);
227 MODE(apm_apxaltmode);
228 apx = apx_softc + unit;
229 MODE(apm_apxmode);
230 MODE(apm_apxaltmode);
231 APX_WCSR(apx, axr_mode, apm_apxmode);
232 APX_WCSR(apx, axr_altmode, apm_apxaltmode);
01af915f
KS
233 (void) apxctr(apx);
234 (void) apx_uprim(apx, SG_STOP, "stop to reset");
235 if ((apx->apx_if.if_flags & IFF_UP) == 0)
b852041a 236 return 0;
01af915f 237 apx_meminit(apx->apx_hmem, apx);
b852041a 238 SG_WCSR(apx, 4, apx->apx_csr4);
01af915f
KS
239 SG_WCSR(apx, 2, apx->apx_csr23.f_hi);
240 SG_WCSR(apx, 3, apx->apx_csr23.lo);
90e5f293 241 if (apx_uprim(apx, SG_INIT, "init request") ||
b852041a 242 apx_uprim(apx, SG_STAT, "status request") ||
7726cddb 243 apx_uprim(apx, SG_TRANS, "transparent mode"))
b852041a
KS
244 return 0;
245 SG_WCSR(apx, 0, SG_INEA);
90e5f293 246 return 1;
b852041a
KS
247}
248
249apx_uprim(apx, request, ident)
b852041a 250 register struct apx_softc *apx;
04edb38b 251 char *ident;
b852041a
KS
252{
253 register int timo = 0;
04edb38b 254 int reply;
b852041a 255
04edb38b
KS
256 if ((apx->apx_flags & APXF_CHIPHERE) == 0)
257 return 1; /* maybe even should panic . . . */
258 if ((reply = SG_RCSR(apx, 1)) & 0x8040)
673c2aae 259 SG_WCSR(apx, 1, 0x8040); /* Magic! */
7726cddb 260 if (request == SG_STOP && (SG_RCSR(apx, 0) & SG_STOPPED))
4234d067 261 return 0;
b852041a
KS
262 SG_WCSR(apx, 1, request | SG_UAV);
263 do {
7726cddb 264 reply = SG_RCSR(apx, 1);
01af915f 265 if (timo++ >= TIMO || (reply & 0x8000)) {
01af915f 266 apxerror(apx, ident, reply);
01af915f 267 return 1;
b852041a
KS
268 }
269 } while (reply & SG_UAV);
270 return 0;
271}
272
273apx_meminit(apc, apx)
274 register struct apc_mem *apc;
275 struct apx_softc *apx;
276{
277 register struct apc_mem *apcbase = apx->apx_dmem;
278 register int i;
90e5f293
KS
279#define LOWADDR(e) (((u_long)&(apcbase->e)) & 0xffff)
280#define HIADDR(e) ((((u_long)&(apcbase->e)) >> 16) & 0xff)
01af915f
KS
281#define SET_SGAE(d, f, a) {(d).lo = LOWADDR(a); (d).f_hi = (f) | HIADDR(a);}
282#define SET_SGDX(d, f, a, b) \
283 {SET_SGAE((d).sgdx_ae, f, a); (d).sgdx_mcnt = (d).sgdx_bcnt = (b);}
b852041a 284
01af915f 285 apx->apx_txnum = apx->apx_rxnum = apx->apx_txcnt = 0;
7726cddb
KS
286 bzero((caddr_t)apc, ((caddr_t)(&apc->apc_rxmd[0])) - (caddr_t)apc);
287 apc->apc_mode = 0x0108; /* 2 flag spacing, leave addr & ctl, do CRC16 */
b852041a 288 apc->apc_sgop = apx->apx_modes.apm_sgop;
01af915f
KS
289 SET_SGAE(apx->apx_csr23, SG_UIE | SG_PROM, apc_mode);
290 SET_SGAE(apc->apc_rxdd, SG_RLEN, apc_rxmd[0]);
4234d067
KS
291 i = SG_TLEN | ((apx->apx_modes.apm_txwin)<< 8);
292 SET_SGAE(apc->apc_txdd, i, apc_txmd[0]);
01af915f
KS
293 SET_SGAE(apc->apc_stdd, 0, apc_sgsb);
294 SET_SGDX(apc->apc_rxtid, SG_OWN, apc_rxidbuf[0], -SGMTU);
295 SET_SGDX(apc->apc_txtid, 0, apc_txidbuf[0], 0);
b852041a 296 for (i = 0; i < SGRBUF; i++)
01af915f 297 SET_SGDX(apc->apc_rxmd[i], SG_OWN, apc_rbuf[i][0], -SGMTU)
b852041a 298 for (i = 0; i < SGTBUF; i++)
4234d067 299 SET_SGDX(apc->apc_txmd[i], 0, apc_tbuf[i][0], 0)
b852041a
KS
300}
301
302/*
303 * Start output on interface. Get another datagram to send
304 * off of the interface queue, and copy it to the interface
305 * before starting the output.
306 */
307apxstart(ifp)
308 struct ifnet *ifp;
309{
310 register struct apx_softc *apx = &apx_softc[ifp->if_unit];
311 register struct sgdx *dx;
90e5f293 312 struct apc_mem *apc = apx->apx_hmem;
b852041a
KS
313 struct mbuf *m;
314 int len;
315
316 if ((ifp->if_flags & IFF_RUNNING) == 0)
317 return (0);
318 do {
90e5f293 319 dx = apc->apc_txmd + apx->apx_txnum;
b852041a
KS
320 if (dx->sgdx_flags & SG_OWN)
321 return (0);
322 IF_DEQUEUE(&ifp->if_snd, m);
323 if (m == 0)
324 return (0);
325 len = min(m->m_pkthdr.len, SGMTU);
90e5f293 326 m_copydata(m, 0, len, apc->apc_tbuf[apx->apx_txnum]);
b852041a 327 dx->sgdx_mcnt = -len;
01af915f
KS
328 dx->sgdx_flags = (SG_OWN|SG_TUI|SG_SLF|SG_ELF) |
329 (0xff & dx->sgdx_flags);
b852041a 330 SG_WCSR(apx, 0, SG_INEA | SG_TDMD);
4234d067 331 DELAY(20);
b852041a
KS
332 if (++apx->apx_txnum >= SGTBUF)
333 apx->apx_txnum = 0;
334 } while (++apx->apx_txcnt < SGTBUF);
04edb38b 335 apx->apx_txcnt = SGTBUF; /* in case txcnt > SGTBUF by mistake */
b852041a
KS
336 ifp->if_flags |= IFF_OACTIVE;
337 return (0);
338}
339
90e5f293 340void
b852041a
KS
341apxintr()
342{
673c2aae 343 register struct apx_softc *apx;
b852041a
KS
344 int reply;
345
01af915f 346 apxstat.anyint++;
673c2aae
KS
347 for (apx = apx_softc + NAPX + NAPX; --apx >= apx_softc;) {
348 if (apx->apx_flags & APXF_CHIPHERE)
b852041a 349 /* Try to turn off interrupt cause */
7726cddb 350 while ((reply = SG_RCSR(apx, 0)) & 0xff) {
b852041a
KS
351 SG_WCSR(apx, 0, SG_INEA | 0xfe);
352 if (reply & (SG_MERR|SG_TUR|SG_ROR)) {
353 apxerror(apx, "mem, rx, or tx error", reply);
354 apxinit(apx->apx_if.if_unit);
355 break;
356 }
357 if (reply & SG_RINT)
358 apxrint(apx);
359 if (reply & SG_TINT)
360 apxtint(apx);
361 if (reply & SG_PINT)
362 apxstat.pint++;
363 }
673c2aae 364 }
b852041a
KS
365}
366
90e5f293 367void
b852041a
KS
368apxtint(apx)
369 register struct apx_softc *apx;
370{
90e5f293 371 register struct apc_mem *apc = apx->apx_hmem;
b852041a
KS
372 int i, loopcount = 0;
373
01af915f 374 apxstat.tint++;
b852041a
KS
375 do {
376 if ((i = apx->apx_txnum - apx->apx_txcnt) < 0)
377 i += SGTBUF;
378 if (apc->apc_txmd[i].sgdx_flags & SG_OWN) {
379 if (loopcount)
380 break;
01af915f 381 apxstat.txnull++;
b852041a
KS
382 return;
383 }
384 loopcount++;
385 apx->apx_if.if_flags &= ~IFF_OACTIVE;
386 } while (--apx->apx_txcnt > 0);
387 apxstart(&apx->apx_if);
388}
389
673c2aae 390void
b852041a
KS
391apxrint(apx)
392 register struct apx_softc *apx;
393{
90e5f293 394 register struct apc_mem *apc = apx->apx_hmem;
b852041a 395 register struct sgdx *dx = apc->apc_rxmd + apx->apx_rxnum;
01af915f 396 int i = 0;
b852041a
KS
397#define SGNEXTRXMD \
398dx = ++apx->apx_rxnum == SGRBUF ? &apc->apc_rxmd[apx->apx_rxnum = 0] : dx + 1;
399
01af915f 400 apxstat.rint++;
b852041a
KS
401 /*
402 * Out of sync with hardware, should never happen?
403 */
01af915f
KS
404 while (dx->sgdx_flags & SG_OWN) {
405 apxstat.rxnrdy++;
406 if (++i == SGRBUF) {
407 apxstat.rxnull++;
408 return;
409 }
410 SGNEXTRXMD;
b852041a
KS
411 }
412 /*
413 * Process all buffers with valid data
414 */
415 while ((dx->sgdx_flags & SG_OWN) == 0) {
416 if ((dx->sgdx_flags & (SG_SLF|SG_ELF)) != (SG_SLF|SG_ELF)) {
417 /*
01af915f
KS
418 * Find the end of the packet so we synch up.
419 * We throw the data away.
b852041a 420 */
90e5f293 421 apxerror(apx, "chained buffer", dx->sgdx_flags);
b852041a 422 do {
01af915f 423 apxstat.rx2big++;
b852041a
KS
424 dx->sgdx_bcnt = 0;
425 dx->sgdx_flags = SG_OWN | (0xff&dx->sgdx_flags);
426 SGNEXTRXMD;
427 } while (!(dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)));
428 /*
429 * If search terminated without successful completion
430 * we reset the hardware (conservative).
431 */
432 if ((dx->sgdx_flags & (SG_OWN|SG_SLF|SG_ELF)) !=
90e5f293 433 SG_ELF) {
b852041a
KS
434 apxreset(apx->apx_if.if_unit);
435 return;
436 }
437 } else
438 apxinput(&apx->apx_if, apc->apc_rbuf[apx->apx_rxnum],
01af915f 439 -dx->sgdx_mcnt);
b852041a
KS
440 dx->sgdx_bcnt = 0;
441 dx->sgdx_flags = SG_OWN | (0xff & dx->sgdx_flags);
442 SGNEXTRXMD;
443 }
444}
445
90e5f293 446void
b852041a 447apxinput(ifp, buffer, len)
04edb38b
KS
448 register struct ifnet *ifp;
449 caddr_t buffer;
b852041a 450{
04edb38b 451 extern struct ifqueue hdintrq, ipintrq;
b852041a 452 register struct ifqueue *inq;
04edb38b 453 register u_char *cp = (u_char *)buffer;
fdbd99c6 454 struct mbuf *m, *m_devget();
b852041a
KS
455 int isr;
456
457 ifp->if_ipackets++;
01af915f
KS
458 if ((ifp->if_flags & IFF_UP) == 0) {
459 apxstat.nxpctd++;
460 return;
461 }
b852041a
KS
462 if (cp[0] == 0xff && cp[1] == 0x3) {
463 /* This is a UI HDLC Packet, so we'll assume PPP
464 protocol. for now, IP only. */
465 buffer += 4;
466 len -= 4;
467 inq = &ipintrq;
468 isr = NETISR_IP;
469 } else {
04edb38b 470#ifdef CCITT
b852041a
KS
471 inq = &hdintrq;
472 isr = NETISR_CCITT;
473 }
04edb38b
KS
474 if (len <= 0) {
475#endif
b852041a 476 return;
04edb38b 477 }
fdbd99c6 478 m = m_devget(buffer, len, 0, ifp, (void (*)())0);
b852041a
KS
479 if (m == 0)
480 return;
b852041a
KS
481 if(IF_QFULL(inq)) {
482 IF_DROP(inq);
483 m_freem(m);
484 } else {
01af915f 485 apxstat.queued++;
b852041a
KS
486 IF_ENQUEUE(inq, m);
487 schednetisr(isr);
488 }
489}
490
b852041a
KS
491/*
492 * Process an ioctl request.
493 */
494apxioctl(ifp, cmd, data)
495 register struct ifnet *ifp;
496 int cmd;
497 caddr_t data;
498{
499 register struct ifaddr *ifa = (struct ifaddr *)data;
500 int s = splimp(), error = 0;
501 struct apx_softc *apx = &apx_softc[ifp->if_unit];
502
503 switch (cmd) {
673c2aae
KS
504
505 case SIOCSIFADDR:
506#ifdef CCITT
7726cddb 507 ifa->ifa_rtrequest = x25_rtrequest;
673c2aae
KS
508 break;
509
b852041a 510 case SIOCSIFCONF_X25:
673c2aae 511 ifp->if_output = x25_ifoutput;
b852041a
KS
512 ifp->if_flags |= IFF_UP;
513 error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr);
514 if (error == 0)
515 apxinit(ifp->if_unit);
673c2aae 516#endif
b852041a
KS
517 break;
518
519 case SIOCSIFFLAGS:
520 if (((ifp->if_flags & IFF_UP) == 0 &&
521 (ifp->if_flags & IFF_RUNNING)) ||
522 (ifp->if_flags & IFF_UP) &&
523 (ifp->if_flags & IFF_RUNNING) == 0)
524 apxinit(ifp->if_unit);
525 break;
526
527 case SIOCSIFMODE:
528 if ((ifp->if_flags & IFF_UP) == 0)
90e5f293 529 apx->apx_modes = *(struct apc_modes *)data;
b852041a
KS
530 else
531 default:
532 error = EINVAL;
533
534 }
535 splx(s);
536 return (error);
537}
538
539apxerror(apx, msg, data)
540 register struct apx_softc *apx;
541 char *msg;
542{
543 log(LOG_WARNING, "apc%d: %s, stat=0x%x\n",
544 apx->apx_if.if_unit, msg, data);
545}
7726cddb 546
673c2aae
KS
547/*
548 * For debugging loopback activity.
549 */
673c2aae
KS
550apxoutput(ifp, m, dst, rt)
551register struct ifnet *ifp;
552register struct mbuf *m;
553struct sockaddr *dst;
554struct rtentry *rt;
555{
7726cddb
KS
556 int s = splimp(), error = 0;
557 static char pppheader[4] = { -1, 3, 0, 0x21 };
673c2aae
KS
558 /*
559 * Queue message on interface, and start output if interface
560 * not yet active.
561 */
7726cddb 562 ifp->if_opackets++;
673c2aae
KS
563 M_PREPEND(m, sizeof pppheader, M_DONTWAIT);
564 if (m == 0) {
565 splx(s);
566 return ENOBUFS;
567 }
568 bcopy(pppheader, mtod(m, caddr_t), sizeof pppheader);
569 if (IF_QFULL(&ifp->if_snd)) {
570 IF_DROP(&ifp->if_snd);
673c2aae
KS
571 m_freem(m);
572 error = ENOBUFS;
573 } else {
574 IF_ENQUEUE(&ifp->if_snd, m);
575 if ((ifp->if_flags & IFF_OACTIVE) == 0)
576 (*ifp->if_start)(ifp);
577 }
578 splx(s);
579 return (error);
580}
b852041a 581#endif /* NAPX */