Commit 4edfad00 authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN/PPP: PPP header cleanups

Use a shared function for generating the PPP header, use the
{put,get}_u{8,16,32} helpers for endian-safe access.
parent afd5fdbf
...@@ -106,6 +106,30 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot ...@@ -106,6 +106,30 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot
} }
} }
void
isdn_ppp_push_header(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
{
unsigned char *p;
if (skb_headroom(skb) < 4) {
isdn_BUG();
return;
}
if ((idev->pppcfg & SC_COMP_PROT) && proto <= 0xff)
put_u8(skb_push(skb, 1), proto);
else
put_u16(skb_push(skb, 2), proto);
if (idev->pppcfg & SC_COMP_AC)
return;
p = skb_push(skb, 2);
p += put_u8(p, PPP_ALLSTATIONS);
p += put_u8(p, PPP_UI);
}
/* /*
* unbind isdn_net_local <=> ippp-device * unbind isdn_net_local <=> ippp-device
* note: it can happen, that we hangup/free the master before the slaves * note: it can happen, that we hangup/free the master before the slaves
...@@ -857,23 +881,29 @@ isdn_ppp_cleanup(void) ...@@ -857,23 +881,29 @@ isdn_ppp_cleanup(void)
*/ */
static int isdn_ppp_skip_ac(isdn_net_dev *idev, struct sk_buff *skb) static int isdn_ppp_skip_ac(isdn_net_dev *idev, struct sk_buff *skb)
{ {
u8 val;
if (skb->len < 1) if (skb->len < 1)
return -1; return -1;
if (skb->data[0] == 0xff) { get_u8(skb->data, &val);
if (skb->len < 2) if (val != PPP_ALLSTATIONS) {
return -1; /* if AC compression was not negotiated, but no AC present,
discard packet */
if (skb->data[1] != 0x03)
return -1;
// skip address/control (AC) field
skb_pull(skb, 2);
} else {
if (idev->pppcfg & SC_REJ_COMP_AC) if (idev->pppcfg & SC_REJ_COMP_AC)
// if AC compression was not negotiated, but used, discard packet
return -1; return -1;
return 0;
} }
if (skb->len < 2)
return -1;
get_u8(skb->data + 1, &val);
if (val != PPP_UI)
return -1;
/* skip address/control (AC) field */
skb_pull(skb, 2);
return 0; return 0;
} }
...@@ -883,19 +913,21 @@ static int isdn_ppp_skip_ac(isdn_net_dev *idev, struct sk_buff *skb) ...@@ -883,19 +913,21 @@ static int isdn_ppp_skip_ac(isdn_net_dev *idev, struct sk_buff *skb)
*/ */
int isdn_ppp_strip_proto(struct sk_buff *skb) int isdn_ppp_strip_proto(struct sk_buff *skb)
{ {
int proto; u16 proto;
u8 val;
if (skb->len < 1) if (skb->len < 1)
return -1; return -1;
if (skb->data[0] & 0x1) { get_u8(skb->data, &val);
// protocol field is compressed if (val & 0x1) {
proto = skb->data[0]; /* protocol field is compressed */
proto = val;
skb_pull(skb, 1); skb_pull(skb, 1);
} else { } else {
if (skb->len < 2) if (skb->len < 2)
return -1; return -1;
proto = ((int) skb->data[0] << 8) + skb->data[1]; get_u16(skb->data, &proto);
skb_pull(skb, 2); skb_pull(skb, 2);
} }
return proto; return proto;
...@@ -911,13 +943,6 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -911,13 +943,6 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct ipppd *is; struct ipppd *is;
int proto; int proto;
/*
* If encapsulation is syncppp, don't reset
* huptimer on LCP packets.
*/
if (PPP_PROTOCOL(skb->data) != PPP_LCP)
idev->huptimer = 0;
is = ipppd_get(idev->ppp_slot); is = ipppd_get(idev->ppp_slot);
if (!is) if (!is)
goto err; goto err;
...@@ -934,6 +959,10 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -934,6 +959,10 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev,
proto = isdn_ppp_strip_proto(skb); proto = isdn_ppp_strip_proto(skb);
if (proto < 0) if (proto < 0)
goto err_put; goto err_put;
/* Don't reset huptimer on LCP packets. */
if (proto != PPP_LCP)
idev->huptimer = 0;
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
if (is->compflags & SC_LINK_DECOMP_ON) { if (is->compflags & SC_LINK_DECOMP_ON) {
...@@ -1071,32 +1100,6 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -1071,32 +1100,6 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
kfree_skb(skb); kfree_skb(skb);
} }
/*
* isdn_ppp_skb_push ..
* checks whether we have enough space at the beginning of the skb
* and allocs a new SKB if necessary
*/
static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
{
struct sk_buff *skb = *skb_p;
if(skb_headroom(skb) < len) {
struct sk_buff *nskb = skb_realloc_headroom(skb, len);
if (!nskb) {
printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
dev_kfree_skb(skb);
return NULL;
}
printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len);
dev_kfree_skb(skb);
*skb_p = nskb;
return skb_push(nskb, len);
}
return skb_push(skb,len);
}
/* /*
* send ppp frame .. we expect a PIDCOMPressable proto -- * send ppp frame .. we expect a PIDCOMPressable proto --
* (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP) * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
...@@ -1258,27 +1261,7 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -1258,27 +1261,7 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev)
skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1); skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
#endif #endif
if ((idev->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) { isdn_ppp_push_header(idev, skb, proto);
unsigned char *data = isdn_ppp_skb_push(&skb,1);
if(!data)
goto put2;
data[0] = proto & 0xff;
} else {
unsigned char *data = isdn_ppp_skb_push(&skb,2);
if(!data)
goto put2;
data[0] = (proto >> 8) & 0xff;
data[1] = proto & 0xff;
}
if (!(idev->pppcfg & SC_COMP_AC)) {
unsigned char *data = isdn_ppp_skb_push(&skb,2);
if(!data)
goto put2;
data[0] = 0xff; /* All Stations */
data[1] = 0x03; /* Unnumbered information */
}
/* tx-stats are now updated via BSENT-callback */
if (ipts->debug & 0x40) { if (ipts->debug & 0x40) {
printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len); printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
...@@ -1287,7 +1270,6 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -1287,7 +1270,6 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev)
isdn_net_writebuf_skb(idev, skb); isdn_net_writebuf_skb(idev, skb);
put2:
ipppd_put(ipt); ipppd_put(ipt);
put: put:
ipppd_put(ipts); ipppd_put(ipts);
...@@ -1966,24 +1948,19 @@ static void isdn_ppp_ccp_lp_kick_up(void *priv, unsigned int flags) ...@@ -1966,24 +1948,19 @@ static void isdn_ppp_ccp_lp_kick_up(void *priv, unsigned int flags)
isdn_ppp_fill_rq(NULL, 0, PPP_COMP, idev->ppp_slot); isdn_ppp_fill_rq(NULL, 0, PPP_COMP, idev->ppp_slot);
} }
/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is /* Send a CCP Reset-Request or Reset-Ack directly from the kernel. */
getting that lengthy because there is no simple "send-this-frame-out"
function above but every wrapper does a bit different. Hope I guess
correct in this hack... */
static void isdn_ppp_ccp_xmit_reset(void *priv, int proto, static void
unsigned char code, unsigned char id, isdn_ppp_ccp_xmit_reset(void *priv, int proto, unsigned char code,
unsigned char *data, int len) unsigned char id, unsigned char *data, int len)
{ {
isdn_net_dev *idev = priv; isdn_net_dev *idev = priv;
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *p; unsigned char *p;
int hl; int hl;
int cnt = 0;
/* Alloc large enough skb */
hl = isdn_slot_hdrlen(idev->isdn_slot); hl = isdn_slot_hdrlen(idev->isdn_slot);
skb = alloc_skb(len + hl + 16,GFP_ATOMIC); skb = alloc_skb(len + hl + IPPP_MAX_HEADER, GFP_ATOMIC);
if(!skb) { if(!skb) {
printk(KERN_WARNING printk(KERN_WARNING
"ippp: CCP cannot send reset - out of memory\n"); "ippp: CCP cannot send reset - out of memory\n");
...@@ -1991,31 +1968,18 @@ static void isdn_ppp_ccp_xmit_reset(void *priv, int proto, ...@@ -1991,31 +1968,18 @@ static void isdn_ppp_ccp_xmit_reset(void *priv, int proto,
} }
skb_reserve(skb, hl+16); skb_reserve(skb, hl+16);
/* We may need to stuff an address and control field first */ isdn_ppp_push_header(idev, skb, proto);
if (!(idev->pppcfg & SC_COMP_AC)) {
p = skb_put(skb, 2);
*p++ = 0xff;
*p++ = 0x03;
}
/* Stuff proto, code, id and length */ p = skb_put(skb, 4);
p = skb_put(skb, 6); p += put_u8 (p, code);
*p++ = (proto >> 8); p += put_u8 (p, id);
*p++ = (proto & 0xff); p += put_u16(p, len + 4);
*p++ = code;
*p++ = id; if (len)
cnt = 4 + len; memcpy(skb_put(skb, len), data, len);
*p++ = (cnt >> 8);
*p++ = (cnt & 0xff);
/* Now stuff remaining bytes */
if(len) {
p = skb_put(skb, len);
memcpy(p, data, len);
}
/* skb is now ready for xmit */ isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1,
isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1, idev->ppp_slot); idev->ppp_slot);
isdn_net_write_super(idev, skb); isdn_net_write_super(idev, skb);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment