static int ipcp_nakci()

in net/ip/lwip_base/src/netif/ppp/ipcp.c [1076:1334]


static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) {
    ppp_pcb *pcb = f->pcb;
    ipcp_options *go = &pcb->ipcp_gotoptions;
    u_char citype, cilen, *next;
#if VJ_SUPPORT
    u_char cimaxslotindex, cicflag;
    u_short cishort;
#endif /* VJ_SUPPORT */
    u32_t ciaddr1, ciaddr2, l;
#if LWIP_DNS
    u32_t cidnsaddr;
#endif /* LWIP_DNS */
    ipcp_options no;		/* options we've seen Naks for */
    ipcp_options try_;		/* options to request next time */

    BZERO(&no, sizeof(no));
    try_ = *go;

    /*
     * Any Nak'd CIs must be in exactly the same order that we sent.
     * Check packet length and CI length at each step.
     * If we find any deviations, then this packet is bad.
     */
#define NAKCIADDRS(opt, neg, code) \
    if ((neg) && \
	(cilen = p[1]) == CILEN_ADDRS && \
	len >= cilen && \
	p[0] == opt) { \
	len -= cilen; \
	INCPTR(2, p); \
	GETLONG(l, p); \
	ciaddr1 = lwip_htonl(l); \
	GETLONG(l, p); \
	ciaddr2 = lwip_htonl(l); \
	no.old_addrs = 1; \
	code \
    }

#if VJ_SUPPORT
#define NAKCIVJ(opt, neg, code) \
    if (go->neg && \
	((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
	len >= cilen && \
	p[0] == opt) { \
	len -= cilen; \
	INCPTR(2, p); \
	GETSHORT(cishort, p); \
	no.neg = 1; \
        code \
    }
#endif /* VJ_SUPPORT */

#define NAKCIADDR(opt, neg, code) \
    if (go->neg && \
	(cilen = p[1]) == CILEN_ADDR && \
	len >= cilen && \
	p[0] == opt) { \
	len -= cilen; \
	INCPTR(2, p); \
	GETLONG(l, p); \
	ciaddr1 = lwip_htonl(l); \
	no.neg = 1; \
	code \
    }

#if LWIP_DNS
#define NAKCIDNS(opt, neg, code) \
    if (go->neg && \
	((cilen = p[1]) == CILEN_ADDR) && \
	len >= cilen && \
	p[0] == opt) { \
	len -= cilen; \
	INCPTR(2, p); \
	GETLONG(l, p); \
	cidnsaddr = lwip_htonl(l); \
	no.neg = 1; \
	code \
    }
#endif /* LWIP_DNS */

    /*
     * Accept the peer's idea of {our,his} address, if different
     * from our idea, only if the accept_{local,remote} flag is set.
     */
    NAKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs,
	       if (treat_as_reject) {
		   try_.old_addrs = 0;
	       } else {
		   if (go->accept_local && ciaddr1) {
		       /* take his idea of our address */
		       try_.ouraddr = ciaddr1;
		   }
		   if (go->accept_remote && ciaddr2) {
		       /* take his idea of his address */
		       try_.hisaddr = ciaddr2;
		   }
	       }
	);

#if VJ_SUPPORT
    /*
     * Accept the peer's value of maxslotindex provided that it
     * is less than what we asked for.  Turn off slot-ID compression
     * if the peer wants.  Send old-style compress-type option if
     * the peer wants.
     */
    NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
	    if (treat_as_reject) {
		try_.neg_vj = 0;
	    } else if (cilen == CILEN_VJ) {
		GETCHAR(cimaxslotindex, p);
		GETCHAR(cicflag, p);
		if (cishort == IPCP_VJ_COMP) {
		    try_.old_vj = 0;
		    if (cimaxslotindex < go->maxslotindex)
			try_.maxslotindex = cimaxslotindex;
		    if (!cicflag)
			try_.cflag = 0;
		} else {
		    try_.neg_vj = 0;
		}
	    } else {
		if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
		    try_.old_vj = 1;
		    try_.vj_protocol = cishort;
		} else {
		    try_.neg_vj = 0;
		}
	    }
	    );
#endif /* VJ_SUPPORT */

    NAKCIADDR(CI_ADDR, neg_addr,
	      if (treat_as_reject) {
		  try_.neg_addr = 0;
		  try_.old_addrs = 0;
	      } else if (go->accept_local && ciaddr1) {
		  /* take his idea of our address */
		  try_.ouraddr = ciaddr1;
	      }
	      );

#if LWIP_DNS
    NAKCIDNS(CI_MS_DNS1, req_dns1,
	     if (treat_as_reject) {
		 try_.req_dns1 = 0;
	     } else {
		 try_.dnsaddr[0] = cidnsaddr;
	     }
	     );

    NAKCIDNS(CI_MS_DNS2, req_dns2,
	     if (treat_as_reject) {
		 try_.req_dns2 = 0;
	     } else {
		 try_.dnsaddr[1] = cidnsaddr;
	     }
	     );
#endif /* #if LWIP_DNS */

    /*
     * There may be remaining CIs, if the peer is requesting negotiation
     * on an option that we didn't include in our request packet.
     * If they want to negotiate about IP addresses, we comply.
     * If they want us to ask for compression, we refuse.
     * If they want us to ask for ms-dns, we do that, since some
     * peers get huffy if we don't.
     */
    while (len >= CILEN_VOID) {
	GETCHAR(citype, p);
	GETCHAR(cilen, p);
	if ( cilen < CILEN_VOID || (len -= cilen) < 0 )
	    goto bad;
	next = p + cilen - 2;

	switch (citype) {
#if VJ_SUPPORT
	case CI_COMPRESSTYPE:
	    if (go->neg_vj || no.neg_vj ||
		(cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
		goto bad;
	    no.neg_vj = 1;
	    break;
#endif /* VJ_SUPPORT */
	case CI_ADDRS:
	    if ((!go->neg_addr && go->old_addrs) || no.old_addrs
		|| cilen != CILEN_ADDRS)
		goto bad;
	    try_.neg_addr = 0;
	    GETLONG(l, p);
	    ciaddr1 = lwip_htonl(l);
	    if (ciaddr1 && go->accept_local)
		try_.ouraddr = ciaddr1;
	    GETLONG(l, p);
	    ciaddr2 = lwip_htonl(l);
	    if (ciaddr2 && go->accept_remote)
		try_.hisaddr = ciaddr2;
	    no.old_addrs = 1;
	    break;
	case CI_ADDR:
	    if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
		goto bad;
	    try_.old_addrs = 0;
	    GETLONG(l, p);
	    ciaddr1 = lwip_htonl(l);
	    if (ciaddr1 && go->accept_local)
		try_.ouraddr = ciaddr1;
	    if (try_.ouraddr != 0)
		try_.neg_addr = 1;
	    no.neg_addr = 1;
	    break;
#if LWIP_DNS
	case CI_MS_DNS1:
	    if (go->req_dns1 || no.req_dns1 || cilen != CILEN_ADDR)
		goto bad;
	    GETLONG(l, p);
	    try_.dnsaddr[0] = lwip_htonl(l);
	    try_.req_dns1 = 1;
	    no.req_dns1 = 1;
	    break;
	case CI_MS_DNS2:
	    if (go->req_dns2 || no.req_dns2 || cilen != CILEN_ADDR)
		goto bad;
	    GETLONG(l, p);
	    try_.dnsaddr[1] = lwip_htonl(l);
	    try_.req_dns2 = 1;
	    no.req_dns2 = 1;
	    break;
#endif /* LWIP_DNS */
#if 0 /* UNUSED - WINS */
	case CI_MS_WINS1:
	case CI_MS_WINS2:
	    if (cilen != CILEN_ADDR)
		goto bad;
	    GETLONG(l, p);
	    ciaddr1 = lwip_htonl(l);
	    if (ciaddr1)
		try_.winsaddr[citype == CI_MS_WINS2] = ciaddr1;
	    break;
#endif /* UNUSED - WINS */
	default:
	    break;
	}
	p = next;
    }

    /*
     * OK, the Nak is good.  Now we can update state.
     * If there are any remaining options, we ignore them.
     */
    if (f->state != PPP_FSM_OPENED)
	*go = try_;

    return 1;

bad:
    IPCPDEBUG(("ipcp_nakci: received bad Nak!"));
    return 0;
}