if_ppp.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. /*
  2. * if_ppp.c - a network interface connected to a STREAMS module.
  3. *
  4. * Copyright (c) 1994 Paul Mackerras. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. *
  18. * 3. The name(s) of the authors of this software must not be used to
  19. * endorse or promote products derived from this software without
  20. * prior written permission.
  21. *
  22. * 4. Redistributions of any form whatsoever must retain the following
  23. * acknowledgment:
  24. * "This product includes software developed by Paul Mackerras
  25. * <paulus@samba.org>".
  26. *
  27. * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
  28. * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  29. * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
  30. * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  31. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  32. * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  33. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * $Id: if_ppp.c,v 1.18 2002/12/06 09:49:15 paulus Exp $
  36. */
  37. /*
  38. * This file is used under SunOS 4 and Digital UNIX.
  39. *
  40. * This file provides the glue between PPP and IP.
  41. */
  42. #define INET 1
  43. #include <sys/types.h>
  44. #include <sys/param.h>
  45. #include <sys/errno.h>
  46. #include <sys/mbuf.h>
  47. #include <sys/socket.h>
  48. #include <net/if.h>
  49. #include <net/netisr.h>
  50. #include <net/ppp_defs.h>
  51. #include <net/pppio.h>
  52. #include <netinet/in.h>
  53. #include <netinet/in_var.h>
  54. #ifdef __osf__
  55. #include <sys/ioctl.h>
  56. #include <net/if_types.h>
  57. #else
  58. #include <sys/sockio.h>
  59. #endif
  60. #include "ppp_mod.h"
  61. #include <sys/stream.h>
  62. #ifdef SNIT_SUPPORT
  63. #include <sys/time.h>
  64. #include <net/nit_if.h>
  65. #include <netinet/if_ether.h>
  66. #endif
  67. #ifdef __osf__
  68. #define SIOCSIFMTU SIOCSIPMTU
  69. #define SIOCGIFMTU SIOCRIPMTU
  70. #define IFA_ADDR(ifa) (*(ifa)->ifa_addr)
  71. #else
  72. #define IFA_ADDR(ifa) ((ifa)->ifa_addr)
  73. #endif
  74. #define ifr_mtu ifr_metric
  75. static int if_ppp_open __P((queue_t *, int, int, int));
  76. static int if_ppp_close __P((queue_t *, int));
  77. static int if_ppp_wput __P((queue_t *, mblk_t *));
  78. static int if_ppp_rput __P((queue_t *, mblk_t *));
  79. #define PPP_IF_ID 0x8021
  80. static struct module_info minfo = {
  81. PPP_IF_ID, "if_ppp", 0, INFPSZ, 4096, 128
  82. };
  83. static struct qinit rinit = {
  84. if_ppp_rput, NULL, if_ppp_open, if_ppp_close, NULL, &minfo, NULL
  85. };
  86. static struct qinit winit = {
  87. if_ppp_wput, NULL, NULL, NULL, NULL, &minfo, NULL
  88. };
  89. struct streamtab if_pppinfo = {
  90. &rinit, &winit, NULL, NULL
  91. };
  92. typedef struct if_ppp_state {
  93. int unit;
  94. queue_t *q;
  95. int flags;
  96. } if_ppp_t;
  97. /* Values for flags */
  98. #define DBGLOG 1
  99. static int if_ppp_count; /* Number of currently-active streams */
  100. static int ppp_nalloc; /* Number of elements of ifs and states */
  101. static struct ifnet **ifs; /* Array of pointers to interface structs */
  102. static if_ppp_t **states; /* Array of pointers to state structs */
  103. static int if_ppp_output __P((struct ifnet *, struct mbuf *,
  104. struct sockaddr *));
  105. static int if_ppp_ioctl __P((struct ifnet *, u_int, caddr_t));
  106. static struct mbuf *make_mbufs __P((mblk_t *, int));
  107. static mblk_t *make_message __P((struct mbuf *, int));
  108. #ifdef SNIT_SUPPORT
  109. /* Fake ether header for SNIT */
  110. static struct ether_header snit_ehdr = {{0}, {0}, ETHERTYPE_IP};
  111. #endif
  112. #ifndef __osf__
  113. static void ppp_if_detach __P((struct ifnet *));
  114. /*
  115. * Detach all the interfaces before unloading.
  116. * Not sure this works.
  117. */
  118. int
  119. if_ppp_unload()
  120. {
  121. int i;
  122. if (if_ppp_count > 0)
  123. return EBUSY;
  124. for (i = 0; i < ppp_nalloc; ++i)
  125. if (ifs[i] != 0)
  126. ppp_if_detach(ifs[i]);
  127. if (ifs) {
  128. FREE(ifs, ppp_nalloc * sizeof (struct ifnet *));
  129. FREE(states, ppp_nalloc * sizeof (struct if_ppp_t *));
  130. }
  131. ppp_nalloc = 0;
  132. return 0;
  133. }
  134. #endif /* __osf__ */
  135. /*
  136. * STREAMS module entry points.
  137. */
  138. static int
  139. if_ppp_open(q, dev, flag, sflag)
  140. queue_t *q;
  141. int dev;
  142. int flag, sflag;
  143. {
  144. if_ppp_t *sp;
  145. if (q->q_ptr == 0) {
  146. sp = (if_ppp_t *) ALLOC_SLEEP(sizeof (if_ppp_t));
  147. if (sp == 0)
  148. return OPENFAIL;
  149. bzero(sp, sizeof (if_ppp_t));
  150. q->q_ptr = (caddr_t) sp;
  151. WR(q)->q_ptr = (caddr_t) sp;
  152. sp->unit = -1; /* no interface unit attached at present */
  153. sp->q = WR(q);
  154. sp->flags = 0;
  155. ++if_ppp_count;
  156. }
  157. return 0;
  158. }
  159. static int
  160. if_ppp_close(q, flag)
  161. queue_t *q;
  162. int flag;
  163. {
  164. if_ppp_t *sp;
  165. struct ifnet *ifp;
  166. sp = (if_ppp_t *) q->q_ptr;
  167. if (sp != 0) {
  168. if (sp->flags & DBGLOG)
  169. printf("if_ppp closed, q=%x sp=%x\n", q, sp);
  170. if (sp->unit >= 0) {
  171. if (sp->unit < ppp_nalloc) {
  172. states[sp->unit] = 0;
  173. ifp = ifs[sp->unit];
  174. if (ifp != 0)
  175. ifp->if_flags &= ~(IFF_UP | IFF_RUNNING);
  176. #ifdef DEBUG
  177. } else {
  178. printf("if_ppp: unit %d nonexistent!\n", sp->unit);
  179. #endif
  180. }
  181. }
  182. FREE(sp, sizeof (if_ppp_t));
  183. --if_ppp_count;
  184. }
  185. return 0;
  186. }
  187. static int
  188. if_ppp_wput(q, mp)
  189. queue_t *q;
  190. mblk_t *mp;
  191. {
  192. if_ppp_t *sp;
  193. struct iocblk *iop;
  194. int error, unit;
  195. struct ifnet *ifp;
  196. sp = (if_ppp_t *) q->q_ptr;
  197. switch (mp->b_datap->db_type) {
  198. case M_DATA:
  199. /*
  200. * Now why would we be getting data coming in here??
  201. */
  202. if (sp->flags & DBGLOG)
  203. printf("if_ppp: got M_DATA len=%d\n", msgdsize(mp));
  204. freemsg(mp);
  205. break;
  206. case M_IOCTL:
  207. iop = (struct iocblk *) mp->b_rptr;
  208. error = EINVAL;
  209. if (sp->flags & DBGLOG)
  210. printf("if_ppp: got ioctl cmd=%x count=%d\n",
  211. iop->ioc_cmd, iop->ioc_count);
  212. switch (iop->ioc_cmd) {
  213. case PPPIO_NEWPPA: /* well almost */
  214. if (iop->ioc_count != sizeof(int) || sp->unit >= 0)
  215. break;
  216. if ((error = NOTSUSER()) != 0)
  217. break;
  218. unit = *(int *)mp->b_cont->b_rptr;
  219. /* Check that this unit isn't already in use */
  220. if (unit < ppp_nalloc && states[unit] != 0) {
  221. error = EADDRINUSE;
  222. break;
  223. }
  224. /* Extend ifs and states arrays if necessary. */
  225. error = ENOSR;
  226. if (unit >= ppp_nalloc) {
  227. int newn;
  228. struct ifnet **newifs;
  229. if_ppp_t **newstates;
  230. newn = unit + 4;
  231. if (sp->flags & DBGLOG)
  232. printf("if_ppp: extending ifs to %d\n", newn);
  233. newifs = (struct ifnet **)
  234. ALLOC_NOSLEEP(newn * sizeof (struct ifnet *));
  235. if (newifs == 0)
  236. break;
  237. bzero(newifs, newn * sizeof (struct ifnet *));
  238. newstates = (if_ppp_t **)
  239. ALLOC_NOSLEEP(newn * sizeof (struct if_ppp_t *));
  240. if (newstates == 0) {
  241. FREE(newifs, newn * sizeof (struct ifnet *));
  242. break;
  243. }
  244. bzero(newstates, newn * sizeof (struct if_ppp_t *));
  245. bcopy(ifs, newifs, ppp_nalloc * sizeof(struct ifnet *));
  246. bcopy(states, newstates, ppp_nalloc * sizeof(if_ppp_t *));
  247. if (ifs) {
  248. FREE(ifs, ppp_nalloc * sizeof(struct ifnet *));
  249. FREE(states, ppp_nalloc * sizeof(if_ppp_t *));
  250. }
  251. ifs = newifs;
  252. states = newstates;
  253. ppp_nalloc = newn;
  254. }
  255. /* Allocate a new ifnet struct if necessary. */
  256. ifp = ifs[unit];
  257. if (ifp == 0) {
  258. ifp = (struct ifnet *) ALLOC_NOSLEEP(sizeof (struct ifnet));
  259. if (ifp == 0)
  260. break;
  261. bzero(ifp, sizeof (struct ifnet));
  262. ifs[unit] = ifp;
  263. ifp->if_name = "ppp";
  264. ifp->if_unit = unit;
  265. ifp->if_mtu = PPP_MTU;
  266. ifp->if_flags = IFF_POINTOPOINT | IFF_RUNNING;
  267. #ifndef __osf__
  268. #ifdef IFF_MULTICAST
  269. ifp->if_flags |= IFF_MULTICAST;
  270. #endif
  271. #endif /* __osf__ */
  272. ifp->if_output = if_ppp_output;
  273. #ifdef __osf__
  274. ifp->if_version = "Point-to-Point Protocol, version 2.3.11";
  275. ifp->if_mediamtu = PPP_MTU;
  276. ifp->if_type = IFT_PPP;
  277. ifp->if_hdrlen = PPP_HDRLEN;
  278. ifp->if_addrlen = 0;
  279. ifp->if_flags |= IFF_NOARP | IFF_SIMPLEX | IFF_NOTRAILERS;
  280. #ifdef IFF_VAR_MTU
  281. ifp->if_flags |= IFF_VAR_MTU;
  282. #endif
  283. #ifdef NETMASTERCPU
  284. ifp->if_affinity = NETMASTERCPU;
  285. #endif
  286. #endif
  287. ifp->if_ioctl = if_ppp_ioctl;
  288. ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  289. if_attach(ifp);
  290. if (sp->flags & DBGLOG)
  291. printf("if_ppp: created unit %d\n", unit);
  292. } else {
  293. ifp->if_mtu = PPP_MTU;
  294. ifp->if_flags |= IFF_RUNNING;
  295. }
  296. states[unit] = sp;
  297. sp->unit = unit;
  298. error = 0;
  299. iop->ioc_count = 0;
  300. if (sp->flags & DBGLOG)
  301. printf("if_ppp: attached unit %d, sp=%x q=%x\n", unit,
  302. sp, sp->q);
  303. break;
  304. case PPPIO_DEBUG:
  305. error = -1;
  306. if (iop->ioc_count == sizeof(int)) {
  307. if (*(int *)mp->b_cont->b_rptr == PPPDBG_LOG + PPPDBG_IF) {
  308. printf("if_ppp: debug log enabled, q=%x sp=%x\n", q, sp);
  309. sp->flags |= DBGLOG;
  310. error = 0;
  311. iop->ioc_count = 0;
  312. }
  313. }
  314. break;
  315. default:
  316. error = -1;
  317. break;
  318. }
  319. if (sp->flags & DBGLOG)
  320. printf("if_ppp: ioctl result %d\n", error);
  321. if (error < 0)
  322. putnext(q, mp);
  323. else if (error == 0) {
  324. mp->b_datap->db_type = M_IOCACK;
  325. qreply(q, mp);
  326. } else {
  327. mp->b_datap->db_type = M_IOCNAK;
  328. iop->ioc_count = 0;
  329. iop->ioc_error = error;
  330. qreply(q, mp);
  331. }
  332. break;
  333. default:
  334. putnext(q, mp);
  335. }
  336. return 0;
  337. }
  338. static int
  339. if_ppp_rput(q, mp)
  340. queue_t *q;
  341. mblk_t *mp;
  342. {
  343. if_ppp_t *sp;
  344. int proto, s;
  345. struct mbuf *mb;
  346. struct ifqueue *inq;
  347. struct ifnet *ifp;
  348. int len;
  349. sp = (if_ppp_t *) q->q_ptr;
  350. switch (mp->b_datap->db_type) {
  351. case M_DATA:
  352. /*
  353. * Convert the message into an mbuf chain
  354. * and inject it into the network code.
  355. */
  356. if (sp->flags & DBGLOG)
  357. printf("if_ppp: rput pkt len %d data %x %x %x %x %x %x %x %x\n",
  358. msgdsize(mp), mp->b_rptr[0], mp->b_rptr[1], mp->b_rptr[2],
  359. mp->b_rptr[3], mp->b_rptr[4], mp->b_rptr[5], mp->b_rptr[6],
  360. mp->b_rptr[7]);
  361. if (sp->unit < 0) {
  362. freemsg(mp);
  363. break;
  364. }
  365. if (sp->unit >= ppp_nalloc || (ifp = ifs[sp->unit]) == 0) {
  366. #ifdef DEBUG
  367. printf("if_ppp: no unit %d!\n", sp->unit);
  368. #endif
  369. freemsg(mp);
  370. break;
  371. }
  372. if ((ifp->if_flags & IFF_UP) == 0) {
  373. freemsg(mp);
  374. break;
  375. }
  376. ++ifp->if_ipackets;
  377. proto = PPP_PROTOCOL(mp->b_rptr);
  378. adjmsg(mp, PPP_HDRLEN);
  379. len = msgdsize(mp);
  380. mb = make_mbufs(mp, sizeof(struct ifnet *));
  381. freemsg(mp);
  382. if (mb == NULL) {
  383. if (sp->flags & DBGLOG)
  384. printf("if_ppp%d: make_mbufs failed\n", ifp->if_unit);
  385. ++ifp->if_ierrors;
  386. break;
  387. }
  388. #ifdef SNIT_SUPPORT
  389. if (proto == PPP_IP && (ifp->if_flags & IFF_PROMISC)) {
  390. struct nit_if nif;
  391. nif.nif_header = (caddr_t) &snit_ehdr;
  392. nif.nif_hdrlen = sizeof(snit_ehdr);
  393. nif.nif_bodylen = len;
  394. nif.nif_promisc = 0;
  395. snit_intr(ifp, mb, &nif);
  396. }
  397. #endif
  398. /*
  399. * For Digital UNIX, there's space set aside in the header mbuf
  400. * for the interface info.
  401. *
  402. * For Sun it's smuggled around via a pointer at the front of the mbuf.
  403. */
  404. #ifdef __osf__
  405. mb->m_pkthdr.rcvif = ifp;
  406. mb->m_pkthdr.len = len;
  407. #else
  408. mb->m_off -= sizeof(struct ifnet *);
  409. mb->m_len += sizeof(struct ifnet *);
  410. *mtod(mb, struct ifnet **) = ifp;
  411. #endif
  412. inq = 0;
  413. switch (proto) {
  414. case PPP_IP:
  415. inq = &ipintrq;
  416. schednetisr(NETISR_IP);
  417. }
  418. if (inq != 0) {
  419. s = splhigh();
  420. if (IF_QFULL(inq)) {
  421. IF_DROP(inq);
  422. ++ifp->if_ierrors;
  423. if (sp->flags & DBGLOG)
  424. printf("if_ppp: inq full, proto=%x\n", proto);
  425. m_freem(mb);
  426. } else {
  427. IF_ENQUEUE(inq, mb);
  428. }
  429. splx(s);
  430. } else {
  431. if (sp->flags & DBGLOG)
  432. printf("if_ppp%d: proto=%x?\n", ifp->if_unit, proto);
  433. ++ifp->if_ierrors;
  434. m_freem(mb);
  435. }
  436. break;
  437. default:
  438. putnext(q, mp);
  439. }
  440. return 0;
  441. }
  442. /*
  443. * Network code wants to output a packet.
  444. * Turn it into a STREAMS message and send it down.
  445. */
  446. static int
  447. if_ppp_output(ifp, m0, dst)
  448. struct ifnet *ifp;
  449. struct mbuf *m0;
  450. struct sockaddr *dst;
  451. {
  452. mblk_t *mp;
  453. int proto, s;
  454. if_ppp_t *sp;
  455. u_char *p;
  456. if ((ifp->if_flags & IFF_UP) == 0) {
  457. m_freem(m0);
  458. return ENETDOWN;
  459. }
  460. if ((unsigned)ifp->if_unit >= ppp_nalloc) {
  461. #ifdef DEBUG
  462. printf("if_ppp_output: unit %d?\n", ifp->if_unit);
  463. #endif
  464. m_freem(m0);
  465. return EINVAL;
  466. }
  467. sp = states[ifp->if_unit];
  468. if (sp == 0) {
  469. #ifdef DEBUG
  470. printf("if_ppp_output: no queue?\n");
  471. #endif
  472. m_freem(m0);
  473. return ENETDOWN;
  474. }
  475. if (sp->flags & DBGLOG) {
  476. p = mtod(m0, u_char *);
  477. printf("if_ppp_output%d: af=%d data=%x %x %x %x %x %x %x %x q=%x\n",
  478. ifp->if_unit, dst->sa_family, p[0], p[1], p[2], p[3], p[4],
  479. p[5], p[6], p[7], sp->q);
  480. }
  481. switch (dst->sa_family) {
  482. case AF_INET:
  483. proto = PPP_IP;
  484. #ifdef SNIT_SUPPORT
  485. if (ifp->if_flags & IFF_PROMISC) {
  486. struct nit_if nif;
  487. struct mbuf *m;
  488. int len;
  489. for (len = 0, m = m0; m != NULL; m = m->m_next)
  490. len += m->m_len;
  491. nif.nif_header = (caddr_t) &snit_ehdr;
  492. nif.nif_hdrlen = sizeof(snit_ehdr);
  493. nif.nif_bodylen = len;
  494. nif.nif_promisc = 0;
  495. snit_intr(ifp, m0, &nif);
  496. }
  497. #endif
  498. break;
  499. default:
  500. m_freem(m0);
  501. return EAFNOSUPPORT;
  502. }
  503. ++ifp->if_opackets;
  504. mp = make_message(m0, PPP_HDRLEN);
  505. m_freem(m0);
  506. if (mp == 0) {
  507. ++ifp->if_oerrors;
  508. return ENOBUFS;
  509. }
  510. mp->b_rptr -= PPP_HDRLEN;
  511. mp->b_rptr[0] = PPP_ALLSTATIONS;
  512. mp->b_rptr[1] = PPP_UI;
  513. mp->b_rptr[2] = proto >> 8;
  514. mp->b_rptr[3] = proto;
  515. s = splstr();
  516. if (sp->flags & DBGLOG)
  517. printf("if_ppp: putnext(%x, %x), r=%x w=%x p=%x\n",
  518. sp->q, mp, mp->b_rptr, mp->b_wptr, proto);
  519. putnext(sp->q, mp);
  520. splx(s);
  521. return 0;
  522. }
  523. /*
  524. * Socket ioctl routine for ppp interfaces.
  525. */
  526. static int
  527. if_ppp_ioctl(ifp, cmd, data)
  528. struct ifnet *ifp;
  529. u_int cmd;
  530. caddr_t data;
  531. {
  532. int s, error;
  533. struct ifreq *ifr = (struct ifreq *) data;
  534. struct ifaddr *ifa = (struct ifaddr *) data;
  535. u_short mtu;
  536. error = 0;
  537. s = splimp();
  538. switch (cmd) {
  539. case SIOCSIFFLAGS:
  540. if ((ifp->if_flags & IFF_RUNNING) == 0)
  541. ifp->if_flags &= ~IFF_UP;
  542. break;
  543. case SIOCSIFADDR:
  544. if (IFA_ADDR(ifa).sa_family != AF_INET)
  545. error = EAFNOSUPPORT;
  546. break;
  547. case SIOCSIFDSTADDR:
  548. if (IFA_ADDR(ifa).sa_family != AF_INET)
  549. error = EAFNOSUPPORT;
  550. break;
  551. case SIOCSIFMTU:
  552. if ((error = NOTSUSER()) != 0)
  553. break;
  554. #ifdef __osf__
  555. /* this hack is necessary because ifioctl checks ifr_data
  556. * in 4.0 and 5.0, but ifr_data and ifr_metric overlay each
  557. * other in the definition of struct ifreq so pppd can't set both.
  558. */
  559. bcopy(ifr->ifr_data, &mtu, sizeof (u_short));
  560. ifr->ifr_mtu = mtu;
  561. #endif
  562. if (ifr->ifr_mtu < PPP_MINMTU || ifr->ifr_mtu > PPP_MAXMTU) {
  563. error = EINVAL;
  564. break;
  565. }
  566. ifp->if_mtu = ifr->ifr_mtu;
  567. break;
  568. case SIOCGIFMTU:
  569. ifr->ifr_mtu = ifp->if_mtu;
  570. break;
  571. case SIOCADDMULTI:
  572. case SIOCDELMULTI:
  573. switch(ifr->ifr_addr.sa_family) {
  574. case AF_INET:
  575. break;
  576. default:
  577. error = EAFNOSUPPORT;
  578. break;
  579. }
  580. break;
  581. default:
  582. error = EINVAL;
  583. }
  584. splx(s);
  585. return (error);
  586. }
  587. /*
  588. * Turn a STREAMS message into an mbuf chain.
  589. */
  590. static struct mbuf *
  591. make_mbufs(mp, off)
  592. mblk_t *mp;
  593. int off;
  594. {
  595. struct mbuf *head, **prevp, *m;
  596. int len, space, n;
  597. unsigned char *cp, *dp;
  598. len = msgdsize(mp);
  599. if (len == 0)
  600. return 0;
  601. prevp = &head;
  602. space = 0;
  603. cp = mp->b_rptr;
  604. #ifdef __osf__
  605. MGETHDR(m, M_DONTWAIT, MT_DATA);
  606. m->m_len = 0;
  607. space = MHLEN;
  608. *prevp = m;
  609. prevp = &m->m_next;
  610. dp = mtod(m, unsigned char *);
  611. len -= space;
  612. off = 0;
  613. #endif
  614. for (;;) {
  615. while (cp >= mp->b_wptr) {
  616. mp = mp->b_cont;
  617. if (mp == 0) {
  618. *prevp = 0;
  619. return head;
  620. }
  621. cp = mp->b_rptr;
  622. }
  623. n = mp->b_wptr - cp;
  624. if (space == 0) {
  625. MGET(m, M_DONTWAIT, MT_DATA);
  626. *prevp = m;
  627. if (m == 0) {
  628. if (head != 0)
  629. m_freem(head);
  630. return 0;
  631. }
  632. if (len + off > 2 * MLEN) {
  633. #ifdef __osf__
  634. MCLGET(m, M_DONTWAIT);
  635. #else
  636. MCLGET(m);
  637. #endif
  638. }
  639. #ifdef __osf__
  640. space = ((m->m_flags & M_EXT) ? MCLBYTES : MLEN);
  641. #else
  642. space = (m->m_off > MMAXOFF? MCLBYTES: MLEN) - off;
  643. m->m_off += off;
  644. #endif
  645. m->m_len = 0;
  646. len -= space;
  647. dp = mtod(m, unsigned char *);
  648. off = 0;
  649. prevp = &m->m_next;
  650. }
  651. if (n > space)
  652. n = space;
  653. bcopy(cp, dp, n);
  654. cp += n;
  655. dp += n;
  656. space -= n;
  657. m->m_len += n;
  658. }
  659. }
  660. /*
  661. * Turn an mbuf chain into a STREAMS message.
  662. */
  663. #define ALLOCB_MAX 4096
  664. static mblk_t *
  665. make_message(m, off)
  666. struct mbuf *m;
  667. int off;
  668. {
  669. mblk_t *head, **prevp, *mp;
  670. int len, space, n, nb;
  671. unsigned char *cp, *dp;
  672. struct mbuf *nm;
  673. len = 0;
  674. for (nm = m; nm != 0; nm = nm->m_next)
  675. len += nm->m_len;
  676. prevp = &head;
  677. space = 0;
  678. cp = mtod(m, unsigned char *);
  679. nb = m->m_len;
  680. for (;;) {
  681. while (nb <= 0) {
  682. m = m->m_next;
  683. if (m == 0) {
  684. *prevp = 0;
  685. return head;
  686. }
  687. cp = mtod(m, unsigned char *);
  688. nb = m->m_len;
  689. }
  690. if (space == 0) {
  691. space = len + off;
  692. if (space > ALLOCB_MAX)
  693. space = ALLOCB_MAX;
  694. mp = allocb(space, BPRI_LO);
  695. *prevp = mp;
  696. if (mp == 0) {
  697. if (head != 0)
  698. freemsg(head);
  699. return 0;
  700. }
  701. dp = mp->b_rptr += off;
  702. space -= off;
  703. len -= space;
  704. off = 0;
  705. prevp = &mp->b_cont;
  706. }
  707. n = nb < space? nb: space;
  708. bcopy(cp, dp, n);
  709. cp += n;
  710. dp += n;
  711. nb -= n;
  712. space -= n;
  713. mp->b_wptr = dp;
  714. }
  715. }
  716. /*
  717. * Digital UNIX doesn't allow for removing ifnet structures
  718. * from the list. But then we're not using this as a loadable
  719. * module anyway, so that's OK.
  720. *
  721. * Under SunOS, this should allow the module to be unloaded.
  722. * Unfortunately, it doesn't seem to detach all the references,
  723. * so your system may well crash after you unload this module :-(
  724. */
  725. #ifndef __osf__
  726. /*
  727. * Remove an interface from the system.
  728. * This routine contains magic.
  729. */
  730. #include <net/route.h>
  731. #include <netinet/in_pcb.h>
  732. #include <netinet/ip_var.h>
  733. #include <netinet/tcp.h>
  734. #include <netinet/tcp_timer.h>
  735. #include <netinet/tcp_var.h>
  736. #include <netinet/udp.h>
  737. #include <netinet/udp_var.h>
  738. static void
  739. ppp_if_detach(ifp)
  740. struct ifnet *ifp;
  741. {
  742. int s;
  743. struct inpcb *pcb;
  744. struct ifaddr *ifa;
  745. struct in_ifaddr **inap;
  746. struct ifnet **ifpp;
  747. s = splhigh();
  748. /*
  749. * Clear the interface from any routes currently cached in
  750. * TCP or UDP protocol control blocks.
  751. */
  752. for (pcb = tcb.inp_next; pcb != &tcb; pcb = pcb->inp_next)
  753. if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
  754. in_losing(pcb);
  755. for (pcb = udb.inp_next; pcb != &udb; pcb = pcb->inp_next)
  756. if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
  757. in_losing(pcb);
  758. /*
  759. * Delete routes through all addresses of the interface.
  760. */
  761. for (ifa = ifp->if_addrlist; ifa != 0; ifa = ifa->ifa_next) {
  762. rtinit(ifa, ifa, SIOCDELRT, RTF_HOST);
  763. rtinit(ifa, ifa, SIOCDELRT, 0);
  764. }
  765. /*
  766. * Unlink the interface's address(es) from the in_ifaddr list.
  767. */
  768. for (inap = &in_ifaddr; *inap != 0; ) {
  769. if ((*inap)->ia_ifa.ifa_ifp == ifp)
  770. *inap = (*inap)->ia_next;
  771. else
  772. inap = &(*inap)->ia_next;
  773. }
  774. /*
  775. * Delete the interface from the ifnet list.
  776. */
  777. for (ifpp = &ifnet; (*ifpp) != 0; ) {
  778. if (*ifpp == ifp)
  779. break;
  780. ifpp = &(*ifpp)->if_next;
  781. }
  782. if (*ifpp == 0)
  783. printf("couldn't find interface ppp%d in ifnet list\n", ifp->if_unit);
  784. else
  785. *ifpp = ifp->if_next;
  786. splx(s);
  787. }
  788. #endif /* __osf__ */